android phonegap js <-> java交互原理
项目里 用了一下 phonegap来 包装我们的client java jar, 已提供js接口. 其中 从js到java 的调用还是颇有点神秘感. 就顺便看了看phonegap的实现.
cordova5.1.1:
https://github.com/apache/cordova-android/archive/5.1.1.zip
在android上, phonegap使用了WebView.
http://developer.android.com/guide/webapps/webview.html
WebView提供addJavascriptInterface来 把一个Java object映射为JS object, 官网上有如下示例:
class JsObject { @JavascriptInterface public String toString() { return "injectedObject"; } } webView.addJavascriptInterface(new JsObject(), "injectedObject"); webView.loadData("", "text/html", null); webView.loadUrl("javascript:alert(injectedObject.toString())");
在phonegap-android中,
SystemWebViewEngine.java, init() -> exposeJsInterface():
SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge); webView.addJavascriptInterface(exposedJsApi, "_cordovaNative");
cordova-js-src/exec.js:
function androidExec(success, fail, service, action, args) { // ... var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
cordova-js-src/android/nativeapiprovider.js:
var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi'); var currentApi = nativeApi; module.exports = { get: function() { return currentApi; }, // ...
JS端 可以同步 从 cordova.exec()直接返回结果; 也可以异步polling的方式, 调用 _cordovaNative对象的retrieveJsMessages方法取结果.
注: js端也可以不通过 addJavascriptInterface, 而通过 promt() -> 触发 WebView中WebChromeClient的onJsPrompt来做. 这是android4.1之前的做法. 算一个hack.
回到java端, 上面已经 提供了 名为"_cordovaNative"的 js对象映射到 一个 java CordovaBridge对象.
CordovaBridge.java, jsExec() 对应了 cordova.exec(). 其中调用了 PluginManager.exec():
public void exec(final String service, final String action, final String callbackId, final String rawArgs) { // 根据service 做java 反射 生成对应的 CordovaPlugin对象 // 调用此对象的 exec()
返回结果 放入一个 NativeToJsMessageQueue中, js端通过同步或异步方式 取回结果. NativeToJsMessageQueue中通过synchronized (this) 来同步 进出queue的操作.