因為工作原因,最近需要研究Cordova架構,看了其中的源碼和實作方式,當場在看的時候馬上能了解,但是事後再回去看相關源碼時候卻發現之前了解的内容又忘記了,又不得不重新開始看,是以總覺得需要記錄下來,這樣也表明之前也是學習過,俗話說「好記性不如爛筆頭 」,想必也是展現了筆記的重要性。
為何要用Cordova
什麼是Cordova
Cordova中UML類圖
Cordova實作機制
小結
随着移動網際網路的發展,現在基本是APP滿天飛,不知在大家印象中,如果我去下載下傳一個APP,那麼基本都能看到有兩種選擇,一種是Android版本,一種是IOS版本。不管我的手機是哪種作業系統,安裝完一個APP之後,後續如果有新的版本釋出的時候,我還必須去更新,才能享用新版本裡的功能,比如我裝了“京東”這個APP,前幾天正好碰到“618”活動,那麼之前一個月APP Store就提醒我要去更新最新的APP版本,以免錯過“618”活動中新的功能使用。相對來說IOS系統更新APP比起Android系統使用者體驗會好一點,但是還是稍顯麻煩點。
那麼有沒有一種方式,我隻需要開發一個APP版本,就能去适配通用的作業系統呢,不僅可以适配Android、IOS,還可以适配其他系統,比如Windows Phone、 Palm WebOS、Blackberry等等。有,Cordova就能提供這種能力,代碼寫一次,就能到處運作,跟我們日常開發網站效果一樣,基于寫Web APP,根據輸出平台要求不同,就能提供不同類型的安裝包。Cordova其設計初衷是希望使用者群體能夠通過跨平台開發的方法降低原生開發的成本,為此,開發人員需要安裝原生開發環境,配置工程,使用HTML5、CSS3、JS和原生SDK生成應用。
官網定義如下:
Apache Cordova是一個開源的移動開發架構。允許你用标準的web技術-HTML5,CSS3和JavaScript做跨平台開發。 應用在每個平台的具體執行被封裝了起來,并依靠符合标準的API綁定去通路每個裝置的功能,比如說:傳感器、資料、網絡狀态等。
使用Apache Cordova的人群:
移動應用開發者,想擴充一個應用的使用平台,而不通過每個平台的語言和工具集重新實作。
web開發者,想包裝部署自己的web App将其分發到各個應用商店門戶。
移動應用開發者,有興趣混合原生應用組建和一個WebView(一個特别的浏覽器視窗) 可以接觸裝置A級PI,或者你想開發一個原生和WebView元件之間的插件接口。
架構圖

