Easily extending Cordova’s WebView in your Android app

I’ve recently been working on producing a AngularJS-based financial web app for a client which will also be packaged and distributed via cordova/phonegap. As we are only targeting relatively new browsers, and as we’re aiming to be mobile-first, I decided to use HTML5 inputs such as number as this causes virtual keyboards on iOS and Android to reflect the fact that they can only enter numbers.

This was working fine in Chrome and on various different Android phones via the phonegap build, but then we got feedback that on a certain Android 4.x Samsung phone you could only enter numbers and not a decimal point! This was the first time I’d heard about this bug as normally when I’ve used number inputs before they have only been integral, but it seems that this is a relatively well-known bug on most Samsung Android phones. D’oh.

I searched for quite a while for a plugin or work-around for phonegap, and discovered some code that could be used on a WebView component to work around but no instructions for how to replace this function in the cordova WebView subclass. Fortunately it turned out to be relatively simple, and this is also a generic way of customizing a cordova build’s Android WebView in such a way that you can keep rebuilding the app without it getting overwritten.

Firstly, create a new Java class under your main package called HackedWebViewEngine as at the bottom of this post. The key line is

        this(new HackedWebView(context), preferences);

which changes phonegap’s engine to use your own subclassed WebView rather than using the default one. You need to tell phonegap to use this customised Engine by placing the following in your config.xml file:

    <platform name="android">
       <preference name="webView" value="com.myapp.HackedWebViewEngine" />
    </platform>

Here’s the full code of the Java class to handle the overriding (as an aside, I hate how many imports Java programs need!)

package ...;

import android.content.Context;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;

import org.apache.cordova.CordovaPreferences;
import org.apache.cordova.engine.SystemWebView;
import org.apache.cordova.engine.SystemWebViewEngine;

public class HackedWebViewEngine extends SystemWebViewEngine {
    public static class HackedWebView extends SystemWebView {
        public HackedWebView(Context context) {
            super(context);
        }
        public HackedWebView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        @Override
        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
            InputConnection connection = super.onCreateInputConnection(outAttrs);

            // Many Samsung phones don't show decimal points on html number inputs by default.
            if ((outAttrs.inputType & InputType.TYPE_CLASS_NUMBER) == InputType.TYPE_CLASS_NUMBER)
                outAttrs.inputType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;

            return connection;
        }
    }

    /** Used when created via reflection. */
    public HackedWebViewEngine(Context context, CordovaPreferences preferences) {
        this(new HackedWebView(context), preferences);
    }

    public HackedWebViewEngine(SystemWebView webView) {
        super(webView);
    }
    public HackedWebViewEngine(SystemWebView webView, CordovaPreferences preferences) {
        super(webView, preferences);
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *