You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ka...@apache.org on 2014/11/12 17:49:43 UTC

[3/9] js commit: CB-7735 Fix iOS bridge race condition when using innerHTML on

CB-7735 Fix iOS bridge race condition when using innerHTML on <body>


Project: http://git-wip-us.apache.org/repos/asf/cordova-js/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-js/commit/94291706
Tree: http://git-wip-us.apache.org/repos/asf/cordova-js/tree/94291706
Diff: http://git-wip-us.apache.org/repos/asf/cordova-js/diff/94291706

Branch: refs/heads/3.7.x
Commit: 94291706945c42fd47fa632ed30f5eb811080e95
Parents: d9e2a1c
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Oct 14 16:39:06 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 14 16:39:48 2014 -0400

----------------------------------------------------------------------
 src/ios/exec.js | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-js/blob/94291706/src/ios/exec.js
----------------------------------------------------------------------
diff --git a/src/ios/exec.js b/src/ios/exec.js
index e3e8b32..5c7cc98 100644
--- a/src/ios/exec.js
+++ b/src/ios/exec.js
@@ -52,15 +52,20 @@ var cordova = require('cordova'),
     commandQueue = [], // Contains pending JS->Native messages.
     isInContextOfEvalJs = 0;
 
-function createExecIframe() {
+function createExecIframe(src, unloadListener) {
     var iframe = document.createElement("iframe");
     iframe.style.display = 'none';
+    // Both the unload listener and the src must be set before adding the iframe
+    // to the document in order to avoid race conditions. Callbacks from native
+    // can happen within the appendChild() call!
+    iframe.onunload = unloadListener;
+    iframe.src = src;
     document.body.appendChild(iframe);
     return iframe;
 }
 
 function createHashIframe() {
-    var ret = createExecIframe();
+    var ret = createExecIframe('about:blank');
     // Hash changes don't work on about:blank, so switch it to file:///.
     ret.contentWindow.history.replaceState(null, null, 'file:///#');
     return ret;
@@ -233,6 +238,11 @@ function pokeNativeViaXhr() {
     execXhr.send(null);
 }
 
+function onIframeUnload() {
+    execIframe = null;
+    setTimeout(pokeNativeViaIframe, 0);
+}
+
 function pokeNativeViaIframe() {
     // CB-5488 - Don't attempt to create iframe before document.body is available.
     if (!document.body) {
@@ -240,6 +250,7 @@ function pokeNativeViaIframe() {
         return;
     }
     if (bridgeMode === jsToNativeModes.IFRAME_HASH_NO_PAYLOAD || bridgeMode === jsToNativeModes.IFRAME_HASH_WITH_PAYLOAD) {
+        // TODO: This bridge mode doesn't properly support being removed from the DOM (CB-7735)
         execHashIframe = execHashIframe || createHashIframe();
         // Check if they've removed it from the DOM, and put it back if so.
         if (!execHashIframe.contentWindow) {
@@ -253,12 +264,15 @@ function pokeNativeViaIframe() {
         }
         execHashIframe.contentWindow.location.hash = hashValue;
     } else {
-        execIframe = execIframe || createExecIframe();
         // Check if they've removed it from the DOM, and put it back if so.
-        if (!execIframe.contentWindow) {
-            execIframe = createExecIframe();
+        if (execIframe && execIframe.contentWindow) {
+            // Listen for unload, since it can happen (CB-7735) that the iframe gets
+            // removed from the DOM before it gets a chance to poke the native side.
+            execIframe.contentWindow.onunload = onIframeUnload;
+            execIframe.src = 'gap://ready';
+        } else {
+            execIframe = createExecIframe('gap://ready', onIframeUnload);
         }
-        execIframe.src = "gap://ready";
     }
 }
 
@@ -276,6 +290,10 @@ iOSExec.setJsToNativeBridgeMode = function(mode) {
 };
 
 iOSExec.nativeFetchMessages = function() {
+    // Stop listing for window detatch once native side confirms poke.
+    if (execIframe && execIframe.contentWindow) {
+        execIframe.contentWindow.onunload = null;
+    }
     // Each entry in commandQueue is a JSON string already.
     if (!commandQueue.length) {
         return '';


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org