Как связаться с WebView в Chrome App?

Я разработал веб-сайт, который намереваюсь отобразить в веб-представлении в приложении Chrome. Это отлично работает.

Теперь я хочу использовать postMessage с веб-сайта, чтобы отправлять сообщения из веб-просмотра и в содержащее приложение Chrome. Это делается через top.postMessage внутри веб-просмотра.

Я пробовал следующие слушатели событий:

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

webView.addEventListener('message', messageHandler);

window.addEventListener('message', messageHandler);

document.addEventListener('message', messageHandler);

Я успешно реализовал следующие слушатели событий. Все из которых работают как ожидалось: contentload, dialog а также consolemessage,

Если я не могу заставить это работать, я рассматриваю использование consolemessage отправлять сообщения из веб-просмотра в контейнер - что-то, что я нахожу непривлекательным, и я подозреваю, что это не будет работать, если не использовать режим разработчика.

3 ответа

Решение

Причина, по которой встроенная веб-страница не может отправлять сообщения в приложение, заключается в том, что встроенная веб-страница не имеет ссылки на приложение.

top.postMessage не является ссылкой на приложение. top будет работать, если вы пытаетесь получить доступ к верхнему фрейму, в том же веб-просмотре.

Чтобы иметь возможность отправлять сообщения в приложение, на веб-странице должна быть ссылка на приложение. Самый простой способ сделать это - заставить приложение отправить первое сообщение во фрейм - сообщение "привет".

Из приложения:

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

Пример веб-просмотра демонстрирует хорошее использование postMessage для отправки сообщений между приложением и внешней страницей, загруженной в веб-просмотр.

Вот ключевые части кода.

  1. В приложении слушайте 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;
    }
    

    Затем страница может использовать эти объекты для отправки сообщения обратно в приложение.

    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);
    });
    
  • На странице гостя внутри содержимого веб-просмотра используйте chrome.runtime.sendMessage() отправлять сообщения в содержащее приложение.

  • В приложении используйте chrome.runtime.onMessage.addListener() слушать эти сообщения.

Обратите внимание, что таким способом вы можете отправлять сообщения любому приложению, не только тому, которое содержит ваше веб-представление, но вам необходимо знать идентификатор приложения для этого и использовать onMessageExternal вместо onMessage, Для содержащего приложения идентификатор необязателен.

Вот рабочий пример этого механизма. Это элемент Polymer, но это не меняет механизм: designerProxy_ является эквивалентом вашей гостевой страницы; registerDesignerProxyListener_ это эквивалент вашего приложения.

Другие вопросы по тегам