ChromeApp中如何与WebView通信?

How to communicate with WebView in Chrome App?

我开发了一个网站,我打算在 Chrome 应用程序中的 webview 中显示该网站。这很好用。

现在,我想使用网站上的 postMessage,将消息从 webview 发送到包含 Chrome 的应用程序中。这是通过网络视图中的 top.postMessage 完成的。

我尝试了以下事件侦听器:

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

webView.addEventListener('message', messageHandler);

window.addEventListener('message', messageHandler);

document.addEventListener('message', messageHandler);

我已经成功实现了以下事件侦听器。所有这些都按预期工作:contentloaddialogconsolemessage.

除非我能让它工作,否则我正在考虑使用 consolemessage 将消息从 webview 发送到容器 - 我觉得这没有吸引力,我怀疑在不使用开发人员时它不会工作模式。

webview sample 有一个很好的演示,使用 postMessage 在应用程序和 webview 中加载的外部页面之间发送消息。

以下是关键代码。

  1. 在应用程序中,监听 webview 的 loadstop 事件并向页面发送初始消息。您可以将此消息限制在特定的域或页面。

    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. 在外部页面中,侦听message事件并保存源和来源。

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

    然后页面可以使用这些对象 post 向应用返回消息。

    function doSendMessage() {
     if (appWindow && appOrigin) {
      appWindow.postMessage("this is a message from the page!", appOrigin);
     } 
    }
    
  3. 该应用程序还应侦听 message 事件以接收来自外部页面的消息。

    window.addEventListener('message', function(e) {
     log("[???] messagereceived: " + e.data);
    });
    
  • 在包含的 webview 内的访客页面中,使用 chrome.runtime.sendMessage() 向包含的应用程序发送消息。

  • 在应用程序中,使用 chrome.runtime.onMessage.addListener() 收听这些消息。

请注意,您可以通过这种方式向任何应用程序发送消息,不仅是包含您的网络视图的应用程序,而且您需要知道该应用程序的 ID,并使用 onMessageExternal 而不是 onMessage .对于包含应用程序,ID 是可选的。

这是a working example of this mechanism。它是一个 Polymer 元素,但这并没有改变机制:designerProxy_ 相当于您的访客页面; registerDesignerProxyListener_ 相当于您的应用。

嵌入式网页无法post向应用程序发送消息的原因是嵌入式网页没有对应用程序的引用。

top.postMessage 不是 对应用程序的引用。 top 如果您尝试访问同一个 web 视图中最顶层的框架,则可以使用。

为了能够向应用程序发送消息,网页需要引用该应用程序。最简单的方法是让应用程序向框架发送第一条消息 - "hello"-message.

来自应用:

// 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.
});

在网页中:

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