cordova封装了一套js和OC通信的代码,cordova.js下的iOSExex是关键的js去调原生的发起点。

function iOSExec() {

    var successCallback, failCallback, service, action, actionArgs;
var callbackId = null;
if (typeof arguments[0] !== 'string') {
// FORMAT ONE
successCallback = arguments[0];
failCallback = arguments[1];
service = arguments[2];
action = arguments[3];
actionArgs = arguments[4]; // Since we need to maintain backwards compatibility, we have to pass
// an invalid callbackId even if no callback was provided since plugins
// will be expecting it. The Cordova.exec() implementation allocates
// an invalid callbackId and passes it even if no callbacks were given.
callbackId = 'INVALID';
} else {
throw new Error('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' +
'cordova.exec(null, null, \'Service\', \'action\', [ arg1, arg2 ]);'
);
} // If actionArgs is not provided, default to an empty array
actionArgs = actionArgs || []; // Register the callbacks and add the callbackId to the positional
// arguments if given.
if (successCallback || failCallback) {
callbackId = service + cordova.callbackId++;
cordova.callbacks[callbackId] =
{success:successCallback, fail:failCallback};
} actionArgs = massageArgsJsToNative(actionArgs); var command = [callbackId, service, action, actionArgs]; // Stringify and queue the command. We stringify to command now to
// effectively clone the command arguments in case they are mutated before
// the command is executed.
commandQueue.push(JSON.stringify(command)); // If we're in the context of a stringByEvaluatingJavaScriptFromString call,
// then the queue will be flushed when it returns; no need for a poke.
// Also, if there is already a command in the queue, then we've already
// poked the native side, so there is no reason to do so again.
if (!isInContextOfEvalJs && commandQueue.length == 1) {
pokeNative();
}
}

OC里执行js很简单,就是evaluateJavaScript:js方法,执行js的地方最后都走到evalJsHelper2这里

- (void)evalJsHelper2:(NSString*)js
{
CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]);
[_viewController.webViewEngine evaluateJavaScript:js completionHandler:^(id obj, NSError* error) {
// TODO: obj can be something other than string
if ([obj isKindOfClass:[NSString class]]) {
NSString* commandsJSON = (NSString*)obj;
if ([commandsJSON length] > 0) {
CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining.");
} [_commandQueue enqueueCommandBatch:commandsJSON];
[_commandQueue executePending];
}
}];
}

可以看到就是evaluateJavaScript方法去执行一段js。

  下面具体来看一下:

 1.首先一个插件肯定在js里去调用,其实都是走exec这个方法,具体是走iOSExec(),还是androidExec(),对应各自平台。

   iOSExec在上面已经粘贴了,最下面有个pokeNative(),看方法名也猜出来是去调native端的代码

function pokeNative() {
  ...
execIframe.contentWindow.location = 'gap://ready';
   ...
}
  前面js通过创建一个iframe并发送gap://ready这个指令来告诉native开始执行操作。
  (ios在7.0以前没有提供js直接调OC的代码,所以通过下面这种方式url截取。在7.0以后版本的JavaScriptCore就可  以,http://blog.csdn.net/j_akill/article/details/44463301
  native中对应的操作在CDVUIWebViewNavigationDelegate.m(老的cordova好像再CDVViewController.m下面)文件中的webView:shouldStartLoadWithRequest:navigationType:方法
  

- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL* url = [request URL];
CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; /*
* Execute any commands queued with cordova.exec() on the JS side.
* The part of the URL after gap:// is irrelevant.
*/
if ([[url scheme] isEqualToString:@"gap"]) {
[vc.commandQueue fetchCommandsFromJs];
// The delegate is called asynchronously in this case, so we don't have to use
// flushCommandQueueWithDelayedJs (setTimeout(0)) as we do with hash changes.
[vc.commandQueue executePending];
return NO;
} /*
* Give plugins the chance to handle the url
*/
BOOL anyPluginsResponded = NO;
BOOL shouldAllowRequest = NO; for (NSString* pluginName in vc.pluginObjects) {
CDVPlugin* plugin = [vc.pluginObjects objectForKey:pluginName];
SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:");
if ([plugin respondsToSelector:selector]) {
anyPluginsResponded = YES;
shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, request, navigationType));
if (!shouldAllowRequest) {
break;
}
}
} if (anyPluginsResponded) {
return shouldAllowRequest;
} /*
* Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
*/
BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url];
if (shouldAllowNavigation) {
return YES;
} else {
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
} return NO;
}

  到这就是js调用native的过程了。

    

  

