前面几篇文章主要讲解了PhoneGap几个重要的类,如果看到这里,相信大家对PhoneGap也有了一定的了解。
PhoneGap类间调用关系
在讲解PhoneGap的交互原理之前,我们把原来的内容串讲一下,以加深理解。请看下面的类间调用关系图:
在我们创建Android应用程序的时候,一般会先创建一个Activity。PhoneGap应用程序创建时Activity应继承DroidGap类。当Activity启动时,系统会调用onCreate方法。在DroidGap类中,复写了Activity的onCreate方法。
在DroidGap的onCreate方法中,对Window做了一些设置,并设置了WebView的布局。最后设置了音量硬件控制功能。代码如下:
onCreate
1 /**
2 * Called when the activity is first created.3 *4 *@paramsavedInstanceState5 */
6 @SuppressWarnings("deprecation")7 @Override8 public voidonCreate(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(newLinearLayout.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发送回调通知。