淺談Cordova框架的一些理解

前言

由於工做緣由,最近須要研究Cordova框架,看了其中的源碼和實現方式,當場在看的時候立刻能理解,可是過後再回去看相關源碼時候卻發現以前理解的內容又忘記了,又不得不從新開始看,因此總以爲須要記錄下來,這樣也代表以前也是學習過,俗話說「好記性不如爛筆頭 」,想必也是體現了筆記的重要性。javascript

目錄

  • 爲什麼要用Cordovacss

  • 什麼是Cordovahtml

  • Cordova中UML類圖前端

  • Cordova實現機制html5

  • 小結java

爲什麼要用Cordova

隨着移動互聯網的發展,如今基本是APP滿天飛,不知在你們印象中,若是我去下載一個APP,那麼基本都能看到有兩種選擇,一種是Android版本,一種是IOS版本。無論個人手機是哪一種操做系統,安裝完一個APP以後,後續若是有新的版本發佈的時候,我還必須去更新,才能享用新版本里的功能,好比我裝了「京東」這個APP,前幾天正好碰到「618」活動,那麼以前一個月APP Store就提醒我要去更新最新的APP版本,以避免錯過「618」活動中新的功能使用。相對來講IOS系統更新APP比起Android系統用戶體驗會好一點,可是仍是稍顯麻煩點。android

那麼有沒有一種方式,我只須要開發一個APP版本,就能去適配通用的操做系統呢,不只能夠適配Android、IOS,還能夠適配其餘系統,好比Windows Phone、 Palm WebOS、Blackberry等等。有,Cordova就能提供這種能力,代碼寫一次,就能處處運行,跟咱們平常開發網站效果同樣,基於寫Web APP,根據輸出平臺要求不一樣,就能提供不一樣類型的安裝包。Cordova其設計初衷是但願用戶羣體可以經過跨平臺開發的方法下降原生開發的成本,爲此,開發人員須要安裝原生開發環境,配置工程,使用HTML5CSS3JS和原生SDK生成應用。css3

什麼是Cordova

官網定義以下:web

Apache Cordova是一個開源的移動開發框架。容許你用標準的web技術-HTML5,CSS3和JavaScript作跨平臺開發。 應用在每一個平臺的具體執行被封裝了起來,並依靠符合標準的API綁定去訪問每一個設備的功能,好比說:傳感器、數據、網絡狀態等。apache

使用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中UML類圖

其實Cordova經過命令來添加項目的,可是能夠選擇哪一個平臺去編譯,好比咱們添加Android平臺,在Android默認mainActivity類,咱們能夠看到它其實繼承CordovaActivity類,一切初始化條件是從loadUrl方法開始。

package com.example.hello;

import android.os.Bundle;
import org.apache.cordova.*;

public class MainActivity extends CordovaActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // enable Cordova apps to be started in the background
        Bundle extras = getIntent().getExtras();
        if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
            moveTaskToBack(true);
        }

        // Set by <content src="index.html" /> in config.xml
        loadUrl(launchUrl);
    }
}

進而獲得如下UML類圖

UML圖

簡單分析下,CordovaActivity內依賴一個WebView類,一個Preferences類,一個CordovaInterface接口,並同時初始化一些配置信息。WebView具體實現是由CordovaWebViewImpl類,CordovaInterface接口具體實現是由CordovaInterfaceImpl類實現。

CordovaWebViewImpl是核心類,裏面會把一些插件能力初始化,用一個PluginManager進行管理,包含一個引擎類—CordovaWebViewEngine,這個引擎是經過反射的方式建立,自身初始化的時候把NativeToJsMessageQueue關聯起來,裏面包含着以Js字符串爲主的雙向鏈表,把每次從前端經過JS代碼存儲起來,而後經過綁定的橋接方式Pop出到相應的Native代碼中去。

最終實現由SystemWebViewEngine類來對Android系統中WebView控件進行二次包裝,這個類的初始化是在CordovaWebViewImpl類反射建立,相關插件和消息傳遞也是經過SystemWebViewEngine進行綁定。

Cordova實現機制

當Cordova框架啓動時候,CordovaActivity類中的onCreate方法調用loadUrl方法便可啓動,最終在SystemWebViewEngine類的init方法中,會調用webView的addJavascriptInterface方法,看到這個方法是否是很熟悉,咱們常規讓webView支持開啓JavaScript調用接口也是使用此特性。

private static void exposeJsInterface(WebView webView, CordovaBridge bridge) {
        if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) {
            LOG.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old.");
            // Bug being that Java Strings do not get converted to JS strings automatically.
            // This isn't hard to work-around on the JS side, but it's easier to just
            // use the prompt bridge instead.
            return;
        }
        SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge);
        webView.addJavascriptInterface(exposedJsApi, "_cordovaNative");
    }

那麼SystemExposedJsApi類new出來的對象就等同拋出「_cordovaNative」對象給JS端調用,進去看下SystemExposedJsApi類包含哪些內容,

class SystemExposedJsApi implements ExposedJsApi {
    private final CordovaBridge bridge;

    SystemExposedJsApi(CordovaBridge bridge) {
        this.bridge = bridge;
    }

    @JavascriptInterface
    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
        return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
    }

    @JavascriptInterface
    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
        bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
    }

    @JavascriptInterface
    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
        return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
    }
}

其中最關鍵是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

一、webView.sendJavascript 發送js方法到JS隊列

二、onJsPrompt 方法攔截,獲取調用方式

  • 若是是gap_bridge_mode,則執行 appView.exposedJsApi.setNativeToJsBridgeMode(Integer.parseInt(message));
  • 若是是gap_poll, 則執行 appView.exposedJsApi.retrieveJsMessages("1".equals(message));

三、調用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,開發人員必備技能——單元測試

相關文章
相關標籤/搜索