phonegap

phonegap 框架详解

 转自:http://www.cnblogs.com/hubcarl/p/4216844.html

首先, 来看一下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
     if  ((url !=  null ) && !url.startsWith( "file://" )) {
        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

相关文章
相关标签/搜索