PhoneGap原理分析(Android版)


PhoneGap提供了Native Api的支持(如:重力感應、相機、聯系人、文件、地址位置…),

比如要用js獲取本機的聯系人,可以用:

      var options = new ContactFindOptions();

        options.filter = "";

        options.multiple = true;

        var fields = ["displayName", "phoneNumbers", "emails"];

        navigator.contacts.find(fields, onSuccess, onError, options);

就樣就可以獲取到名稱中包含‘李’的人了。

 

現在PhoneGap似乎已經成為apache開源項目

 

PhoneGap主頁

http://phonegap.com/

 

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"}]);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM