前面幾篇文章主要講解了PhoneGap幾個重要的類,如果看到這里,相信大家對PhoneGap也有了一定的了解。
PhoneGap類間調用關系
在講解PhoneGap的交互原理之前,我們把原來的內容串講一下,以加深理解。請看下面的類間調用關系圖:
在我們創建Android應用程序的時候,一般會先創建一個Activity。PhoneGap應用程序創建時Activity應繼承DroidGap類。當Activity啟動時,系統會調用onCreate方法。在DroidGap類中,復寫了Activity的onCreate方法。
在DroidGap的onCreate方法中,對Window做了一些設置,並設置了WebView的布局。最后設置了音量硬件控制功能。代碼如下:

1 /** 2 * Called when the activity is first created. 3 * 4 * @param savedInstanceState 5 */ 6 @SuppressWarnings("deprecation") 7 @Override 8 public void onCreate(Bundle savedInstanceState) { 9 //preferences = new PreferenceSet(); 10 11 LOG.d(TAG, "DroidGap.onCreate()"); 12 super.onCreate(savedInstanceState); 13 14 if(!this.getBooleanProperty("showTitle", false)) 15 { 16 getWindow().requestFeature(Window.FEATURE_NO_TITLE); 17 } 18 19 if(this.getBooleanProperty("setFullscreen", false)) 20 { 21 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 22 WindowManager.LayoutParams.FLAG_FULLSCREEN); 23 } 24 else 25 { 26 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, 27 WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); 28 } 29 // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket! 30 Display display = getWindowManager().getDefaultDisplay(); 31 int width = display.getWidth(); 32 int height = display.getHeight(); 33 34 root = new LinearLayoutSoftKeyboardDetect(this, width, height); 35 root.setOrientation(LinearLayout.VERTICAL); 36 root.setBackgroundColor(this.backgroundColor); 37 root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 38 ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); 39 40 // Setup the hardware volume controls to handle volume control 41 setVolumeControlStream(AudioManager.STREAM_MUSIC); 42 }
然后PhoneGap應用程序調用了loadUrl方法,
super.loadUrl("file:///android_asset/www/index.html");
之前說過,loadUrl可以看作是整個應用程序的入口函數。
loadUrl函數會調用Init方法,創建一個CordovaWebView,並設置了CordovaWebViewClient和CordovaChromeClient。
在實例化CordovaWebView時,對PluginManager做了初始化工作,而在CordovaWebViewClient的onPageStarted方法里初始化並啟動CallbackServer。
CordovaWebViewClient的onJsPrompt方法截獲Web端的JavaScript消息,調用PluginManager的exce方法執行插件。
插件執行成功后調用CallbackServer的sendJavaScript方法給Js端返回回調Js代碼。
這就是PhoneGap類間的調用關系,整個PhoneGap工作流程大概也就清晰了。
Js和Java交互原理
-
js↔java同步過程
同步處理:
從js的prompt到WebChromeClient的onJSPrompt是一個跨線程的同步調用過程,如上圖:
在cordova.js文件中,可以找到如下代碼:
var r = prompt(JSON.stringify(args), "gap:"+JSON.stringify([service, action, callbackId, true]));
這句prompt便實現了本地代碼調用。本地代碼通過WebChromeClient攔截onJsPrompt回調,利用gap:開頭標志得知是調用本地插件請求,然后向PluginManager轉發該請求。PluginManager將會根據參數來查找並執行具體插件方法。
js層通過prompt向本地發送poll請求,本地將從CallBackServer中拿出下一個回調返回給js層。
-
js↔java異步過程
異步處理:
為了區別異步和同步。若prompt返回的是空字符串,那么將認為是異步調用。此時PhoneGap會在JS層保留回調函數,待本地層向CallBackServer發送回調后進行執行。
本地層怎么區別哪個回調?PhoneGap對此的處理十分簡單,在cordova.js中定義了一個callbackId的自增種子,並將每個callBack插入callBacks中去。無論同步異步,每個plugin調用都將得到一個流水號碼作為回調標識。這個回調標識在prompt階段便傳遞到了本地層。當本地層的Plugin異步結束后,便可以根據該callbackId找到回調。並向CallBackServer發送回調通知。