Uploaded image for project: 'Apache Cordova'
  1. Apache Cordova
  2. CB-4897

Support window.postMessage for two way communication between local and remote content



    • New Feature
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • 3.0.0
    • None
    • None


      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


      • 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.




            Unassigned Unassigned
            lachlan.hunt Lachlan Hunt
            21 Vote for this issue
            28 Start watching this issue