You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2012/08/22 15:57:11 UTC

[6/6] android commit: Added Native-JS bridge mode that uses private WebView APIs.

Added Native-JS bridge mode that uses private WebView APIs.


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

Branch: refs/heads/master
Commit: bbafe53a2b667990b85b56f50899771edc04a50c
Parents: e239fd9
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Aug 21 20:45:59 2012 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Aug 22 09:46:30 2012 -0400

----------------------------------------------------------------------
 .../org/apache/cordova/NativeToJsMessageQueue.java |   79 +++++++++++++--
 1 files changed, 70 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/bbafe53a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index e9f093a..9ba1562 100755
--- a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -18,11 +18,17 @@
 */
 package org.apache.cordova;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.LinkedList;
 
 import org.apache.cordova.api.CordovaInterface;
 
+import android.os.Message;
 import android.util.Log;
+import android.webkit.WebView;
 
 /**
  * Holds the list of messages to be sent to the WebView.
@@ -54,17 +60,13 @@ public class NativeToJsMessageQueue {
     public NativeToJsMessageQueue(CordovaWebView webView, CordovaInterface cordova) {
         this.cordova = cordova;
         this.webView = webView;
-        registeredListeners = new BridgeMode[4];
-        registeredListeners[0] = null;
+        registeredListeners = new BridgeMode[5];
+        registeredListeners[0] = null;  // Polling. Requires no logic.
         registeredListeners[1] = new CallbackBridgeMode();
         registeredListeners[2] = new LoadUrlBridgeMode();
         registeredListeners[3] = new OnlineEventsBridgeMode();
+        registeredListeners[4] = new PrivateApiBridgeMode();
         reset();
-//        POLLING: 0,
-//        HANGING_GET: 1,
-//        LOAD_URL: 2,
-//        ONLINE_EVENT: 3,
-//        PRIVATE_API: 4
     }
     
     /**
@@ -167,14 +169,14 @@ public class NativeToJsMessageQueue {
     }
     
     /** Uses webView.loadUrl("javascript:") to execute messages. */
-    public class LoadUrlBridgeMode implements BridgeMode {
+    private class LoadUrlBridgeMode implements BridgeMode {
         public void onNativeToJsMessageAvailable() {
             webView.loadUrlNow("javascript:" + popAll());
         }
     }
 
     /** Uses online/offline events to tell the JS when to poll for messages. */
-    public class OnlineEventsBridgeMode implements BridgeMode {
+    private class OnlineEventsBridgeMode implements BridgeMode {
         boolean online = true;
         final Runnable runnable = new Runnable() {
             @Override
@@ -190,4 +192,63 @@ public class NativeToJsMessageQueue {
             cordova.getActivity().runOnUiThread(runnable);
         }
     }
+    
+    /**
+     * Uses Java reflection to access an API that lets us eval JS.
+     * Requires Android 3.2.4 or above. 
+     */
+    private class PrivateApiBridgeMode implements BridgeMode {
+    	// Message added in commit:
+    	// http://omapzoom.org/?p=platform/frameworks/base.git;a=commitdiff;h=9497c5f8c4bc7c47789e5ccde01179abc31ffeb2
+    	// Which first appeared in 3.2.4ish.
+    	private static final int EXECUTE_JS = 194;
+    	
+    	Method sendMessageMethod;
+    	Object webViewCore;
+    	boolean initFailed;
+
+    	@SuppressWarnings("rawtypes")
+    	private void initReflection() {
+        	Object webViewObject = webView;
+    		Class webViewClass = WebView.class;
+        	try {
+    			Field f = webViewClass.getDeclaredField("mProvider");
+    			f.setAccessible(true);
+    			webViewObject = f.get(webView);
+    			webViewClass = webViewObject.getClass();
+        	} catch (Throwable e) {
+        		// mProvider is only required on newer Android releases.
+    		}
+        	
+        	try {
+    			Field f = webViewClass.getDeclaredField("mWebViewCore");
+                f.setAccessible(true);
+    			webViewCore = f.get(webViewObject);
+    			
+    			if (webViewCore != null) {
+    				sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class);
+	    			sendMessageMethod.setAccessible(true);	    			
+    			}
+    		} catch (Throwable e) {
+    			initFailed = true;
+				Log.e(LOG_TAG, "PrivateApiBridgeMode failed to find the expected APIs.", e);
+    		}
+    	}
+    	
+        public void onNativeToJsMessageAvailable() {
+        	if (sendMessageMethod == null && !initFailed) {
+        		initReflection();
+        	}
+        	// webViewCore is lazily initialized, and so may not be available right away.
+        	if (sendMessageMethod != null) {
+	        	String js = popAll();
+	        	Message execJsMessage = Message.obtain(null, EXECUTE_JS, js);
+				try {
+				    sendMessageMethod.invoke(webViewCore, execJsMessage);
+				} catch (Throwable e) {
+					Log.e(LOG_TAG, "Reflection message bridge failed.", e);
+				}
+        	}
+        }
+    }    
 }