项目里 用了一下 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, 官网上有如下示例:
classJsObject {
@JavascriptInterfacepublic 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 = newSystemExposedJsApi(bridge);
webView.addJavascriptInterface(exposedJsApi,"_cordovaNative");
cordova-js-src/exec.js:
functionandroidExec(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, finalString rawArgs) {//根据service 做java 反射 生成对应的 CordovaPlugin对象//调用此对象的 exec()
返回结果 放入一个NativeToJsMessageQueue中, js端通过同步或异步方式 取回结果. NativeToJsMessageQueue中通过synchronized (this) 来同步 进出queue的操作.