JS和Native的通信原理
图中表示的是默认的JS和Native通信的方法(采用iframe)
- 保存Cordova_plugin.js的 插件文件名字和地址。
- 插件的API呼出时,通过调用Cordova的exec模块将API的参数保存在CommandQueue的队列中。 CALLBACK则保存在JS侧的callbacks map里面。
- 添加一个空的iframe,iframe的src则指向gap://ready
- 3的iframe的src设置以后,NATIVE侧UIWebviewDelegate#shouldStartLoadWithRequest则被呼出来。
- Webview的Delegatet判断gap://ready的情况下,则执行commandDelegate的处理。
- commandDelegate则从JS侧取出API的参数,内部实现则是通过 UIWebview#stringByEvaluatingJavaScriptFromString的返回值 取得CommandQueue里面的参数转换成JSON数据。
- 根据6的插件,执行NATIVE定义的插件实例。
- 插件中,有CALLBACK的情况下,成功失败的结果通过UIWebview#stringByEvaluatingJavaScriptFromString执行JS,JS端则根据传过来的CALLBACKID,从callbacks map取出回调函数并执行。
例:camera插件呼出的时序图
JS到Natvie通信方式
从JS到Natvie的主要的通信方式有2种
- iframe的方法(默认)
该方法是添加iframe到html元素中,并设置iframe的src为指定gap://ready,触发NATIVE侧UIWebview#shouldStartLoadWithRequest的方法。插件的参数则
再从JS侧的JSON数据取过来。插件的方法执行完了为止都是同步处理。
2.xmlHttpRequest的方法(iOS5.x版本因为 -webkit-scroll的IFRAME有BUG,则推荐使用)
JS侧没有明确定义这个XHR的方法则不可使用。插件具体的参数内容则设置在了头部信息。
execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true);
execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages());
Native侧NSURLRequest的协议,根据是否为/!gap_exec来判定需要拦截。
/!gap_exec的时候,则从头部取得插件的具体参数。
通信模式切换的方法下面链接有记载
https://github.com/phonegap/phonegap/blob/master/lib/ios/guides/Changing%20the%20JavaScript%20to%20Native%20Bridge%20Mode.md
deviceready的事件处理中,执行XHR模式或者iframe模式的切换。
var exec = cordova.require('cordova/exec');
exec.setJsToNativeBridgeMode(exec.jsToNativeModes.XHR_OPTIONAL_PAYLOAD);
var exec = cordova.require('cordova/exec');
exec.setJsToNativeBridgeMode(exec.jsToNativeModes.IFRAME_NAV);
插件导入流程
Natvie侧
- APP启动,MainViewController初始化之时,queue和command的DELEGATE初期化
- config.xml文件解析,插件名设置到数组,插件文件和插件名设置到pluginMap,属性设置到setting
- 在Webview类里面,加载index.html,index.html里面加载cordova.js、开始初期化
JS侧
- 加载cordova.js时、内部的事件设置模块,NATIVE交互模块,初期化模块,插件加载
- 插件模块是cordova_plugins.js文件定义的插件文件地址,文件名保存的MAP。
- deviceready事件发布后,插件的API可以使用了。
- 插件API执行后,模块MAP将插件文件加载,执行exec函数。
- 在index.html里面添加一个空的iframe、指定src=gap://ready,通知到Nativie侧。
Cordova本体的各个组的构造图
组 | 说明 |
Staging组 | JS侧的组。平台不同,cordova.js和config.xml写法不同 |
Plugins组 | Native侧的插件组。添加的插件放在这个组 |
Classes组 | app启动的appDelegate以及MainViewController类放置的组 |
CordovaLib组 | Cordova的核心类、JS,Native之间通信、整体控制类放置的组 |
Cordova本体JS与Native通信类
JS侧:
function(全局函数,JS加载的时候被执行)
cordova(基本模块,所有的JS模块在这里面定义)
exec(JS和Native的窗口)
Channel(pub-sub定义、document/window#EventListener定义)
pluginloader(插件加载模块)
Native侧:
CDVCommandQueue(插件API队列)
CDViewController(全体控制类)
CDVCommandDelegateImpl(API控制类)
CDVPlugin(所有的插件的父类)