phoneGap简单分析
来源:互联网 发布:linux内核poll流程 编辑:程序博客网 时间:2024/06/06 08:35
想了解phonegap 开发大概流程,应该知道如下几点。
1 js 通过html prompt弹窗接口往anroid native 发送消息。
2 android 本地利用WebChromeClient 对象的 onJsPrompt函数截获html 弹窗的消息。
3 android本地截获到消息以后,通过Pluginmanager 把消息分发到目的插件,同时通过jsMessageQueue收集需要返回给js的数据。(异步处理)
4 如何实现把jsMessageQueue的数据返回到js
5 pluginmanager负责加载和管理所有plugin.
Js通过prompt函数 调用native代码
module.exports = {
exec: function(service, action, callbackId,argsJson) {
return prompt(argsJson,'gap:'+JSON.stringify([service, action, callbackId]));
},
};
CordovaChromeClient继承 WebChromeClient 实现了 onJsPrompt函数
这个函数用来截获 js 发过来弹窗
请求中主要有以下 5种方式 消息类型:
1: gap(这个消息头 是调用android本地插件接口)
gap: 开头标志得知是调用本地插件请求,然后向 PluginManager 转发该请求。PluginManager 将会根据参数来查找并执行具体插件方法。
2: gap_bridge_mode:
//后面单独分析
3: gap_poll //
Gap_poll 之前版本留下来的,目前视乎native没有做什么处理。
4: gap_init
5: 显示android Dialog
Js调用到 android native的流程如下:
1. cordova.exec(
2. successCallback, // 成功时回调js代码
3. errorCallback, //失败时回调 js代码
4. 'CalendarPlugin', // android 本地插件java类名
5. 'addCalendarEntry', // with this action name
6. [参数]
执行上面js 函数就会执行
prompt(argsJson, 'gap:'+JSON.stringify([service, action,callbackId]));
执行这一句之后, native端CordovaChromeClient 类函数onJsPrompt 得到执行。
执行的消息头为 gap
执行android本地代码片段如下:
if (reqOk && defaultValue !=null && defaultValue.length() > 3 &&defaultValue.substring(0, 4).equals("gap:")) {
JSONArray array;
try {
array = newJSONArray(defaultValue.substring(4));
String service =array.getString(0);
String action = array.getString(1);
String callbackId =array.getString(2);
String r =this.appView.exposedJsApi.exec(service, action, callbackId, message);
result.confirm(r == null ?"" : r);
} catch (JSONException e) {
e.printStackTrace();
return false;
}
}
片段主要是解析jsonarray ,调用exposedJsApi.exec函数。
类 exposedJsApi 从名字上看就知道 暴露给js 的api(接口)
看看 appview (CordovaWebView)里面的如何初始化的。
exposedJsApi = newExposedJsApi(pluginManager, jsMessageQueue);
包含 pluginmanager 和 jsMessageQueue
Pluginmanager 是管理所有插件的, 也就是说js上调native 插件执行具体代码是有 它来分发的。
jsMessageQueue 从名字上看就知道, 是一个消息队列用来保存native端返回给js的消息的队列。
再考虑一个问题, 如果 ExposedJsApi 真的暴露给了js 是不是js 就可以通过这个类,来获得 jsMessageQueue里面的消息呢?
果然, cordovaWebView 有这么一个函数把ExposedJsApi 暴露给JS
private void exposeJsInterface() {
//这是一些判断
this.addJavascriptInterface(exposedJsApi, "_cordovaNative");//暴露给js
}
再看 ExposedJSApi.exec函数
这个函数主要是执行
pluginManager.exec(service,action, callbackId, arguments);
public void exec(final String service,final String action, final String callbackId, final String rawArgs) {
if (numPendingUiExecs.get() > 0) {//判断当前等待UI线程执行的插件个数 大于0就往主线程消息队列里面发送一个消息。
numPendingUiExecs.getAndIncrement();//统计当前主线程消息队列插件的个数。增加一个
this.ctx.getActivity().runOnUiThread(new Runnable() {
public void run() {
execHelper(service, action,callbackId, rawArgs);
numPendingUiExecs.getAndDecrement();//统计当前主线程消息队列插件的个数。减少一个
}
});
} else {//如果主线程队列里面没有消息,直接调用execHelper
execHelper(service, action,callbackId, rawArgs);
}
}
execHelper()函数如下:
private void execHelper(final String service, finalString action, final String callbackId, final String rawArgs) {
CordovaPlugin plugin =getPlugin(service);//通过js传过来的名字找到对应的插件
try {
CallbackContext callbackContext = new CallbackContext(callbackId, app);
//这个对象一看就是callback 接口前面说了ExposedJSApi 把接口暴露给js 从jsmessagequeue队列里面取消息,谁往里面添加消息呢? 就是他了!
boolean wasValidAction = plugin.execute(action,rawArgs, callbackContext);
这里就执行具体插件的 android本地代码了。
执行完成之后 客户端就会调用如下代码:
callbackContext.success(message);
sendPluginResult(newPluginResult(PluginResult.Status.OK, message));
接下来调用WebView 接口
public voidsendPluginResult(PluginResult result, String callbackId) {
this.jsMessageQueue.addPluginResult(result, callbackId);
}
webView调用jsMessageQueue.addPluginResult(result, callbackId);
jsMessageQueue主要代码如下:
JsMessage message = new JsMessage(result, callbackId);
//新建一个jsMessage 对象, 保存callbackID 和 native 回送的具体消息。
if(FORCE_ENCODE_USING_EVAL) {
StringBuilder sb = new StringBuilder(message.calculateEncodedLength() +50);
message.encodeAsJsMessage(sb);
message = new JsMessage(sb.toString());
}
enqueueMessage(message);//加入到消息队列。
上面函数主要执行 queue.add(message);
private final LinkedList<JsMessage> queue = newLinkedList<JsMessage>();
这样往jsMessageQueue消息队列里面添加消息的过程就结束了!
Js怎么取jsMessageQueue消息队列里面的消息呢?
流程大概是这样, 前面说过exposedJSApi包含了jsMessageQueue同时又暴露给js, js就可以通过 调用 exposedJSApi.retrieveJsMessages来取消息。
所以你可以在 cordova.js中搜索 retrieveJsMessages 函数名,就能找到js相关的处理,
很遗憾js看不太明白。暂时不做分析,直接看android代码吧!
gap_bridge_mode: 作用是 js请求native调用js代码的一种方式,
好像很绕, 简单来说是:
Js 请求 native 处理 保存jsMessageQueue 消息队列里面的消息通过下面两种方式调用js 语句实现数据回传。
1 LoadUrlBridgeMode:(从名字看出端倪, loadUrl方式执行js语句)
WebView loadUrlNow 的接口实现调用js 把数据返回给js
代码如下:
String js = popAndEncodeAsJs();
webView.loadUrlNow("javascript:" + js);
2 PrivateApiBridgeMode:(从名字看出端倪, 私有接口方式执行js语句)看到这,我们能想到什么, OK, 就是利用反射机制
通过WebView 获得内部私有对象 webViewCore
通过 WebViewCore 获得 sendMessage()函数
然后:从jsMessageQueue 消息队列里面取出消息拼成JS 消息 调用 sendMessage 去执行 。
代码如下:
String js = popAndEncodeAsJs();
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);
}
第二种方式只适合在 Android 3.2.4 或以上,
具体执行流程:
前奏:
Js 端需要知道:
Cordova.js文件中有一个这样的函数:
setNativeToJsBridgeMode: function(value) {
prompt(value, 'gap_bridge_mode:');
},
Value 取值如下:
nativeToJsModes = {
POLLING: 0,
LOAD_URL: 1,
ONLINE_EVENT: 2,
PRIVATE_API: 3
},
对应 android端如下:
在NativeToJsMessageQueue类里面:有一个 数组
private final BridgeMode[] registeredListeners;
构造函数对数组的初始化如下:
registeredListeners = newBridgeMode[4];
registeredListeners[0] = null; // Polling. Requires no logic.
registeredListeners[1] = newLoadUrlBridgeMode();
registeredListeners[2] = newOnlineEventsBridgeMode();
registeredListeners[3] = newPrivateApiBridgeMode();
看到没js端value 的取值刚刚好和 android端对应不同的处理方式。
1: js 调用 setNativeToJsBridgeMode(value)指定一个处理类型 假设value = 1
调用js弹窗函数 prompt(1, 'gap_bridge_mode:');
2: CordovaChromeClient 在函数 onJsPrompt 拦截到这个窗口。
对应 gap_bridge_mode 调下面函数。
this.appView.exposedJsApi.setNativeToJsBridgeMode(Integer.parseInt(message));
3: 调用 exposedJsApi setNativeToJsBridgeMode(1) 前面说过 exposed包含 jsMessageQueue对象。 所以直接调用 这个对象的 setBridgeMode(1)
4: 接下来的代码就是从数组registeredListeners取出value对应的方式来处理
Js消息。
BridgeMode activeListener =registeredListeners[value];
if (!paused &&!queue.isEmpty() && activeListener != null) {
activeListener.onNativeToJsMessageAvailable();
}
再往下就回到前面LoadUrlBridgeMode 和 PrivateApiBridgeMode 的具体处理了。
关于plugin (插件的加载过程)
前面说过,pluginManager 是管理所有 plugin的管理类。所有的plugin类定义在config.xml文件里面。其实加载plugin的过程就是 解析config.xml 的过程。
具体如下:
1 在 CordovaWebView 构造函数中会调用初始化webView的函数setup()
2 在Setup 函数中会创建pluginManager = new PluginManager(this, this.cordova);
3 在用CordovaWebView 装载url 函数loadUrlIntoView中回到用 pluginManager.init()
4 pluginManagerinit函数中会调用loadplugin()函数,这个函数主要是解析config.xml文件把定义插件的信息 保存到pluginManager中
PluginEntry entry = new PluginEntry(service, pluginClass, onload);
this.addService(entry);
- phoneGap简单分析
- phoneGap分析
- phoneGap在iOS下运行原理简单分析
- Phonegap简单了解
- Phonegap 可行性分析
- phoneGap可行性分析
- phoneGap可行性分析
- phoneGap可行性分析
- phoneGap可行性分析
- phoneGap可行性分析
- phoneGap可行性分析
- Phonegap可行性分析
- phonegap源码分析
- phoneGap可行性分析
- phoneGap可行性分析
- 使用PhoneGap开发简单案例
- 1(phonegap源码分析)说明
- phonegap原理分析-ios版
- 对于有志于成为架构师的开发者,支付宝架构团队有何建议?
- OCP 1Z0 053 84
- 遥控器对码与飞控解锁
- dataGridview 查看列是否存在..........
- Android工程目录结构相关(eclipse)
- phoneGap简单分析
- 网络编程基础
- 安装完MySQL后必须要调整的10项配置
- Trace宏:TRACE宏对于VC下程序调试来说是很有用的东西,有着类似printf的功能。
- ubuntu 用户名无法使用 sudo 问题
- ajax简单封装
- Activity生命周期
- CSDN专访:大数据时代下的商业存储
- 数组与对象