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);
+ }
+ }
+ }
+ }
}