天天看點

Cordova插件中JavaScript代碼與Java的互動細節介紹

在Cordova官網中有這麼一張架構圖:大家看右下角藍色的矩形框"Custom Plugin"——自定義插件。意思就是如果您用Cordova打包Mobile應用時,發現您的移動應用裡需要使用一些功能,這些功能用普通的JavaScript無法實作,而是需要調用移動平台的一些原生API才能實作時,我們就需要自己實作自定義插件。這些插件通過在特定的移動平台上采用原生開發實作,比如Android Studio中的Java開發,然後再通過JavaScript wrapper的方式暴露給您的Mobile應用。比如您是用Cordova在Android平台上打包生成APK檔案,那麼您的Mobile代碼(JavaScript)裡還是不會直接調用您用Java實作的Custom Plugin,而是調用Custom Plugin對應的JavaScript wrapper。

Cordova插件中JavaScript代碼與Java的互動細節介紹

那麼JavaScript wrapper本身是JavaScript代碼,它是怎麼調用到Custom Plugin的Java實作的?本文就會介紹這個細節。

下圖是OData離線存儲插件(OData Offline Store)的JavaScript實作代碼的一部分。下圖第232行會調用裝置的native API進行離線存儲的打開操作:

exec(win, error, 'OData', 'openOfflineStore', [this, options ? options : {}]);

Cordova插件中JavaScript代碼與Java的互動細節介紹
這個exec函數從哪裡來?由Cordova架構實作,通過語句 require(‘cordova/exec’)傳回。
Cordova插件中JavaScript代碼與Java的互動細節介紹

那麼當應用執行到JavaScript代碼:exec(win, error, 'OData', 'openOfflineStore', [this, options ? options : {}]); 的時候,程式流是如何從這個JavaScript的exec函數進入到Android平台的原生API執行呢?

打開PackagedApp檔案夾裡的android子檔案夾,有一個JavaScript檔案:cordova.js:

Cordova插件中JavaScript代碼與Java的互動細節介紹
裡面能看到函數exec的定義和實作:
Cordova插件中JavaScript代碼與Java的互動細節介紹
Cordova插件中JavaScript代碼與Java的互動細節介紹
進而去檢視androidExec函數的實作細節:
Cordova插件中JavaScript代碼與Java的互動細節介紹

第938行:var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);

第943行的五個參數含義:

success, fail, service, action, args

  • success & fail: JavaScript回調函數,當移動平台上的Java原生API執行完畢後,這個JavaScript回調函數會被調用到。
  • service: 待執行的Java Native API的Java實作類名稱。
  • action: 待執行的Java Native API的Java實作類的方法名稱。
  • args: JavaScript傳遞給Java native API的參數數組。

2. 在安卓平台上,JavaScript調用Java的技術實作方式有兩種:定義在下圖JavaScript代碼中的jsToNativeModes對象中:PROMPT和JS_OBJECT。相對應的,Java調用JavaScript有三種模式:POLLING, LOAD_URL和ONLINE_EVENT:

Cordova插件中JavaScript代碼與Java的互動細節介紹

看下面這段Java代碼,暴露了一個方法getSomeString給JavaScript端消費:

import android.app.Activity;

import android.os.Bundle;

import android.webkit.WebView;

public class WebViewGUI extends Activity {

    WebView mWebView;

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        mWebView = new WebView(this);

        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.addJavascriptInterface(new JavaScriptInterface(),
                "jsinterface");

        mWebView.loadUrl("file:///android_asset/www/index.html");

        setContentView(mWebView);

    }

    final class JavaScriptInterface {

        JavaScriptInterface() {
        }

        public String getSomeString() {

            return "string";

        }

    }

}           

在JavaScript代碼裡消費上述Java代碼暴露的getSomeString方法:

<script>

var String = window.jsinterface.getSomeString();

</script>           

我們再回過頭來看看AndroidExec的實作:

var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);

在AndroidExec的實作裡, nativeApiProvider的get方法傳回一個執行個體,然後執行exec方法。而881行代碼說明nativeApiProvider的實作位于檔案夾cordova/android下面的nativeapiprovider.js裡:

Cordova插件中JavaScript代碼與Java的互動細節介紹

打開nativeapiprovider.js,在第21行的注釋裡我們得到了重要資訊: currentApi要麼來自Java檔案ExposedJsApi.java,要麼來自PromptBasedNativeApi.java。

Cordova插件中JavaScript代碼與Java的互動細節介紹

Java檔案ExposedJsApi.java可以在這個檔案夾内找到:

platform/android/CordovaLib/src/org/apache/cordova

Cordova插件中JavaScript代碼與Java的互動細節介紹

ExposedJsApi實際就是個Java interface,上面聲明了一個exec方法:

Cordova插件中JavaScript代碼與Java的互動細節介紹

JavaScript到Java的執行通過prompt調用完成:

Cordova插件中JavaScript代碼與Java的互動細節介紹

Java類SystemExposedJsApi實作了這個interface,再将執行流轉交給類CordovaBridge的執行個體.

Cordova插件中JavaScript代碼與Java的互動細節介紹

CordovaBridge再調用PluginManager:

Cordova插件中JavaScript代碼與Java的互動細節介紹

PluginManager首先根據名字找到負責處理該請求的Java plugin的實作類,再調用該實作類的方法:

Cordova插件中JavaScript代碼與Java的互動細節介紹

以OData離線存儲的實作類為例,我們在其實作代碼裡能發現有大量的IF-ELSE分支,每個分支處理不同的離線存儲操作請求。

Cordova插件中JavaScript代碼與Java的互動細節介紹

要擷取更多Jerry的原創技術文章,請關注公衆号"汪子熙"或者掃描下面二維碼:

Cordova插件中JavaScript代碼與Java的互動細節介紹
Cordova插件中JavaScript代碼與Java的互動細節介紹