Как связаться с 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 для отправки сообщений между приложением и внешней страницей, загруженной в веб-просмотр.
Вот ключевые части кода.
В приложении слушайте
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/*"); }
На внешней странице слушайте
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); } }
Приложение также должно слушать
message
событие для получения сообщений с внешней страницы.window.addEventListener('message', function(e) { log("[???] messagereceived: " + e.data); });
На странице гостя внутри содержимого веб-просмотра используйте
chrome.runtime.sendMessage()
отправлять сообщения в содержащее приложение.В приложении используйте
chrome.runtime.onMessage.addListener()
слушать эти сообщения.
Обратите внимание, что таким способом вы можете отправлять сообщения любому приложению, не только тому, которое содержит ваше веб-представление, но вам необходимо знать идентификатор приложения для этого и использовать onMessageExternal
вместо onMessage
, Для содержащего приложения идентификатор необязателен.
Вот рабочий пример этого механизма. Это элемент Polymer, но это не меняет механизм: designerProxy_
является эквивалентом вашей гостевой страницы; registerDesignerProxyListener_
это эквивалент вашего приложения.