1. 程式人生 > >phonegap原始碼分析(一)------ android

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端的原始碼,它在其他平臺上實現有待後續深究,不過我估計大體結構是一致的。下面是我分析後的架構圖:


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

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

相關推薦

phonegap原始碼分析------ android

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

Android系統播放器MediaPlayer原始碼分析

前言 對於MediaPlayer播放器的原始碼分析內容相對來說比較多,會從Java->JNI->C/C++慢慢分析,後面會慢慢更新。另外,部落格只作為自己學習記錄的一種方式,對於其他的不過多的評論。 MediaPlayerDemo public class MainA

Android recyclerview原始碼分析

原始碼分析基於22.2.1版本 先預覽一下recyclerview 相關的類   今天先分析SortedList 和SortedListAdapterCallback 先看下這兩個類的用法  SortedList<Object> mDataList=new

Android SharedPreference 原始碼分析

1. 前言 眾所周知,SharedPreferences是Android平臺上一個輕量級的儲存類,用來儲存應用的一些常用配置,比如Activity狀態,Activity暫停時,將此activity的狀態儲存到SharedPereferences中;當Activ

Android 8.0 RIL原始碼分析

1.去電流程三中跟蹤到最後的時候可以看到其呼叫了RIL的dail方法 這裡繼續以此分析其從RIL到Modem的流程 @Override public void dial(String address, int clirMode, UUSInfo

Flume NG原始碼分析基於靜態properties檔案的配置模組

日誌收集是網際網路公司的一個重要服務,Flume NG是Apache的頂級專案,是分散式日誌收集服務的一個開源實現,具有良好的擴充套件性,與其他很多開源元件可以無縫整合。搜了一圈發現介紹Flume NG的文章有不少,但是深入分析Flume NG原始碼的卻沒有。準備寫一個系列分析一下Flume NG的

GCC原始碼分析——介紹與安裝

原文連結:http://blog.csdn.net/sonicling/article/details/6702031     上半年一直在做有關GCC和LD的專案,到現在還沒做完。最近幾天程式設計的那臺電腦壞了,所以趁此間隙寫一點相關的分析和

Glide原始碼分析從用法來看之with方法

繼續啃原始碼,用過Glide的人,肯定都覺得它好好用,我們一般只需要幾行程式碼,就可以達到我們想要的效果,可以在這個背後是什麼呢?就需要我們來看了。 我一般看原始碼,我喜歡先從用法來看,然後一步一步的再細扣,所以就先從用法來看Glide的整體流程。 用過Glide的人,用下面這段

zigbee 之ZStack-2.5.1a原始碼分析

先看main, 在檔案Zmain.c裡面 main osal_init_system(); osalInitTasks(); ... ... SampleApp_Init( taskID ); // 使用者定義的任務

Docker Client原始碼分析

主要內容: Docker Client在Docker中的定位,以及Docker Client原始碼的初步分析。 本文選取Docker拆分為DockerCE(社群版)和DockerEE(企業版)之後的Docker-CE的第一個穩定版本v17.06.0-ce。 https://github.com/docker

Hibernate使用及原始碼分析

Hibernate使用及原始碼分析(一) 本篇文章主要通過hibernate初級使用分析一下原始碼,只是給初學者一點小小的建議,不喜勿噴,謝謝! hibernate環境搭建 簡單使用 原始碼走讀 一 hibernate環境搭建 這裡直接

SpringCloud原始碼分析--客戶端搭建

一、前言 上一節的註冊中心搭建完成了,本節開始搭建客戶端,其實對於springcloud的Eureka註冊中心而言,他本身就是服務端也是客戶端,我們上節待見服務端註冊中心的時候,已經通過配置來設定其不向自己註冊,和不去檢索服務的功能,保持了其作為服務註冊中心的相對的功能單一性。 二、pom檔案

Vue原始碼分析:入口檔案

Vue原始碼分析(一):入口檔案   首先開啟命令列,從github下載原始碼,下載到自己的工作目錄。 git clone https://github.com/vuejs/vue.git   這裡我下載的是2.5.17版本的,vue 原始碼是由各種模組用 rollup 工具

okhttp原始碼分析——基本流程超詳細

1.okhttp原始碼分析(一)——基本流程(超詳細) 2.okhttp原始碼分析(二)——RetryAndFollowUpInterceptor過濾器 3.okhttp原始碼分析(三)——CacheInterceptor過濾器 4.okhttp原始碼分析(四)——Conn

spring事務管理原始碼分析配置和事務增強代理的生成流程

在本篇文章中,將會介紹如何在spring中進行事務管理,之後對其內部原理進行分析。主要涉及 @EnableTransactionManagement註解為我們做了什麼? 為什麼標註了@Transactional註解的方法就可以具有事務的特性,保持了資料的ACID特性?spring到底是如何具有這樣

Android7.1 [Camera] Camera Hal 原始碼分析

原始碼平臺:rk3399   命令列ls看下原始碼的結構 hardware/rockchip/camera/CameraHal: lib目錄 原始碼的檔案看起來有點多,我們看看Android.mk檔案, 這些檔案最終編譯成camera.rk30bo

Cat原始碼分析:Client端

前言 cat的Client端所做的工作就是收集埋點資訊,將埋點資訊處理成messageTree,放到傳送佇列中,在啟動另一個執行緒,非同步消費佇列,進行訊息的傳送。 本文涉及到三個內容: 客戶端初始化:做了哪些準備工作 message的建立過程 客戶端的傳

laravel框架原始碼分析自動載入

一、前言   使用php已有好幾年,laravel的使用也是有好長時間,但是一直對於框架原始碼的理解不深,原因很多,歸根到底還是php基礎不紮實,所以原始碼看起來也比較吃力。最近有時間,所以開啟第5、6遍的框架原始碼探索之旅,前面幾次都是看了一些就放棄,希望這次能夠看完。每一次看原始碼都會有新的收穫,因為框

github上hamsternz/FPGA_DisplayPort 的VHDL原始碼分析

原始碼來源於https://github.com/hamsternz/FPGA_DisplayPort。由於我也是第一次接觸這個介面,所以文中肯定有我理解錯誤的地方,懇請指正。要看懂程式碼首先還是要對協議有一定了解。所以我做的原始碼分析中會和協議結合起來。 激勵檔案test_source_800

vue-element-admin原始碼分析

這兩天看花褲衩大大的手摸手系列,使用vue+element+vuex+axios實現了一個後臺模板(專案地址),在閱讀原始碼的過程中收益匪淺,以下做一些筆記。(由於是學習大大專案的思想,所以略去了很多大大的程式碼)。 這裡只是做一個登陸頁面,然後能提交資料給後臺