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

时间:2013-10-03 16:19:51

标签: javascript android android-webview postmessage

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

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

4 个答案:

答案 0 :(得分:6)

我意识到这个问题已经过时但是我遇到了它,所以我想我会在这里回答。简而言之 - 我发现postMessage至少可以用于从子iframe到父窗口的通信但是...

事实证明我们真的不喜欢iframe在android的WebView中的表现方式,所以我们直接渲染了iframe的内容(正如你的建议)。这给我们留下了两个问题 - 首先我们有很多来自iframe的消息钩子到它的父节点,第二个我们仍然需要调用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。在这里,我们还在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中运行而不会发生任何变化(至少对这部分代码而言)。

我希望能有所帮助。

答案 1 :(得分:2)

最近,我们不得不开发一个项目,该项目需要第三方的外部Webview集成进行通讯。

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

我描述了如何通过JS PostMessage API通过消息步骤与本地应用程序通信Webview。

使用我们的webview实现。我们实施了onPageFinished方法,以便注入我们的JS代码来加载网络。

override fun onPageFinished(url: String?) {
webview.loadUrl(
"javascript:(function() {" +
    "window.parent.addEventListener ('message', function(event) {" +
    " Android.receiveMessage(JSON.stringify(event.data));});" +
    "})()"
)
}

基本上,我们正在做的是创建一个侦听器,将这些消息发送到我们自己的JS和Android Bridge interface。我们之前在Android活动中的网络视图设置中创建了该设置,就像通常使用addJavascriptInterface

一样
webview.addJavascriptInterface(JsObject(presenter), "Android”)

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

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

答案 2 :(得分: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
}

答案 3 :(得分:0)

我遇到了类似的问题,我想听听Webview中发生的.postMessage事件。我检查了原始的html,发现事件是这样触发的

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

因此,我对postMessage进行了更多研究,发现this link用于添加eventListener

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

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

  // ...
}

durban's answer帮助我进行了设置 Android JS界面。

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

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

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

webView.addJavascriptInterface(new JsObject(), "Android"); //"Android" is just a name

然后像下面这样在onPageStarted的{​​{1}}回调中调用javascript

WebViewClient