前面几篇文章主要讲解了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发送回调通知。