從圖中,我們可以看到它提供了Web APP、WebView、Cordova Plugins。
Web APP
這是存放應用程式代碼的地方,展現是你的具體業務邏輯子產品。應用的實作是通過web頁面,預設的本地檔案名稱是是index.html,這個本地檔案應用CSS,JavaScript,圖檔,媒體檔案和其他運作需要的資源。應用執行在原生應用包裝的WebView中,這個原生應用是你分發到app stores中的。
WebView
Cordova啟用的WebView可以給應用提供完整使用者通路界面。在一些平台中,他也可以作為一個元件給大的、混合應用,這些應用混合和Webview和原生的應用元件。
Cordova Plugins
插件是Cordova生态系統的重要組成部分。他提供了Cordova和原生元件互相通信的接口并綁定到了标準的裝置API上,這使你能夠通過JavaScript調用原生代碼。
其實Cordova通過指令來添加項目的,但是可以選擇哪個平台去編譯,比如我們添加Android平台,在Android預設mainActivity類,我們可以看到它其實繼承CordovaActivity類,一切初始化條件是從loadUrl方法開始。
進而得到以下UML類圖
簡單分析下,CordovaActivity内依賴一個WebView類,一個Preferences類,一個CordovaInterface接口,并同時初始化一些配置資訊。WebView具體實作是由CordovaWebViewImpl類,CordovaInterface接口具體實作是由CordovaInterfaceImpl類實作。
CordovaWebViewImpl是核心類,裡面會把一些插件能力初始化,用一個PluginManager進行管理,包含一個引擎類—CordovaWebViewEngine,這個引擎是通過反射的方式建立,自身初始化的時候把NativeToJsMessageQueue關聯起來,裡面包含着以Js字元串為主的雙向連結清單,把每次從前端通過JS代碼存儲起來,然後通過綁定的橋接方式Pop出到相應的Native代碼中去。
最終實作由SystemWebViewEngine類來對Android系統中WebView控件進行二次包裝,這個類的初始化是在CordovaWebViewImpl類反射建立,相關插件和消息傳遞也是通過SystemWebViewEngine進行綁定。
當Cordova架構啟動時候,CordovaActivity類中的onCreate方法調用loadUrl方法即可啟動,最終在SystemWebViewEngine類的init方法中,會調用webView的addJavascriptInterface方法,看到這個方法是不是很熟悉,我們正常讓webView支援開啟JavaScript調用接口也是使用此特性。
那麼SystemExposedJsApi類new出來的對象就等同抛出“_cordovaNative”對象給JS端調用,進去看下SystemExposedJsApi類包含哪些内容,
其中最關鍵是exec方法,其中bridgeSecret代表選擇哪個橋接方式,service一般對應着你本地Java檔案類名,action代表java檔案中方法名,callbackId代表回調函數的Id,也就是句柄,arguments代表傳遞的參數。看出其中設計思想了沒,service往往是本地能力集的類名,比如web端想調用相機,一般起個Camera類代表這個相機服務類,然後在這個類中定義方法,也就是action參數,這個action名稱可擴充,因為方法名稱可各種各樣,适合自定義功能擴充。
SystemExposedJsApi對象初始化
在建立SystemExposedJsApi時需要CordovaBridge類,CordovaBridge類初始化需要CordovaWebView的PluginManager對象和NativeToJsMessageQueue對象。因為所有的JS端與Android native代碼互動都是通過SystemExposedJsApi對象的exec方法。在exec方法中執行PluginManager的exec方法,PluginManager去查找具體的Plugin并執行個體化然後再執行Plugin的execute方法,并根據同步辨別判斷是同步傳回給JS消息還是異步。由NativeToJsMessageQueue統一管理傳回給JS的消息。
何時加載Plugin,如何加載
Cordova中很重要的部分是插件,Cordova在啟動每個Activity的時候都會将配置檔案中的所有plugin加載到PluginManager,在第一次loadUrl方法時,就會去初始化PluginManager并加載plugin,PluginManager在加載plugin的時候并不是馬上執行個體化plugin對象,而是隻是将plugin的Class名字儲存到一個hashmap中,用service名字作為key值。當JS端通過JavascriptInterface接口的SystemExposedJsApi對象請求Android時,PluginManager會從hashmap中查找到plugin,如果該plugin還未執行個體化,利用java反射機制執行個體化該plugin,并執行plugin的execute方法。
Cordova的資料傳回
Cordova中通過exec()函數請求android插件,資料的傳回可同步也可以異步于exec()函數的請求。在開發android插件的時候可以重寫public boolean isSynch(String action)方法來決定是同步還是異步。Cordova在android端使用了一個隊列(NativeToJsMessageQueue)來專門管理傳回給JS的資料。
1,同步
Cordova在執行完exec()後,android會馬上傳回資料,但不一定就是該次請求的資料,可能是前面某次請求的資料;因為當exec()請求的插件是允許同步傳回資料的情況下,Cordova也是從NativeToJsMessageQueue隊列頭pop頭資料并傳回。然後再根據callbackID反向查找某個JS請求,并将資料傳回給該請求的success函數。
2,異步
Cordova在執行完exec()後并不會同步得到一個傳回資料。Cordova在執行exec()的同時啟動了一個XMLHttpRequest對象方式或者prompt()函數方式的循環函數來不停的去擷取NativeToJsMessageQueue隊列中的資料,并根據callbackID反向查找到相對應的JS請求,并将該資料交給success函數。
webView.sendJavascript 發送到js隊列,onNativeToJsMessageAvailable 負責執行js.
Native 調用 JS 執行方式有三種實作 LoadUrlBridgeMode、 OnlineEventsBridgeMode、PrivateApiBridgeMode
1、webView.sendJavascript 發送js方法到JS隊列
2、onJsPrompt 方法攔截,擷取調用方式
如果是gap_bridge_mode,則執行 appView.exposedJsApi.setNativeToJsBridgeMode(Integer.parseInt(message));
如果是gap_poll, 則執行 appView.exposedJsApi.retrieveJsMessages("1".equals(message));
3、調用setBridgeMode 方法調用onNativeToJsMessageAvailable 執行javascript調用
總的來說,使用Cordova架構開發優缺點很明顯。
優點:
跨平台,開發簡單,學習成本低
架構多,插件多,可自定義插件
發展最早,社群資源豐富,
缺點:
WebView性能低下時,使用者體驗差,反應慢
畢竟是老外的架構,中文文檔資源少
調試不友善,既不像原生那麼好調試,也不像純web那種調試
最後想說一句,無論是選擇原生模式開發還是Hybrid混合模式,一定是要基于具體業務場景去選擇,而不是盲目和絕對化覺得哪種模式好就不做分析想當然的去選擇,還是有選擇的結合,要知道應用之美在于藥到病除。
源于對掌握的Android開發基礎點進行整理,羅列下已經總結的文章,從中可以看到技術積累的過程。
1,Android系統簡介
2,ProGuard代碼混淆
3,講講Handler+Looper+MessageQueue關系
4,Android圖檔加載庫了解
5,談談Android運作時權限了解
6,EventBus初了解
7,Android 常見工具類
8,對于Fragment的一些了解
9,Android 四大元件之 " Activity "
10,Android 四大元件之" Service "
11,Android 四大元件之“ BroadcastReceiver "
12,Android 四大元件之" ContentProvider "
13,講講 Android 事件攔截機制
14,Android 動畫的了解
15,Android 生命周期和啟動模式
16,Android IPC 機制
17,View 的事件體系
18,View 的工作原理
19,了解 Window 和 WindowManager
20,Activity 啟動過程分析
21,Service 啟動過程分析
22,Android 性能優化
23,Android 消息機制
24,Android Bitmap相關
25,Android 線程和線程池
26,Android 中的 Drawable 和動畫
27,RecylerView 中的裝飾者模式
28,Android 觸摸事件機制
29,Android 事件機制應用
30,Cordova 架構的一些了解
31,有關 Android 插件化思考
32,開發人員必備技能——單元測試