简体   繁体   English

如何在Chrome App中与WebView进行通信?

[英]How to communicate with WebView in Chrome App?

I have developed a website which I intend to display inside a webview, within a Chrome App. 我开发了一个网站,我打算在Chrome浏览器中的webview中显示。 This works fine. 这很好用。

Now, I want to use postMessage from the website, to send messages out of the webview and into the containing Chrome App. 现在,我想从网站上使用postMessage,将消息从webview发送到包含的Chrome应用程序。 This is done via top.postMessage inside the webview. 这是通过webview中的top.postMessage完成的。

I've tried the following event listeners: 我尝试过以下事件监听器:

webView.contentWindow.addEventListener('message', messageHandler);

webView.addEventListener('message', messageHandler);

window.addEventListener('message', messageHandler);

document.addEventListener('message', messageHandler);

I have successfully implemented the following event listeners. 我已经成功实现了以下事件监听器。 All of which work as expected: contentload , dialog and consolemessage . 所有这些都按预期工作: contentloaddialogconsolemessage

Unless I can get this to work, I am considering using consolemessage to send messages from the webview to the container - something I find unappealing, and I suspect it won't work when not using the developer mode. 除非我能让它工作,否则我正在考虑使用consolemessage将消息从webview发送到容器 - 这些我觉得没有吸引力,我怀疑它在不使用开发者模式时不起作用。

The webview sample has a good demo of using postMessage to send messages between an app and an external page loaded in a webview. webview示例有一个很好的演示,使用postMessage在应用程序和webview中加载的外部页面之间发送消息。

Here are the key pieces of code. 以下是关键代码。

  1. In the app, listen to the loadstop event of the webview and send an initial message to the page. 在应用程序中,收听webview的loadstop事件并向页面发送初始消息。 You can restrict this message to specific domains or pages. 您可以将此邮件限制为特定的域或页面。

     wv1.addEventListener('loadstop', sendInitialMessage); function sendInitialMessage(e) { // only send the message if the page was loaded from googledrive hosting e.target.contentWindow.postMessage("initial message", "https://googledrive.com/host/*"); } 
  2. In the external page, listen for the message event and save off the source and origin. 在外部页面中,侦听message事件并保存源和源。

     window.addEventListener('message', onMessage); var appWindow, appOrigin; function onMessage(e) { appWindow = e.source; appOrigin = e.origin; } 

    Then the page can use those objects to post a message back to the app. 然后页面可以使用这些对象将消息发布回应用程序。

     function doSendMessage() { if (appWindow && appOrigin) { appWindow.postMessage("this is a message from the page!", appOrigin); } } 
  3. The app should also listen to the message event to receive the messages from the external page. 应用程序还应该侦听message事件以从外部页面接收消息。

     window.addEventListener('message', function(e) { log("[???] messagereceived: " + e.data); }); 

The reason that the embedded web page is unable to post messages to the app, is because the embedded web page does not have a reference to the app. 嵌入式网页无法向应用发布消息的原因是因为嵌入式网页没有对应用的引用。

top.postMessage is not a reference to the app. top.postMessage 不是对应用的引用。 top would work if you were trying to access the topmost frame, within the same webview. 如果您尝试访问同一webview中的最顶层框架,则top将起作用。

To be able to send messages to the app, the web page needs a reference to the app. 为了能够向应用程序发送消息,该网页需要引用该应用程序。 The easiest way to do this, is by having the app send the first message to the frame - a "hello"-message. 最简单的方法是让应用程序将第一条消息发送到框架 - 一个“hello”-message。

From the app: 从应用程序:

// Initialize communications
webView.contentWindow.postMessage('hello, webpage!', 'https://your.web.page/*');
addEventListener('message', function(e) {

    // I expect this check to work, but I have not tested it.
    if (e.source != webView.contentWindow)
        return;

    // Handle e.data however you want.
});

In the web page: 在网页中:

var messageSource, messageOrigin;
addEventListener('message', function(e) {
    if (!messageSource) {

        /*
         * Once we have a messageSource, we should not allow anybody to change
         * messageSource again
         */

        if (e.data == "hello, webpage!") {

            /*
             * If possible, you should validate the `e.origin` value here. It could 
             * possibly come from somewhere else. However, this is quite safe as it 
             * stands, since there only is a very narrow time window where the app 
             * is open willing to accept the "hello, webpage!" message.
             *
             * Another way of validating, is by having the app wait for the 
             * "hello, host!" message. If that response is not received within a second
             * the app host could simply reload the app.
             */

            messageSource = e.source;
            messageOrigin = e.origin;
            messageSource.postMessage("hello, host!", messageOrigin);
        }
    } else {
        // Handle messages however you like. This will simply respond to every message:
        messageSource.postMessage('Your message: ' + e.data, messageOrigin);
    }
});
  • In the guest page inside the contained webview, use chrome.runtime.sendMessage() to send messages to the containing app. 在包含的webview内的访客页面中,使用chrome.runtime.sendMessage()将消息发送到包含的应用程序。

  • In the app, use chrome.runtime.onMessage.addListener() to listen to those messages. 在应用程序中,使用chrome.runtime.onMessage.addListener()来侦听这些消息。

Note that you can message any app this way, not only the one containing your webview, but you'll need to know the app's ID for that, and use onMessageExternal instead of onMessage . 请注意,您可以通过这种方式向任何应用发送消息,而不仅仅是包含您的webview的应用,但您需要知道该应用的ID,并使用onMessageExternal而不是onMessage For the containing app, the ID is optional. 对于包含应用程序,ID是可选的。

Here's a working example of this mechanism . 是这种机制一个有效例子 It's a Polymer element, but that doesn't change the mechanism: designerProxy_ is the equivalent of your guest page; 它是一个Polymer元素,但这不会改变机制: designerProxy_相当于您的访客页面; registerDesignerProxyListener_ is the equivalent of your app. registerDesignerProxyListener_等同于您的应用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM