前段时间作app活动,发现与JS交互方面有些混乱,为了梳理交互操做,又从新看了一遍原生与JS交互方面的东西javascript
同时找到了下面参考文档中的深刻浅出和全面解析写的还不错,多余的就不赘述了,本身总结一下,不想看的看官门能够跳过【我的总结】这一部分html
首先要声明获取JSContext对象,有下面三个方式,三选一java
- (void)webViewDidFinishLoad:(UIWebView *)webView { // 1.这种方式须要传入一个JSVirtualMachine对象,若是传nil,会致使应用崩溃的。 JSVirtualMachine *JSVM = [[JSVirtualMachine alloc] init]; JSContext *JSCtx = [[JSContext alloc] initWithVirtualMachine:JSVM]; // 2.这种方式,内部会自动建立一个JSVirtualMachine对象,能够经过 JSCtx.virtualMachine // 看其是否建立了一个JSVirtualMachine对象。 JSContext *JSCtx = [[JSContext alloc] init]; // 3. 经过webView的获取JSContext。 JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; }
JSContext对象对应一个全局对象(global object)。例如web浏览器中的JSContext,起全局对象就是window对象。全局变量是全局对象的属性,能够经过JSValue对象或者context下标的方式来访问。ios
因此感受用方法3,去获取而不是建立更好一些。web
JavaScript 与 Objective-C 交互主要经过2种方式:浏览器
block方式:使用block将响应方法暴露给JavaScript,从而完成Objective-C的一些操做markdown
JSExport 协议:经过继承JSExport协议的方式来导出指定的方法和属性,能够将OC的中某个对象直接暴露给JS使用,并且在JS中使用就像调用JS的对象同样天然。并发
OC变量 <---> JS变量app
//执行的JS操做 为a赋值 JSValue *value = [context evaluateScript:@"var a = 1+2*3;"]; //获取a的值的三种方法 NSLog(@"a = %@", [context objectForKeyedSubscript:@"a"]);//经过context的实力方法objectForKeyedSubscript NSLog(@"a = %@", [context.globalObject objectForKeyedSubscript:@"a"]);//经过context.globalObject的ObjectForKeyedSubscript实例方法 NSLog(@"a = %@", context[@"a"]); //经过下标 //输出结果Output: a = 7 a = 7 a = 7
JS方法 ---> OC方法 async
JS方法
//点击调用shareClick方法 <input type="button" value="分享" onclick="shareClick()" /> //shareClick方法 function shareClick() { //调用原生share方法 //调用方法不带参数 share(); //调用方法带参数 share('测试分享的标题','测试分享的内容','url=http://www.baidu.com'); }
OC方法
- (void)addShareWithContext:(JSContext *)context { context[@"share"] = ^() { //从JavaScript代码传过来的参数 NSArray *args = [JSContext currentArguments]; //参数的一些处理 if (args.count < 3) { return ; } NSString *title = [args[0] toString]; NSString *content = [args[1] toString]; NSString *url = [args[2] toString];
// 在这里执行分享的操做
}; }
OC方法 ---> JS方法
JS代码
function shareResult(channel_id,share_channel,share_url) { //拼接数据 var content = channel_id+","+share_channel+","+share_url; asyncAlert(content); //修改当前returnValue的值 document.getElementById("returnValue").value = content; }
OC代码
- (void)addShareWithContext:(JSContext *)context { context[@"share"] = ^() { NSArray *args = [JSContext currentArguments]; if (args.count < 3) { return ; } NSString *title = [args[0] toString]; NSString *content = [args[1] toString]; NSString *url = [args[2] toString]; // 在这里执行分享的操做 // 将分享结果返回给js NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; [[JSContext currentContext] evaluateScript:jsStr]; }; }
这样的话也完成了JS的回调,既调用JS中的方法处理返回值
简单的说就是写一个继承JSExport的协议,写一个类遵循该协议,将这个类做为一个变量交给JavaScriptCore。这样JavaScriptCore会自动认定继承JSExport这个类的协议为要导入到JavaScript的方法和属性列表,从而进行导入。
代码1显示了协议中的变量,方法和类方法。代码2显示了对应的JavaScript中调用的方法
代码1
@protocol MyPointExports <JSExport> //对于每一个导出的Objective-C属性,JavaScriptCore都会在原型上建立JavaScript访问器属性。 @property double x; @property double y; //对于每一个导出的实例方法,JavaScriptCore都会建立一个相应的JavaScript函数做为原型对象的属性。 - (NSString *)description; - (instancetype)initWithX:(double)x y:(double)y; //对于每一个导出的类方法,JavaScriptCore在构造函数对象上建立一个JavaScript函数 + (MyPoint *)makePointWithX:(double)x y:(double)y; @end
代码2
// Objective-C properties become fields. point.x; point.x = 10; // Objective-C instance methods become functions. point.description(); // Objective-C initializers can be called with constructor syntax. var p = MyPoint(1, 2); // Objective-C class methods become functions on the constructor object. var q = MyPoint.makePointWithXY(0, 0);
其中MyPoint为遵循MyPointExports的类
你可能注意到了,后两个方法参数写法上彷佛有些变化。
如上面英文提到的,初始化方法能够用构造函数方法调用
而多参数问题,导入到JavaScript时由这么一个规则
例如:OC中为 doFoo:withBar:
JavaScript中为 doFooWithBar
很差记? 苹果又贴心的给了一个宏来指定导出到Javascript的方法名
@protocol MyClassJavaScriptMethods <JSExport> JSExportAs(doFoo, - (void)doFoo:(id)foo withBar:(id)bar ); @end
到此,用法方面就结束了
其实若是你看了下面的参考文档,你就会以为他们确实写的很全面,我再写这一篇的时候也这么以为,一样也犹豫过,在很显然不如别人写的好的状况下要不要在写下去。
后来想清了一个问题,虽然说不要重复造轮子,可是不会造轮子的话,永远只能当组装师搬运工,学会造轮子以后才能成为创造者。一千个读者就有一千个哈姆雷特,或许你的切入点、视角更好呢,就算不是完美,至少你走过了这一步,也印象更深入了些。虽然不完美,但仍是写完了,但愿可以对你有所帮助。
PS:若是你看了官方文档,会发现,大多数信息源仍是官方文档~~~