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:
方法。
示例代碼: