Can the PostMessage API be used to communicate with an Android WebView?

Brian Putnam picture Brian Putnam · Oct 3, 2013 · Viewed 15.4k times · Source

I usually use the HTML5 PostMessage API to communicate information from my iframed content to the parent frame. Recently I've had my content used inside an Android WebView (as far as I can tell this is the native-Android equivalent of an iframe). Is there a way for the native app to listen for PostMessage events that I send up to them?

I'm aware that addJavascriptInterface exists, I'm just hoping that there's a way to reuse my existing PostMessage code without writing something new.

Answer

darrin picture darrin · Oct 5, 2016

I realize this question is old but I ran into it so I figured I would answer here. In short - I am finding that postMessage does work at least for communication from a child iframe to a parent window BUT...

Turns out we really didn't like the way the iframe behaved in android's WebView so we rendered the contents of the iframe directly instead (as you suggest). This left us with two problems - first we had lots of messaging hooks from that iframe to it's parent and second we still needed to call out to android to react to these events.

Here's an example message from our code - which was sprinkled throughout the iframe:

    parent.postMessage(JSON.stringify({
        action    : 'openModal',
        source    : embedId
    }), '*');

When we're on Android what we want is to use android's support for javascript interfaces to inject an object to handle this request when running in a WebView.

On the Android side this will look something like this:

class JsObject {
   @JavascriptInterface
    public boolean postMessage(String json, String transferList) {
        return false; // here we return true if we handled the post.
    }
}

// And when initializing the webview... 
webView.addJavascriptInterface(new JsObject(), "totDevice");

Now when running inside this WebView totDevice will exist and when running in an iframe it won't. So now we can create a wrapper to check for this condition and cleanly switch between the two methods rather than calling parent.postMessage directly. Here we also added a boolean switch in our Android implementation in case you only wanted to handle some of the messages:

function postMessage(parent, json, transferlist) {
    if (!totDevice || !totDevice.postMessage(json, transferList)) {
        parent.postMessage(json, transferlist);
    }
}

Our original postMessage from above can be rewritten:

    postMessage(parent, JSON.stringify({
        action    : 'openModal',
        source    : embedId
    }), '*');

Now we have a single set of code that can run in an iframe or android WebView with no change (at least to this part of the code).

I hope that helps someone.