javascript 可以使用 PostMessage API 与 Android WebView 通信吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19164205/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 14:37:25  来源:igfitidea点击:

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

javascriptandroidandroid-webviewpostmessage

提问by Brian Putnam

I usually use the HTML5 PostMessage APIto 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?

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

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

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

回答by darrin

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...

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

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.

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

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

这是来自我们代码的示例消息 - 散布在整个 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 interfacesto inject an object to handle this request when running in a WebView.

当我们在 Android 上时,我们想要的是在 WebView 中运行时,使用android 对 javascript 接口的支持来注入一个对象来处理此请求。

On the Android side this will look something like this:

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

Now when running inside this WebView totDevicewill 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.postMessagedirectly. Here we also added a boolean switch in our Android implementation in case you only wanted to handle some of the messages:

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

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

Our original postMessage from above can be rewritten:

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

    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).

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

I hope that helps someone.

我希望这可以帮助某人。

回答by Ivo

You need to use an intermediate abstract interface that in one implementation processes messages via PostMessage and in another case via addJavascriptInterface.

您需要使用一个中间抽象接口,该接口在一个实现中通过 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
}