我们知道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的工作原理,也就是流程三的过程。