首先, 来看一下phonegap 初始化流程以及Native 与 JS 交互流程图。javascript
说明:socket server模式下, phonegap.js 源码实现的采用1 毫秒执行一次XHR请求, 当Native JS 队列里面有JS语句数据时,才是真正的1毫秒调用一下; 当没有数据, scoket server 会阻塞10毫秒, 也就是XHR 要等10秒钟才能收到结果,并进行下一次的轮询。html
一、Activity继承 DroidGap (extends PhonegapActivity)java
从phonegap.xml 中加载白名单配置 和 log配置android
二、loadUrl (每一个Activity 都初始化一次)web
》》初始化webview
》》初始化callbackServer
》》插件管理器PluginManager 编程
三、加载插件配置:缓存
》》读取 plugins.xml 配置,用map存储起来。app
1
2
3
4
5
6
7
|
<
plugins
>
<
plugin
name="Camera" value="com.phonegap.CameraLauncher"/>
<
plugin
name="Contacts" value="com.phonegap.ContactManager"/>
<
plugin
name="Crypto" value="com.phonegap.CryptoHandler"/>
<
plugin
name="File" value="com.phonegap.FileUtils"/>
<
plugin
name="Network Status" value="com.phonegap.NetworkManager"/>
</
plugins
>
|
说明:
name 是别名,javascript调用时经过别名来调用。
value:java具体实现类框架
web页面调用(例如查找联想人)
PhoneGap.exec(successCB, errorCB, "Contacts", "search", [fields, options]);socket
四、插件实现
》》编程java类,继承Plugin类(Plugin 实现了IPlugin接口),并实现execute方法。
例如联系人管理插件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
public
class
ContactManager
extends
Plugin{
/**
* action : 用来指定一个具体动做 search 表示搜索联系人
* args: 方法参数
* callbackId:js与java指定一个标识,
*/
public
PluginResult execute(String action, JSONArray args, String callbackId) {
try
{
if
(action.equals(
"search"
)) {
JSONArray res = contactAccessor.search(args.getJSONArray(
0
), args.optJSONObject(
1
));
return
new
PluginResult(status, res,
"navigator.contacts.cast"
);
}
else
if
(action.equals(
"save"
)) {
String id = contactAccessor.save(args.getJSONObject(
0
));
if
(id !=
null
) {
JSONObject res = contactAccessor.getContactById(id);
if
(res !=
null
) {
return
new
PluginResult(status, res);
}
}
}
else
if
(action.equals(
"remove"
)) {
if
(contactAccessor.remove(args.getString(
0
))) {
return
new
PluginResult(status, result);
}
}
// If we get to this point an error has occurred
JSONObject r =
new
JSONObject();
r.put(
"code"
, UNKNOWN_ERROR);
return
new
PluginResult(PluginResult.Status.ERROR, r);
}
catch
(JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
return
new
PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
}
|
五、polling和server初始化
android DroidGap 初始化时,若是loadUrl的url不是以file:// 开头时,polling = true, 不然是socket server方式
代码见CallbackServer.java 类init方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
void
init(String url) {
//System.out.println("CallbackServer.start("+url+")");
// Determine if XHR or polling is to be used
this
.usePolling =
true
;
this
.stopServer();
}
else
if
(android.net.Proxy.getDefaultHost() !=
null
) {
this
.usePolling =
true
;
this
.stopServer();
}
else
{
this
.usePolling =
false
;
this
.startServer();
}
}
|
六、phonegap.js 关键代码说明
phonegap.js在启动时,首先会经过prompt("usePolling", "gap_callbackServer:")获取调用方式: XHR 轮询 OR prompt 轮询, 若是是XHR的话, 会启动XHR调用获取http server端口 和token。
方法PhoneGap.Channel.join 启动 js server 或者polling调用
UsePolling 默认为false。 经过var polling = prompt("usePolling", "gap_callbackServer:") 获取调用方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
PhoneGap.Channel.join(
function
() {
// Start listening for XHR callbacks
setTimeout(
function
() {
if
(PhoneGap.UsePolling) {
PhoneGap.JSCallbackPolling();
}
else
{
console.log(
'PhoneGap.Channel.join>>>>>>>>>>>>>>>>>>>>>>>>>'
);<br> <span style=
"color: #ff6600;"
>
//phonegap js 首次启动获取js调用Native方式</span>
var
polling = prompt(
"usePolling"
,
"gap_callbackServer:"
);
PhoneGap.UsePolling = polling;
if
(polling ==
"true"
) {
PhoneGap.UsePolling =
true
;
<span style=
"color: #ff6600;"
>PhoneGap.JSCallbackPolling();</span>
}
else
{
PhoneGap.UsePolling =
false
;
<span style=
"color: #ff6600;"
> PhoneGap.JSCallback();</span>
}
}
}, 1);
}
|
XHR轮询:PhoneGap.JSCallback方法
经过XHR 与java端 socket进行通讯,每一毫秒执行一次JSCallback,从android socket获取javascript执行结果代码,最后经过eval动态执行javascript
XHR调用, 经过prompt 获取socket端口 和 token(uuid)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
if
(PhoneGap.JSCallbackPort ===
null
) {
PhoneGap.JSCallbackPort = <span style=
"color: #ff6600;"
>prompt(
"getPort"
,
"gap_callbackServer:"
);</span>
console.log(
'PhoneGap.JSCallback getPort>>>>>>>>>>>>>>>>>>>>>>>>>:'
+ PhoneGap.JSCallbackPort);
}
if
(PhoneGap.JSCallbackToken ===
null
) {
PhoneGap.JSCallbackToken =<span style=
"color: #ff6600;"
> prompt(
"getToken"
,
"gap_callbackServer:"
);</span>
console.log(
'PhoneGap.JSCallback getToken>>>>>>>>>>>>>>>>>>>>>>>>>:'
+ PhoneGap.JSCallbackToken);
}
xmlhttp.open(
"GET"
,
"http://127.0.0.1:"
+ PhoneGap.JSCallbackPort +
"/"
+ PhoneGap.JSCallbackToken,
true
);
xmlhttp.send();
XHR返回结果代码片断
var
msg = decodeURIComponent(xmlhttp.responseText);
setTimeout(
function
() {
try
{
var
t = eval(msg);
}
catch
(e) {
// If we're getting an error here, seeing the message will help in debugging
console.log(
"JSCallback: Message from Server: "
+ msg);
console.log(
"JSCallback Error: "
+ e);
}
}, 1);
<span style=
"color: #ff6600;"
>setTimeout(PhoneGap.JSCallback, 1);</span><br>}
|
prompt轮询: PhoneGap.JSCallbackPolling方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<span style=
"color: #ff6600;"
>PhoneGap.JSCallbackPolling</span> =
function
() {
// Exit if shutting down app
if
(PhoneGap.shuttingDown) {
return
;
}
// If polling flag was changed, stop using polling from now on
if
(!PhoneGap.UsePolling) {
PhoneGap.JSCallback();
return
;
}
var
msg = prompt(
""
,
"gap_poll:"
);
if
(msg) {
setTimeout(
function
() {
try
{
var
t = eval(
""
+ msg);
}
catch
(e) {
console.log(
"JSCallbackPolling: Message from Server: "
+ msg);
console.log(
"JSCallbackPolling Error: "
+ e);
}
}, 1);
<span style=
"color: #ff6600;"
>setTimeout(PhoneGap.JSCallbackPolling, 1);</span>
}
else
{
setTimeout(PhoneGap.JSCallbackPolling, PhoneGap.JSCallbackPollingPeriod);
}
};
|
七、总结
一、phonegap android 插件管理器PluginManager初始化时, 是每一个Activity都要初始化一次, 数据都缓存一次, 致使同一份数据缓存屡次。-- 暂不清楚为啥这样实现? 难道是phonegap 框架是为单webview 实现的,若是有知道缘由的请告知一下。
二、同第1点同样, Socket Server 每一个Activity都会初始化一下, 若是loadUrl 的url类型不一样,会不会致使scoket server状体错乱, 待验证!
三、phonegap 采用 prompt 和 XHR 轮询机制,一是会致使手机耗电状况严重, 二是了解到prompt 调用是会阻塞js执行的, 这样致使影响到页面加载速度。
phonegap 已经更名cordova, 在最新版本cordova 框架里面已经去掉了socket server模式, 详细请查看:http://www.cnblogs.com/hubcarl/p/4202784.html