在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。javascript
那麼JavaScript wrapper自己是JavaScript代碼,它是怎麼調用到Custom Plugin的Java實現的?本文就會介紹這個細節。html
下圖是OData離線存儲插件(OData Offline Store)的JavaScript實現代碼的一部分。下圖第232行會調用設備的native API進行離線存儲的打開操做:java
exec(win, error, 'OData', 'openOfflineStore', [this, options ? options : {}]);android
這個exec函數從哪裏來?由Cordova框架實現,經過語句 require(‘cordova/exec’)返回。web
那麼當應用執行到JavaScript代碼:exec(win, error, 'OData', 'openOfflineStore', [this, options ? options : {}]); 的時候,程序流是如何從這個JavaScript的exec函數進入到Android平臺的原生API執行呢?apache
打開PackagedApp文件夾裏的android子文件夾,有一個JavaScript文件:cordova.js:api
裏面能看到函數exec的定義和實現:數組
進而去查看androidExec函數的實現細節:架構
第938行:var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);app
第943行的五個參數含義:
success, fail, service, action, args
2. 在安卓平臺上,JavaScript調用Java的技術實現方式有兩種:定義在下圖JavaScript代碼中的jsToNativeModes對象中:PROMPT和JS_OBJECT。相對應的,Java調用JavaScript有三種模式:POLLING, LOAD_URL和ONLINE_EVENT:
看下面這段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裏:
打開nativeapiprovider.js,在第21行的註釋裏咱們獲得了重要信息: currentApi要麼來自Java文件ExposedJsApi.java,要麼來自PromptBasedNativeApi.java。
Java文件ExposedJsApi.java能夠在這個文件夾內找到:
platform/android/CordovaLib/src/org/apache/cordova
ExposedJsApi實際就是個Java interface,上面聲明瞭一個exec方法:
JavaScript到Java的執行經過prompt調用完成:
Java類SystemExposedJsApi實現了這個interface,再將執行流轉交給類CordovaBridge的實例.
CordovaBridge再調用PluginManager:
PluginManager首先根據名字找到負責處理該請求的Java plugin的實現類,再調用該實現類的方法:
以OData離線存儲的實現類爲例,咱們在其實現代碼裏能發現有大量的IF-ELSE分支,每一個分支處理不一樣的離線存儲操做請求。
要獲取更多Jerry的原創技術文章,請關注公衆號"汪子熙"或者掃描下面二維碼: