一、JS中定义的exec函数:define("cordova/exec", function(require, exports, module) 。关键实现代码如下:
1.建立command对象,并且将命令推入commandQueue
var command = [callbackId, service, action, actionArgs];
commandQueue.push(JSON.stringify(command));
2.建立不可见的iframe,并且在后续会将此iframe添加的页面
function createExecIframe() {
var iframe = document.createElement("iframe");
iframe.style.display = 'none';
document.body.appendChild(iframe);
return iframe;
}
3.将iframe的链接设置为“gap://ready”,此时网页端会发送一个请求
execIframe = execIframe || createExecIframe();
execIframe.src = "gap://ready";
二、UIWebView中拦截请求
1.CDVViewController中,实现了webview的代理方法:
- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
2.当网页端发起iframe中的请求时,请求会被此方法拦截:
if ([[url scheme] isEqualToString:@"gap"]) {
[_commandQueue fetchCommandsFromJs];
return NO;
}
当发现网页链接是gap协议的,此时通过fetchCommandsFromJs方法获取命令对象并执行,并且返回NO。实现的效果:既拦截了命令,而且页面不做变化。
2.fetchCommandsFromJs实现
(1)通过执行js脚本,获取网页端js对象commandQueue中的命令(转换为Json的字符串格式,包含服务名,方法名,以及参数列表)
NSString* queuedCommandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString:
@"cordova.require('cordova/exec').nativeFetchMessages()"];
(2)将json字符串解析,并且合成CDVInvokedUrlCommand对象
NSArray* commandBatch = [queuedCommandsJSON JSONObject];
CDVInvokedUrlCommand* command = [[CDVInvokedUrlCommand alloc] initFromJson:commandBatch];
(3)执行Command对象
//通过类名获取plugin实例
CDVPlugin* obj = [_viewController.commandDelegate getCommandInstance:command.className];
//通过方法名创建方法对象
SEL normalSelector = NSSelectorFromString(methodName);
//通过参数字符串列表创建参数列表对象
NSMutableArray* arguments = nil;
NSMutableDictionary* dict = nil;
[command legacyArguments:&arguments andDict:&dict];
//发送消息
objc_msgSend(obj, legacySelector, arguments, dict);
三、Native代码回调JS
1.在plugin的功能方法实现中,我们手动调用如下函数向js页面返回结果
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
2.在如上方法的实现中,实现如下:
NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)", callbackId, status, argumentsAsJSON, keepCallback];
[_viewController.webView stringByEvaluatingJavaScriptFromString:js];
四、总结:经上面的步骤,一个完整的交互流程就实现了。