Lachlan Hunt created CB-4897:
--------------------------------
Summary: Support window.postMessage for two way communication
between local and remote content
Key: CB-4897
URL: https://issues.apache.org/jira/browse/CB-4897
Project: Apache Cordova
Issue Type: New Feature
Components: Plugin InAppBrowser
Affects Versions: 3.0.0
Reporter: Lachlan Hunt
For developing a hybrid web app that will use the device APIs provided by
Cordova plugins in combination with a remotely hosted web application, it is
necessary to be able to communicate between the local and remotely hosted
components.
The InAppBrowser plugin currently only provides limited support for mostly
one-way communication using executeScript to inject a new script into the
remote document. But this is limited because it only allows a single return
value, and doesn't directly allow for ongoing communication.
It would be very useful if window.postMessage were supported by the plugin.
When a message is received by the remote page (via the window.onmessage
handler), the evt.source property can provide a WindowProxy or MessagePort to
be used for subsequent communication from the remote page to the local page.
Other solutions I have considered:
* Using iframe instead of InAppBrowser, absolutely positioned and covering the
full height and width of the screen.
This works, because the Window objects are accessible to both, and posting a
message to iframe.contentWinow from the local content provides a reference to
evt.source (The local Window object). This isn't ideal because it prevents
using InAppBrowser's executeScript feature to first inject a script to enable
the two-way communication features. Ideally, I don't want the server to
include it because I don't want the web app to enable the feature when the
remote page is loaded outside of the native app.
* Creating a new MessageChannel() object and returning one of the ports via the
executeScript return value.
This doesn't work because the MessageChannel() constructor is not yet supported
by WebKit on the devices.
* Loading a remote script directly into the local content, and having that
script populate the DOM with content as needed. This isn't ideal because the
base URL of the document is not a URL to the remote host, so relative paths
don't work, and setting <base href> causes other problems.
* Communication via SharedWorker
This method is the best I've found so far, but is quite complex to setup and
operate securely.
Setup for local page:
* Embed <iframe src="http://remote.example.com/bridge.html"></iframe>
* Generate a secure shared secret key using window.crypto DOM API. (Don't use
Math.random() because it could potentially allow attackers to guess the shared
secret.)
* use iframe.contentWindow.postMessage() to send messages to bridge.html.
* Send initialisation message with the shared secret key to the bridge.
* var win = window.open("http://remote.example.com/", ...)
* When loaded, use win.executeScript(...) to inject the same bridge.html iframe
and the shared secret key into the remote page
Setup for remote page (from executeScript call):
* Embed <iframe src="http://remote.example.com/bridge.html"></iframe>
* postMessage() initialisation to the bridge with the shared secret key
Bridge.html
* Creates a new SharedWorker("bridge.js")
* Messages received by the SharedWorker are broadcast out to all other
listeners that have initialised with the same shared secret key.
Because bridge.html may potentially be embedded into any site and access the
same SharedWorker, the shared secret key lets the worker know which pages are
authorised to post messages, and reject messages received from other sources.
The complexity of that solution would be solved by having native support for
window.postMessage() in the InAppBrowser plugin.
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira