PostMessage API可以用于与Android WebView进行通信吗?

Bri*_*nam 21 javascript android postmessage android-webview

我通常使用HTML5 PostMessage API将iframed内容中的信息传递给父框架.最近我在Android WebView中使用了我的内容(据我所知,这是iframe的原生Android相当).本机应用程序是否有办法监听我发送给他们的PostMessage事件?

我知道addJavascriptInterface存在,我只是希望有一种方法可以重用我现有的PostMessage代码,而无需编写新的东西.

Mau*_*Lam 11

这里的答案在发布时是很好的答案,但现在 androidx.webkit 可用,我相信这是推荐的方法。

特别是,WebViewCompat.addWebMessageListenerWebViewCompat.postWebMessage是 javascript PostMessage API 的对应部分。

以下是从文档中复制的代码示例:

 // Web page (in JavaScript)
 myObject.onmessage = function(event) {
   // prints "Got it!" when we receive the app's response.
   console.log(event.data);
 }
 myObject.postMessage("I'm ready!");
 
Run Code Online (Sandbox Code Playgroud)
 // App (in Java)
 WebMessageListener myListener = new WebMessageListener() {
   @Override
   public void onPostMessage(WebView view, WebMessageCompat message, Uri sourceOrigin,
            boolean isMainFrame, JavaScriptReplyProxy replyProxy) {
     // do something about view, message, sourceOrigin and isMainFrame.
     replyProxy.postMessage("Got it!");
   }
 };
 if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
   WebViewCompat.addWebMessageListener(webView, "myObject", rules, myListener);
 }
Run Code Online (Sandbox Code Playgroud)

  • 您可以做的是,如果该功能不受支持,您可以提供 [Play 商店条目](https://play.google.com/store/apps/details?id=com.google.android.webview )并要求用户更新 (2认同)

dar*_*rin 7

我知道这个问题很旧,但是我遇到了,所以我想在这里回答。简而言之-我发现postMessage至少对从子iframe到父窗口的通信有效,但是...

事实证明,我们确实不喜欢iframe在android的WebView中的表现方式,因此我们直接渲染了iframe的内容(如您所建议)。这给我们带来了两个问题-首先,从该iframe到它的父级,我们有很多消息挂钩;其次,我们仍然需要调出android对这些事件做出反应。

这是我们代码中的示例消息-遍及整个iframe:

    parent.postMessage(JSON.stringify({
        action    : 'openModal',
        source    : embedId
    }), '*');
Run Code Online (Sandbox Code Playgroud)

当我们使用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");
Run Code Online (Sandbox Code Playgroud)

现在,在此WebView中运行时totDevice将存在,而在iframe中运行时将不存在。因此,现在我们可以创建一个包装器来检查这种情况,并在两种方法之间干净地切换,而不是parent.postMessage直接调用。在这里,我们还为我们的Android实现添加了一个布尔型开关,以防您只想处理某些消息:

function postMessage(parent, json, transferlist) {
    if (!totDevice || !totDevice.postMessage(json, transferList)) {
        parent.postMessage(json, transferlist);
    }
}
Run Code Online (Sandbox Code Playgroud)

我们上面的原始postMessage可以被重写:

    postMessage(parent, JSON.stringify({
        action    : 'openModal',
        source    : embedId
    }), '*');
Run Code Online (Sandbox Code Playgroud)

现在,我们有一组代码可以在iframe或android WebView中运行,而无需更改(至少对代码的这一部分而言)。

希望对您有所帮助。


Sha*_*ati 7

我面临类似的问题,我想听.postMessage网络视图中发生的事件。我在原始 html 中检查了该事件是这样触发的

window.parent.postMessage(JSON.stringify(message), '*');

因此,我深入研究了 postMessage 并找到了用于添加 eventListener 的链接

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

function receiveMessage(event)
{
  if (event.origin !== "http://example.org:8080")
    return;

  // ...
}
Run Code Online (Sandbox Code Playgroud)

德班的 回答帮助我设置了 Android JS 接口。

首先是像这样的 JavascriptInterface 的自定义类

class JsObject {
    @JavascriptInterface
    public void receiveMessage(String data) {
        Log.i("JsObject", "postMessage data="+data);
        //handle data here
    }
}
Run Code Online (Sandbox Code Playgroud)

在加载 url/html 之前将 javascriptInterface 添加到 webview

webView.addJavascriptInterface(new JsObject(), "Android"); //"Android" is just a name
Run Code Online (Sandbox Code Playgroud)

onPageStarted然后在回调中调用javascript,WebViewClient如下所示

  @Override
  public void onPageStarted(WebView view, String url, Bitmap favicon) {
        webView.loadUrl("javascript:(function() {" +
                            "function receiveMessage(event) {\n" +
                            "Android.receiveMessage(JSON.stringify(event.data));\n" +
                            "}" +
                            "window.addEventListener(\"message\", receiveMessage, false);"+
                            "})()"
        );
        Log.i(TAG, "onPageStarted "+url);
  }
Run Code Online (Sandbox Code Playgroud)


dur*_*bon 6

最近,我们必须开发一个项目,需要将我们的本机 Android 应用程序与第三方的外部 webview集成进行通信。

\n

这个问题在 stackoverflow 中提出的想法非常有趣,如果你无法触及该 webview 的 JS 代码,则更是如此。

\n

我描述了我们做了什么,以便能够通过 JS PostMessage API通过消息步骤与本机应用程序进行通信。

\n

使用我们的 webview 实现。我们实现了onPageFinished方法来注入 JS 代码来加载网页。

\n
override fun onPageFinished(url: String?) {\nwebview.loadUrl(\n"javascript:(function() {" +\n    "window.parent.addEventListener (\'message\', function(event) {" +\n    " Android.receiveMessage(JSON.stringify(event.data));});" +\n    "})()"\n)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

基本上,我们正在做的是创建一个侦听器,将这些消息发送到我们自己的 JS 和Android Bridge 接口。我们之前在 Android 活动的 webview 设置中创建了它,就像我们通常使用addJavascriptInterface所做的那样

\n
webview.addJavascriptInterface(JsObject(presenter), "Android\xe2\x80\x9d)\n
Run Code Online (Sandbox Code Playgroud)\n

这样,我们就已经有了这个通信桥梁,并且 postMessage 发送的所有消息都将通过该侦听器订阅的接口到达我们。

\n
class JsObject(val presenter: Presenter) {\n    @JavascriptInterface\n    fun receiveMessage(data: String): Boolean {\n        presenter.onDataReceived(data)\n        Log.d("Data from JS", data)\n        return true\n    }\n
Run Code Online (Sandbox Code Playgroud)\n


小智 1

您需要使用中间抽象接口,在一种实现中通过 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
}
Run Code Online (Sandbox Code Playgroud)