前言
最近有朋友问我OC和JS交互的问题,我又翻开看了一下之前的代码,发现了一个对jscore理解非常方便的方法,分享给大家。这篇文章我主要讲js调用OC,OC调用js不在该范围内
JavaScriptCore做OC交互的方法
主要分为两种:
- 使用block在js代码里注入方法
- 使用JSExport协议在js代码里注入一个对象
方法一
使用Block
OC代码:
controller.m
- (void)webViewDidFinishLoad:(UIWebView *)webView {
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"testClick"] = ^(NSString * p1, NSString * p2) {
NSLog(@"p1:%@, p2:%@", p1, p2);
};
}
- 这里我在
- (void)webViewDidFinishLoad:(UIWebView *)webView
webview的加载结束代理方法中调用了JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
拿到上下文。 - 然后给JSContext上下文添加了
testClick
block,这个block有两个参数。
JS代码:
<html>
<head>
<script>
function func3Click() {
testClick("参数一", "参数二");
}
</script>
</head>
<body>
<button onclick="func3Click()">button3</button>
</body>
</html>
- 在js代码中大家可以注意到testClick
("参数一", "参数二");
对应的是OC中的context[@"
testClick"] = ^(NSStri ...
。这样就完成了js和OC的交互。
方法二
使用JSExport协议
OC代码:
JSHandler.h
@import JavaScriptCore;
@protocol JSHandlerDelegate <JSExport>
- (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2;
@end
@interface JSHandler : NSObject<JSHandlerDelegate>
@end
JSHandler.m
@implementation JSHandler
- (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2 {
NSLog(@"p1:%@, p2:%@", p1, p2);
}
@end
controller.m
- (void)webViewDidFinishLoad:(UIWebView *)webView {
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSHandler * handler = [[JSHandler alloc] init];
context[@"abchaha"] = handler;
}
我将关键代码抽离了出来
- 我创建了一个
JSHandler
类,该类有一个- (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2
的方法,用来供js调用。 - 在我的controller中有一个webview,
- (void)webViewDidFinishLoad:(UIWebView *)webView
是webview的加载结束代理方法。我该方法中通过[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
拿到方法拿到jscore的上下文变量(用来操作js)。 - 用
contextp[@"abchaha"] = handler
,来将我创建的JSContext
对象传给jscore,这样在js里就可以使用abchaha
这个变量来调用JSHandler的协议里声明的方法了。下面我们来看看JS部分的代码。
JS代码:
<html>
<head>
<script>
function func3Click() {
abchaha.twoparamWithOneTwo("参数一", "参数二");
}
</script>
</head>
<body>
<button onclick="func3Click()">button3</button>
</body>
</html>
注意这里abchaha.twoparamWithOneTwo("参数一", "参数二");
这行是关键代码。
- 大家可以看到,OC中
contextp[@"
abchaha"] = handler
的key对应了js中abchaha.twoparamWithOneTwo("参数一", "参数二");
- OC协议中的方法
- (void)
twoparamWithOne:(NSString *)p1
two:(NSString *)p2;
,对应了js中的twoparamWithOne Two("参数一", "参数二");
,在js中使用驼峰原则就可以调用到OC协议中的方法。
JavaScriptCore在干什么
上述两个方法方法一明显比方法二要简单的多,但其实不知道大家有没有发现一个规律。那就是他们都是使用documentView.webView.mainFrame.javaScriptContext
拿到了JSContext
上下文,我们可以用这个JSContext
使用[]
给他设置字段。
其实可以这样理解。下面我用js和oc对应的代码来做一下我的理解。
方法一
- 当我们的webview代理里什么都没写的时候,是这样的。
JS
OC
- 当我们在webview代理里使用
context[@"abchaha"] = handler;
设置实现JSExport
协议的类的对象时,是这样的。
JS
var abchaha = 实现JSExport的对象;
OC
id <继承JSExport的协议> abchaha = 实现JSExport的对象;
- 当我们在JS里调用
abchaha.twoparamWithOneTwo("参数一", "参数二");
的时候,是这样的。
JS
var abchaha = 实现JSExport的对象;
abchaha.twoparamWithOneTwo("参数一", "参数二");
OC
id <继承JSExport的协议> abchaha = 实现JSExport的对象;
[abchaha twoparamWithOne:@"参数一" two:@"参数二"];
方法二
-
什么都没写的时候就不展示了,就是NoCode。
-
当我们在webview代理里使用
context[@"testClick"] = ^(NSStri ...
设置Block的时候,是这样的。
JS
var testClick = (var p1){
...
}
OC
void(^ testClick)(NSString * p1, NSString * p2) = ^() {
...
};
- 当我们在JS里调用
abchaha.twoparamWithOneTwo("参数一", "参数二");
的时候,是这样的。
JS
var testClick = (var p1) {
...
}
testClick("参数一", "参数二");
OC
void(^ testClick)(NSString * p1, NSString * p2) = ^() {
...
};
testClick(@"参数一", @"参数二");
总结
其实方法一和方法二都是拿到JSContext对象以后,给它设置变量,你可以理解为在往js里写代码。
方法一是给了js一个我们声明好协议的对象,让js可以直接调用对象协议中的方法。而方法二是给js设置了一个闭包(block)让js可以回调我们的方法。
我甚至可以使用context[@"
aStr"] = @"哈哈哈";
直接给js设置一个字符串,然后在js中使用alert(
aStr);
来弹出它。
至此,我建议大家可以把JSContext
按它的本意来理解,这个JSContext就是拿到js上下文,然后给js代码通过[]
来设置变量。
网友评论