首先, 來看一下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