phonegap源碼分析

轉自 http://blog.csdn.net/cutesource/article/details/7324454

Phonegap已把源碼提交到apache,成爲一個非常受關注的開源框架cordova,它的跨平臺的特性有點當年Java的味道和勢頭,成爲移動平臺上比較主流的解決方案。今日品味了一下它在android端的源碼,看看它到底是如何結合native和web的。

首先我們總體上看看phonegap給我們提供的主要特性:

  • 在本地存儲和渲染HTML
  • 以Native App的方式來運行
  • 用JS調用Native功能
說白了一句話,它就是想讓我們只用web技術就能構建本地化移動應用。它比HTML5好的地方是可以預先打包好所需要的所有元素(如圖片和腳本),並且可以更大限度地集成Native特性,當然,它完全兼容HTML5。

對於這樣一款產品,如果讓我開發,我感覺最優先要解決的問題是:

  • 如何執行和渲染HTML
  • web端如何高效地調用Native API(同步和異步)
  • 提供怎樣的擴展機制來兼容新出的Native功能
帶着這三個問題我分析了它在android端的源碼,它在其他平臺上實現有待後續深究,不過我估計大體結構是一致的。下面是我分析後的架構圖:


從上圖我們看出它架構上的關鍵點:

  • 基於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#,分析完後再後續跟上。

發佈了9 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章