另外:

CDVAvailability.h里有个宏 
// Enable this to log all exec() calls.

#define CDV_ENABLE_EXEC_LOGGING 0

设置为1,把所有执行exec的log打出来,就看到所有执行js的地方

cordova IOS源码浅析的更多相关文章

  1. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  2. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  3. ios源码-ios游戏源码-ios源码下载

    游戏源码   一款休闲类的音乐小游戏源码 该源码实现了一款休闲类的音乐小游戏源码,该游戏的源码很简单,而且游戏的玩法也很容易学会,只要我们点击视图中的grid,就可以 人气:2943运行环境:/Xco ...

  4. EarthWarrior3D游戏ios源码

    这是一款不错的ios源码源码,EarthWarrior3D游戏源码, 并且游戏源代码支持多平台. 适用于cocos v2.1.0.0版本 源码下载:http://code.662p.com/view/ ...

  5. 非常不错的点餐系统应用ios源码完整版

    该源码是一款非常不错的点餐系统应用,应用源码齐全,运行起来非常不错,基本实现了点餐的一些常用的功能,而且界面设计地也很不错,是一个不错的ios应用学习的例子,喜欢的朋友可以下载学习看看,更多ios源码 ...

  6. Struts2源码浅析-ConfigurationProvider

    ConfigurationProvider接口 主要完成struts配置文件 加载 注册过程 ConfigurationProvider接口定义 public interface Configurat ...

  7. (转)【深入浅出jQuery】源码浅析2--奇技淫巧

    [深入浅出jQuery]源码浅析2--奇技淫巧 http://www.cnblogs.com/coco1s/p/5303041.html

  8. HashSet其实就那么一回事儿之源码浅析

    上篇文章<HashMap其实就那么一回事儿之源码浅析>介绍了hashMap,  本次将带大家看看HashSet, HashSet其实就是基于HashMap实现, 因此,熟悉了HashMap ...

  9. Android 手势识别类 ( 三 ) GestureDetector 源码浅析

    前言:上 篇介绍了提供手势绘制的视图平台GestureOverlayView,但是在视图平台上绘制出的手势,是需要存储以及在必要的利用时加载取出手势.所 以,用户绘制出的一个完整的手势是需要一定的代码 ...

随机推荐

  1. nginx 配置https upstream 跳转失败

    访问首页没问题,但是在登录跳转重定向时域名被修改成upstream的名字 如果需要跳转的话会出现下面的情况: http://test-xxx-emove_pools/beehive/index ser ...

  2. MongoDB的用户管理(6)

    注意: A)在mongodb中,有一个admin数据库, 牵涉到服务器配置层面的操作,需要先切换到admin数据. 即 use admin , -->相当于进入超级用户管理模式. B)mongo ...

  3. POJ2104 K-th Number(归并树)

    平方分割一直TLE,最后用归并树处理过了,使用STL会比较慢. #include<cstdio> #include<iostream> #include<cstdlib& ...

  4. 【转】C#中WinForm程序退出方法技巧总结

    C#中WinForm程序退出方法技巧总结 一.关闭窗体 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.Ex ...

  5. JAVA Day9

    1.StringBuffer类 优点: 内存的管理! StringBuffer: String 增强版 StringBuffer sb = new StringBuffer(); StringBuff ...

  6. Mysql创建新用户方法

    1. CREATE USER 语法: CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 例子: CREATE USER 'dog'@'lo ...

  7. openx中如何使用site-variable(参数)限制(关键词)广告显示

    openx是个很强大的广告管理系统,可以根据不同的情况显示不同的广告.其中可以根据get参数值的不同来显示,即delivery limitation中的site-variable选项,name表示变量 ...

  8. jQuery插件入门

    一:导言 有些WEB开发者,会引用一个JQuery类库,然后在网页上写一写("#"),("#"),("."),写了几年就对别人说非常熟悉JQ ...

  9. Spring注入方式及注解配置

    一:基于xml的DI(Dependency Injection) 注入类型: 定义学生Student实体类和小汽车Car实体类:进行封装和生成ToString(),并自定义属性Car Student ...

  10. 【转】安装第三方库出现 Python version 2.7 required, which was not found in the registry

    安装第三方库出现 Python version 2.7 required, which was not found in the registry 建立一个文件 register.py 内容如下. 然 ...