1、JS调用OC
如果是结合UIWebview来使用的话,至少有两种方式:
1)地址重定向,定义URL协议。就是将一些要调用的方法和参数拼成URL。然后再去截取解析。使用PerformSelector:方法进行回调。
在加载网页发送请求时会调用
webView:shouldStartLoadWithRequest:navigationType:
代理方法。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = [request URL];
NSString *urlStr = request.URL.absoluteString;
NSString *scheme = @"test://";
if ([urlStr hasPrefix:scheme]) {
// 1.截取方法名称
// methodName1_methodName2_?param1¶m2
NSString *temp = [urlStr substringFromIndex:scheme.length];
NSArray *subPaths = [temp componentsSeparatedByString:@"?"];
NSString *methodName = [subPaths firstObject];
methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"];
// 2.将截取出来的字符串转换为SEL
SEL selector = NSSelectorFromString(methodName);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// 3.切割所有的参数
if (subPaths.count == ) {
NSArray *parms = [[subPaths lastObject] componentsSeparatedByString:@"&"];
if (parms.count == ) {
[self performSelector:selector withObject:[parms firstObject] withObject:[parms lastObject]];
}else
{
[self performSelector:selector withObject:[subPaths lastObject]];
}
return NO;
}
#pragma clang diagnostic pop
// 3.利用performSelector调用OC方法
[self performSelector:selector withObject:nil];
return NO;
}
NSLog(@"正在请求");
return YES;
}
此段代码由于使用的performSelector系列的方法,所以对参数的个数是有限制的。如果需要传递多个参数,那么可以考虑使用NSInvocation这个类。不过在iOS7以后,我们一般就不用这种方式了,而是使用JavaScriptCore.framework框架提供的API来处理。
2)使用JavaScriptCore.framework库
使用JavaScriptCore.framework库进行JS调用OC时,使用jsContext[“js方法名”]就可以完成。因为这个jsContext[“js方法名”]后接一个block,该block中包含要执行的OC代码(block相当于一个匿名的函数,当从JS代码中触发该方法的时候,就相当于js调用了OC的方法)。
下面给出一个应用例子。我们加载一个html网页,当点击该网页中的一个按钮时,触发一段JS函数的调用,该JS函数调用在OC中注册的方法(jsContext[“js方法名”])。该网页的代码如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>百度一下,你就知道</title>
<style type="text/css">
body{
width: ;
margin: ;
padding-bottom: ;
padding-left: px;
padding-right: px;
padding-top: ;
}
#baiduimage{
margin-left: %;
margin-top: %;
}
form{
margin-left: %;
margin-top:px;
}
#text{
width: px;
height: px;
border-color:#39F;
border-style:solid;
border-width:px;
font-size:px;
}
button{
width:px;
height:px;
background-color:#39F;
font-size: px;
}
div footer{
margin-left: %;
margin-bottom: %;
margin-top: px;
margin-bottom: auto;
font-size: px;
}
</style>
<script>
function repost()
{
location.href = "test://sendMessageWithNumber_andContent_?10086&love";
}
function sum()
{
return + ;
}
function JSLoadOCMethod()
{
var str = logForTest("hello jsLoadOCMethod!");
alert(str);
}
</script>
</head>
<body>
<div class="all">
<div>
<img src="baidu.png" alt="" width="270" height="129" id="baiduimage"/>
</div>
<div>
<form>
<input name="input" type="text" id="text" value="百度一下,你就知道" maxlength="100">
<button onclick="JSLoadOCMethod();">百度一下</button>
</form>
</div>
<div>
<footer>
<span>©2016 baidu <a href="http://www.baidu.com/duty/">使用百度前必读</a> 京ICP证030173号<img width="13" height="16" data-loadfunc="1" src="copy_rignt_24.png" data-loaded="1"></span>
</footer>
</div>
</div>
</body>
</html>
加载出来的网页效果如下:

当我们点击蓝色的“百度一下”这个按钮时,会触发绑定的函数,然后在该绑定的函数中我们调用了一个
logForTest
的函数,而该函数并没有在js代码中实现,但是我们在OC代码中会通过
jsContext["logForTest"]
进行注册。之后就是触发了
jsContext["logForTest"]
所赋值的block代码块。OC的实现代码如下:
- (void)JSLoadOCMethod {
self.context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.context[@"logForTest"] = ^(){
NSLog(@"Begin Log");
NSArray *args = [JSContext currentArguments];
for (JSValue *jsVal in args) {
NSLog(@"%@", jsVal);
}
JSValue *this = [JSContext currentThis];
NSLog(@"-------End Log----%@---",this);
return @"Are you OK?";
};
}
测试的结果如下:
在这里同时将OC中block的返回值返回到了所调用的js函数里,并且显示出来。这样也就做到了JS和OC值之间的互相传递。
这里可能有一个注意点,就是
JSLoadOCMethod
方法所放的位置,如果你放在控制器的
viewDidLoad
方法中,那么不管你点多少次按钮,上面的block只会执行一次。这是因为当我们点击按钮时页面重新加载,所注册的JSContext已经失效。所以如果我们把JSContext的注册放在
viewDidLoad
方法中就无法实现JSContext的重新注册。每次重新注册都会执行,
webViewDidFinishLoad:
方法,所以我们可以将
JSLoadOCMethod
方法放在该方法中。对于我们这种情况,由用户发起触发了一个JS调用OC的方法是没有问题的,但如果你的网页在一开始加载的时候,就要触发这个JS调用OC的方法可能是不合适的,因为
webViewDidFinishLoad:
方法还没有执行。其中一个解决方法是:在该方法中触发OC调用JS函数,然后,再由JS函数调用JSContext中注册的方法。
2、OC调用JS
如果是使用UIWebView,那么可以使用它所提供的一个方法
stringByEvaluatingJavaScriptFromString:
该方法的参数是一个字符串类型的JS代码。
当然我们也可以使用JavaScriptCore.framework库提供的OC调用JS的API方法。如:
evaluateScript:
和
evaluateScript: withSourceURL:
方法。
示例代码: