PhoneGap提供了Native Api的支持(如:重力感應、相機、聯繫人、文件、地址位置…),javascript
好比要用js獲取本機的聯繫人,能夠用:html
var options = new ContactFindOptions();java
options.filter = "李";android
options.multiple = true;git
var fields = ["displayName", "phoneNumbers", "emails"];github
navigator.contacts.find(fields, onSuccess, onError, options);apache
就樣就能夠獲取到名稱中包含‘李’的人了。json
如今PhoneGap彷佛已經成爲apache開源項目api
PhoneGap主頁數組
apache cordova(android版)
http://incubator.apache.org/cordova/index.html
源碼:https://github.com/apache/incubator-cordova-android
文檔:https://github.com/apache/incubator-cordova-docs
org.apache.cordova.CordovaChromeClient.onJsConfirm(WebView view, String url, String message, final JsResult result);
這個方法會攔截html頁面發送過來的Native Api請求(調用window.prompt()),而後交由對應的Plugin處理。
1. 服務器流程:
1) 用Plugin來提供服務供客戶端js調用,參見PhoneGap的plugin配置文件:plugins.xml,若是要本身定製plugin,須要繼承Plugin類並在plugins.xml中進行相應的配置。
2) 同步/異步
服務器根據2個參數來判斷是同步OR異步,
客戶端傳過來的異步參數 + 服務端Plugin.isSynch(action)
若是是同步,則直接把處理請求並把響應寫到客戶端
若是是異步,則啓動一個線程來處理,處理完後,將結果經過CallbackServer寫到客戶端。
3) CallbackServer至關於xmlHttpResponse,負責將數據異步寫到客戶端。它在內部會有一個socket監聽,不停的接收來自於客戶端的請求,
若是發現變量(javascript)中有數據的話,就寫到客戶端,
若是沒有,則睡眠10s,10s後,若是有數據,則寫到客戶端,不然寫一個404異常到客戶端而後這次鏈接中斷,從新接收新的客戶端請求(客戶端有一個輪詢,若是服務端返回404,則客戶端會每隔一段時間請求一次服務器)
4) 服務器異步返回給客戶端的數據格式:
// 正常處理後的返回(Contacts2表示請求的ID,客戶端根據這個ID調用對應的回調函數):
// 其中,紅色的json對象是PluginResult對象(自定義plugin時也須要返回一個PluginResult對象)
// 黑色的javascript腳本是通過PluginManager.exec()包裝過的,被客戶端eval解釋執行。
HTTP/1.1 200 OK
require('cordova').callbackSuccess('Contacts2',{status:1,message:[{"displayName":"%E6%9D%8E%E6%8C%9A","id":"44","rawId":"46","phoneNumbers":[{"type":"mobile","value":"18608020312","id":"92","pref":false}]}],keepCallback:false});
// 404保持鏈接的返回
HTTP/1.1 404 NO DATA
2. 客戶端流程:
1) 調用Native Api
PhoneGap的js框架,在調用Native Api時,都會匯聚到exec這個方法:
define('cordova/exec', function(require, exports, module) {
var cordova = require('cordova');
module.exports = function(success, fail, service, action, args) {
try {
var callbackId = service + cordova.callbackId++;
if (success || fail) {
cordova.callbacks[callbackId] = {
success: success,
fail: fail
};
}
//這裏給服務器發送請求,
//service表示採用哪一個
//true表示採用異步調用
//服務器會判斷這個service+action是否支持異步調用
//若是是同步,則服務器會當即返回處理結果到變量r
//若是是異步,則服務器返回空串」」
var r = prompt(JSON.stringify(args),
"gap:" + JSON.stringify([service, action, callbackId, true]));
// If a result was returned
if (r.length > 0) {
……
}
} catch(e2) {
console.log("Error: " + e2);
}
};
});
2) 異步回調
define('cordova/plugin/android/callback', function(require, exports, module) {
……
callback = function() {
……
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState === 4) {
// 服務器端返回結果數據,客戶端經過eval執行結果
// 再次往服務器發起請求。
if (xmlhttp.status === 200) {
// Need to url decode the response
var msg = decodeURIComponent(xmlhttp.responseText);
setTimeout(function() {
try {
var t = eval(msg);
} catch(e) {
console.log("JSCallback: Message from Server: " + msg);
console.log("JSCallback Error: " + e);
}
}, 1);
setTimeout(callback, 1);
}
// 服務器與客戶端約定若是404,則客戶端接着請求服務器,10s內,
// 若是客戶端調用了Native Api,則服務器服務數據後,進入上面200的邏輯,
// 若是客戶端沒調用,則服務器依然返回404,如此循環。
else if (xmlhttp.status === 404) {
setTimeout(callback, 10);
}
……
}
};
xmlhttp.open("GET", "http://127.0.0.1:" + port + "/" + token, true);
xmlhttp.send();
};
});
3. 自定義plugin流程:
1) 服務端:
繼承com.phonegap.api.Plugin類,重寫execute方法
public PluginResult execute(String action, JSONArray args, String callbackId){}
在plugins.xml中配置咱們的類,
<plugin name="LoginPlugin" value="com.synnex.plugin.LoginPlugin"/>
NOTE:
isSynch()方法是告訴PhoneGap框架,此處理是同步OR異步,true表示同步,false表示異步,默認爲flase
在同步處理的時候,不要去作UI操做(如:修改EditText內容),能夠交由Handler更新UI。
2) 客戶端:
// 向PhoneGap註冊服務
var LoginPlugin = function(){};
LoginPlugin.prototype.dologin = function(successCallback, failureCallback, args)
{
//」LoginPlugin」須要與服務端xml中的名稱一致。
//」login」即傳給服務端excute()方法的action參數
//args必須是一個數組,對應execute()方法的args參數
return cordova.exec(successCallback, failureCallback, "LoginPlugin", "login", args);
};
cordova.addConstructor(function()
{
cordova.addPlugin("loginPlugin", new LoginPlugin());
});
// 調用時:
// 此處loginPlugin爲上面addPlugin的第1個參數,
// dologin爲上面LoginPlugin函數的方法名
// msg爲服務端返回的數據。
plugins.loginPlugin.dologin(function(msg)
{
navigator.notification.alert(msg, undefined, "Success", "OK");
}, function(msg)
{
navigator.notification.alert(msg || "Error", undefined, "Failure", "OK");
}, [{username: "troyz", password: "123456"}]);