javascript
Cordova插件中JavaScript代码与Java的交互细节介绍
在Cordova官網(wǎng)中有這么一張架構(gòu)圖:大家看右下角藍(lán)色的矩形框"Custom Plugin"——自定義插件。意思就是如果您用Cordova打包Mobile應(yīng)用時(shí),發(fā)現(xiàn)您的移動應(yīng)用里需要使用一些功能,這些功能用普通的JavaScript無法實(shí)現(xiàn),而是需要調(diào)用移動平臺的一些原生API才能實(shí)現(xiàn)時(shí),我們就需要自己實(shí)現(xiàn)自定義插件。這些插件通過在特定的移動平臺上采用原生開發(fā)實(shí)現(xiàn),比如Android Studio中的Java開發(fā),然后再通過JavaScript wrapper的方式暴露給您的Mobile應(yīng)用。比如您是用Cordova在Android平臺上打包生成APK文件,那么您的Mobile代碼(JavaScript)里還是不會直接調(diào)用您用Java實(shí)現(xiàn)的Custom Plugin,而是調(diào)用Custom Plugin對應(yīng)的JavaScript wrapper。
那么JavaScript wrapper本身是JavaScript代碼,它是怎么調(diào)用到Custom Plugin的Java實(shí)現(xiàn)的?本文就會介紹這個細(xì)節(jié)。
下圖是OData離線存儲插件(OData Offline Store)的JavaScript實(shí)現(xiàn)代碼的一部分。下圖第232行會調(diào)用設(shè)備的native API進(jìn)行離線存儲的打開操作:
exec(win, error, ‘OData’, ‘openOfflineStore’, [this, options ? options : {}]);
這個exec函數(shù)從哪里來?由Cordova框架實(shí)現(xiàn),通過語句 require(‘cordova/exec’)返回。
那么當(dāng)應(yīng)用執(zhí)行到JavaScript代碼:exec(win, error, ‘OData’, ‘openOfflineStore’, [this, options ? options : {}]); 的時(shí)候,程序流是如何從這個JavaScript的exec函數(shù)進(jìn)入到Android平臺的原生API執(zhí)行呢?
打開PackagedApp文件夾里的android子文件夾,有一個JavaScript文件:cordova.js:
里面能看到函數(shù)exec的定義和實(shí)現(xiàn):
進(jìn)而去查看androidExec函數(shù)的實(shí)現(xiàn)細(xì)節(jié):
第938行:var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
第943行的五個參數(shù)含義:
success, fail, service, action, args
- success & fail: JavaScript回調(diào)函數(shù),當(dāng)移動平臺上的Java原生API執(zhí)行完畢后,這個JavaScript回調(diào)函數(shù)會被調(diào)用到。
- service: 待執(zhí)行的Java Native API的Java實(shí)現(xiàn)類名稱。
- action: 待執(zhí)行的Java Native API的Java實(shí)現(xiàn)類的方法名稱。
- args: JavaScript傳遞給Java native API的參數(shù)數(shù)組。
2. 在安卓平臺上,JavaScript調(diào)用Java的技術(shù)實(shí)現(xiàn)方式有兩種:定義在下圖JavaScript代碼中的jsToNativeModes對象中:PROMPT和JS_OBJECT。相對應(yīng)的,Java調(diào)用JavaScript有三種模式:POLLING, LOAD_URL和ONLINE_EVENT:
看下面這段Java代碼,暴露了一個方法getSomeString給JavaScript端消費(fèi):
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代碼里消費(fèi)上述Java代碼暴露的getSomeString方法:
<script>var String = window.jsinterface.getSomeString();</script>我們再回過頭來看看AndroidExec的實(shí)現(xiàn):
var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
在AndroidExec的實(shí)現(xiàn)里, nativeApiProvider的get方法返回一個實(shí)例,然后執(zhí)行exec方法。而881行代碼說明nativeApiProvider的實(shí)現(xiàn)位于文件夾cordova/android下面的nativeapiprovider.js里:
打開nativeapiprovider.js,在第21行的注釋里我們得到了重要信息: currentApi要么來自Java文件ExposedJsApi.java,要么來自PromptBasedNativeApi.java。
Java文件ExposedJsApi.java可以在這個文件夾內(nèi)找到:
platform/android/CordovaLib/src/org/apache/cordova
ExposedJsApi實(shí)際就是個Java interface,上面聲明了一個exec方法:
JavaScript到Java的執(zhí)行通過prompt調(diào)用完成:
Java類SystemExposedJsApi實(shí)現(xiàn)了這個interface,再將執(zhí)行流轉(zhuǎn)交給類CordovaBridge的實(shí)例.
CordovaBridge再調(diào)用PluginManager:
PluginManager首先根據(jù)名字找到負(fù)責(zé)處理該請求的Java plugin的實(shí)現(xiàn)類,再調(diào)用該實(shí)現(xiàn)類的方法:
以O(shè)Data離線存儲的實(shí)現(xiàn)類為例,我們在其實(shí)現(xiàn)代碼里能發(fā)現(xiàn)有大量的IF-ELSE分支,每個分支處理不同的離線存儲操作請求。
要獲取更多Jerry的原創(chuàng)技術(shù)文章,請關(guān)注公眾號"汪子熙"或者掃描下面二維碼:
總結(jié)
以上是生活随笔為你收集整理的Cordova插件中JavaScript代码与Java的交互细节介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用javap深入理解Java整型常量和
- 下一篇: cpuz如何看cpu体质