web-dev-qa-db-ja.com

PostMessageAPIを使用してAndroid WebViewと通信できますか?

私は通常、HTML5 PostMessage API を使用して、iframeコンテンツから親フレームに情報を伝達します。最近、コンテンツをAndroid WebView内で使用しました(これがネイティブAndroidのiframeに相当するものであることがわかります)。ネイティブアプリがリッスンする方法はありますか?私が彼らに送るPostMessageイベントのために?

addJavascriptInterface が存在することを認識しています。何か新しいことを書かずに、既存のPostMessageコードを再利用する方法があることを望んでいます。

23
Brian Putnam

この質問は古いと思いますが、出くわしたので、ここで答えると思いました。要するに、postMessageは少なくとも子iframeから親ウィンドウへの通信では機能することがわかりましたが...

AndroidのWebViewでのiframeの動作が本当に気に入らなかったため、代わりにiframeのコンテンツを直接レンダリングしました(ご提案のとおり)。これにより、2つの問題が発生しました。1つはそのiframeからその親へのメッセージングフックがたくさんあり、もう1つはこれらのイベントに反応するためにAndroidを呼び出す必要がありました。

これが私たちのコードからのメッセージの例です-それはiframe全体に散らばっていました:

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

Android必要なのは、[Androidのjavascriptインターフェイスのサポート]( https://developer.Android.com/reference/Android/webkit/WebView)を使用することです。 .html#addJavascriptInterface(Java.lang.Object 、Java.lang.String))を使用して、WebViewで実行しているときにこのリクエストを処理するオブジェクトを挿入します。

Android側では、これは次のようになります。

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");

これで、このWebView内で実行すると、totDeviceが存在し、iframeで実行する場合は存在しません。これで、ラッパーを作成してこの状態をチェックし、parent.postMessageを直接呼び出すのではなく、2つのメソッドをきれいに切り替えることができます。ここでは、一部のメッセージのみを処理したい場合に備えて、Android実装にブールスイッチを追加しました。

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

上からの元のpostMessageは書き直すことができます:

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

これで、iframeまたはAndroid WebViewを変更せずに(少なくともコードのこの部分に対して)実行できる単一のコードセットができました。

それが誰かの助けになることを願っています。

8
darrin

ある実装ではPostMessageを介して、別の場合はaddJavascriptInterfaceを介してメッセージを処理する中間抽象インターフェースを使用する必要があります。

window.addEventListener("message", onReceivedPostMessage, false);

function onReceivedPostMessage(event){
     //..ex deconstruct event into action & params
     var action = event.data.action;
     var params = event.data.params;
     performAction(action, params); //performAction would be the uniform API
}

function onReceivedActivityMessageViaJavascriptInterface(json){
     //..ex deconstruct data into action & params
     var data = JSON.parse(json); 
     var action = data.action;
     var params = data.params;
     performAction(action, params); //performAction would be the uniform API
}
1
Ivo