我們知道cordova中js要和native通信都是通過 cordova plugin來實現的。如果我們自己創建一個cordova plugin,它其實就是幾個獨立的文件按照一定的目錄結構放在一起,然后用戶自己去手動配置plugin.xml文件(這個文件也要放在plugin中),之后我們利用cordova plugin add 命令來安裝一個plugin到對應的工程中(plugin的安裝和使用會有專門的文章來闡述)。安裝后的plugin如何和現在工程融合的呢?這就是我們這里要詳細闡述的。
1. 調用插件的流程(ionic2是用TypeScript來實現js的)
ts先利用cordova plugin里提供的接口,調用插件的js代碼,這就是流程一。在流程二里是插件js調用插件的native代碼。在流程三中,插件native接收到插件js發過來的請求(方法調用),插件native實現相應的功能后,把相應結果返回給ts。如果僅僅是這張圖,其實我們在整個過程都看不到cordova到底干了什么事情。為了讓大家更明白cordova的作用,我們在上述的流程圖里加入了cordova的部分。
這張圖很像我前面分享的mvp架構圖(http://www.cnblogs.com/StephenWu/p/5680053.html)。可以看到,我們上面的三個流程中都有cordova的身影,而且在整個流程中占有重要的地位。如果沒有cordova,也許這些流程里需要我們自己寫N多代碼才能保證一個完整的通信過程。我們將詳細的闡述每個流程中cordova是怎么樣實現的
2.流程一:ts到插件js
在ts里我們調用插件的方式是:cordova.plugins.TestPlugin.coolMethod,其中在TestPlugin.js里有coolMethod這個方法。
那這個調研是如何實現的呢?
首先我們看下 ionic2項目有cordova_plugin.js文件,該文件是當前工程里所有安裝的plugin。格式如下:
{
"id": "cordova-plugin-splashscreen.SplashScreen",
"file": "plugins/cordova-plugin-splashscreen/www/splashscreen.js",
"pluginId": "cordova-plugin-splashscreen",
"clobbers": [
"navigator.splashscreen"
]
}
對照上面我畫的流程圖,在build的時候通過handlePluginsObject 方法 把 cordova_plugin.js里的所有的plugin都加載進入 symbolList 當Native代碼加載完成后,會調用channel.join去創建所有的cordova對象,包括插件對象插件對象的創建:通過exports.mapModules,調用cordova/builder 里的assignOrWrapInDeprecateGetter ,再調用 clobber 方法,最后調用cordova/utils里的 defineGetter里方法,實現 通過調用 cordova_plugin.js里的
"clobbers": [
"cordova.plugins.TestPlugin"
]
定義的名字可以調用到對應的方法。這樣ts和js的通道就打通了。
那么接下里的問題是,plugin的js是如何調用到plugin的native代碼的呢?接着看下面的流程圖:
剛才上面知道ts中調用:cordova.plugins.TestPlugin.coolMethod到plugin 的TestPlugin.js的詳細流程。那么接下來:
調用了cordova.plugins.TestPlugin.coolMethod后,cordova.js會調用androidExec方法(不同平台都有一份cordova.js,比如iOS的就調用platforms/ios下的corodova.js里iOSExec方法)。在androidExec里會根據一定規則(pluginname + 可變得數(每次都加1))為每個調用生成一個callbackId,這個id是唯一,用於唯一標識一次調用,在native返回到js時候需要用到這個來確認這個回調是屬於哪個方法的。在androidExec方法中會調用nativeApiProvider.get().exec方法。nativeApiProvider是初始化為:
解釋為:_cordovaNative 是指 在webview里設置了webView.addJavascriptInterface(exposedJsApi, "_cordovaNative"),執行nativeApiProvider.get().exec方法后就會執行exposedJsApi.java里的相應方法; 如果沒有設置,那么就調用 platform_www/cordova-js-src/android/promptbasednativeapi.js里exec方法,該方法是執行 js的prompt方法(這個是一個常用的jsbridge里通信方法),之后就會執行WebChromClient的onJsPrompt方法。
到這里,我們已經知道了cordova是怎么從ts到插件的native代碼的。也就是流程一和二的詳細過程
下面將介紹的是cordovalib的工作原理,也就是流程三的過程。