Phonegap已把源码提交到apache,成为一个非常受关注的开源框架cordova,它的跨平台的特性有点当年Java的味道和势头,成为移动平台上比较主流的解决方案。今日品味了一下它在android端的源码,看看它到底是如何结合native和web的。
首先我们总体上看看phonegap给我们提供的主要特性:
- 在本地存储和渲染HTML
- 以Native App的方式来运行
- 用JS调用Native功能
对于这样一款产品,如果让我开发,我感觉最优先要解决的问题是:
- 如何执行和渲染HTML
- web端如何高效地调用Native API(同步和异步)
- 提供怎样的扩展机制来兼容新出的Native功能
从上图我们看出它架构上的关键点:
- 基于WebView来渲染HTML
- 基于Plugin的模式来封装Native API,包括Phonegap本身提供的和开发者自己定制的
- 以覆盖prompt方法的形式来实现Web端对Android端的调用
- 以XHR或JSONP的方式来实现Android端向Web端返回异步调用的结果
1)基于WebView来渲染HTML
这点比较简单,大家都想得到,它实际上就是个内嵌的浏览器,各个移动平台也提供了这样的组件,在Android上就是WebView。
但Phonegap对WebView做了些改造,它通过扩展WebViewClient和WebChromeClient改变了些标准行为,它用CordovaWebViewClient扩展WebViewClient,并复写shouldOverrideUrlLoading、onPageStarted、onPageFinished等方法,使得它扩展了web纯url网页调用的行为,具备了通过geo:xxx调用intent,通过sms:xxx发短信等能力。另外,它用CordovaChromeClient扩展WebChromeClient,并复写了onJsAlert、onJsConfirm等方法,用Native的风格的窗口来相应js端alert、confirm的调用,使其更像是一个native的程序。更关键的是它复写了prompt,并通过这个方法来实现js对android端的调用,下面会详细谈这点。
总之,它就是基于CordovaWebViewClient和CordovaChromeClient扩展了WebView,使其具备标准的HTML执行渲染能力外,更具备Native化的样式和能力。这块的代码我就不具体去讲了,比较简单。
2)基于Plugin的模式来封装Native API
这点也比较简单,但凡想让用户去扩展,都会想到以Plugin的模式来构架,http://wiki.phonegap.com/w/page/36752779/PhoneGap%20Plugins,这篇官方文档比较详细地讲解了如何使用和开发Plugin。
它的结构也比较扁平,总共三个类Plugin, PluginManager和PluginResult,一个配置文件plugin.xml,具体职责我就不多说,看看名字就知道了。
3)以覆盖prompt方法的形式来实现Web端对Android端的调用
这点是我学这个框架最想看的地方,虽然有点失望(感觉有点猥琐),但还是比较实用和直接。
WebChromeClient提供了一个onJsPrompt方法,这个方法是当web端调用prompt方法时就会调到。于是乎,它就把这个方法给改了,改成Android向Web端暴露的接口,当Web要调用任何Android(Java)端的方法时,就调prompt,onJsPrompt被调后,它再去解析参数来代理后续的行为。这时,它就主要是调用Plugin,通过Plugin来满足Web端的需求。时序图如下图所示:
前面比较好理解,但最后一步为啥要向一个server sendJavascript呢?这就是它实现异步调用的机制。
4)以XHR或JSONP的方式来实现Android端向Web端返回异步调用的结果
同步调用就不多说了,它没有上面时序图的最后一步,plugin.execute后就直接返回结果,通过JsPromptResult.confirm向js回调。
而异步调用是这个框架里难度最大的一个,而却是Native API调用大部分的适用场景,比如Camera,这都会启动Native端其他程序,等这些程序操作完了后,还需要得到它们的执行结果,比如拿到拍照后的相片。
Phonegap实际上是基于长背包的方式来实现Android端向web端的反推。长背包我就不多解释了,查查comet就能了解,它的机制就是在web端发起ajax的周期性调用,Android端起一个本地Socket Server,并保持一个JS队列,如果有请求来,它就把队列里的JS返回,web端再执行这个JS,通过这个方式模拟了Android端向web端推动执行结果。而上图中的sendJavascript实际上就是把执行结果用JSON的形式存在队列里等着web端来取。
但XHR(或Ajax)有跨域的限制,比如如果web端的html不是本地的file而是从远端(URL)下载下来的,那么它就不能向本地的server发起ajax请求(因为不同域),所以它提供了一个备选方案:JSONP,这也是一个标准的解决ajax跨域的方案,实际上就是把JS下载下来执行,这个就不多说了,可以通过关键字JSONP继续深究。
总的来说,这块采用的还是比较通用的解决方案,不过值得考量的是,这样频繁的轮询ajax是否会对性能和电池有所影响,除此之外,基本和直接Native程序是差不多的,这比直接调用HTML5确实优化不少。
这是我对phonegap在android端的源码分析,后面还想再看看在IOS和Windows Phone上是如何实现的,不过我得赶紧熟悉一下Objective-C和C#,分析完后再后续跟上。
转载自:http://blog.csdn.net/cutesource/article/details/7324454