分享

phonegap源码分析(一)------ android

Phonegap已把源码提交到apache,成为一个非常受关注的开源框架cordova,它的跨平台的特性有点当年Java的味道和势头,成为移动平台上比较主流的解决方案。今日品味了一下它在android端的源码,看看它到底是如何结合native和web的。
首先我们总体上看看phonegap给我们提供的主要特性:

在本地存储和渲染HTML 以Native App的方式来运行 用JS调用Native功能

说白了一句话,它就是想让我们只用web技术就能构建本地化移动应用。它比HTML5好的地方是可以预先打包好所需要的所有元素(如图片和脚本),并且可以更大限度地集成Native特性,当然,它完全兼容HTML5。
对于这样一款产品,如果让我开发,我感觉最优先要解决的问题是:

如何执行和渲染HTML web端如何高效地调用Native API(同步和异步) 提供怎样的扩展机制来兼容新出的Native功能

带着这三个问题我分析了它在android端的源码,它在其他平台上实现有待后续深究,不过我估计大体结构是一致的。下面是我分析后的架构图:
1.png
从上图我们看出它架构上的关键点:

基于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端的需求。时序图如下图所示:
2.jpg
前面比较好理解,但最后一步为啥要向一个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#,分析完后再后续跟上。

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条