iOS交互一般有兩個(gè)選擇
- JavaScriptCore
- OC調(diào)用JavaScript通過(guò)webview的stringByEvaluatingJavaScriptFromString:方法調(diào)用JavaScript代碼;JavaScript調(diào)用OC,則是通過(guò)web view的代理方法shouldStartLoadWithRequest:來(lái)接收J(rèn)avaScript的網(wǎng)絡(luò)請(qǐng)求從而實(shí)現(xiàn)調(diào)用,推薦Marcus Westin的開源框架 WebViewJavascriptBridge。
在ios7之后,蘋果開放了JavaScriptCore,讓Objective-C和JavaScript代碼直接的交互變得更加的簡(jiǎn)單方便。這里就說(shuō)說(shuō)如何使用JavaScriptCore進(jìn)行交互。
iOS開發(fā)使用JavaScriptCore進(jìn)行交互有兩種方式:遵循JSExport協(xié)議,使用block。對(duì)JavaScriptCore不熟悉的看這篇挺不錯(cuò)的iOS7新JavaScriptCore框架入門介紹
先設(shè)定一個(gè)交互的使用需求背景:
假如有這樣一個(gè)需求:點(diǎn)擊網(wǎng)頁(yè)上的按鈕,調(diào)用本地代碼,然后本地代碼調(diào)用網(wǎng)頁(yè)js的方法改變按鈕樣式,點(diǎn)擊這里看動(dòng)圖展示。
oc端
導(dǎo)入JavaScriptCore
#import <JavaScriptCore/JavaScriptCore.h>JSExport方式:
繼承JSExport協(xié)議, 在協(xié)議中定義自己的方法,在需要交互的ViewController遵循此協(xié)議并實(shí)現(xiàn)協(xié)議中的方法。該協(xié)議的方法會(huì)暴露給js調(diào)用,也就是網(wǎng)頁(yè)所調(diào)用本地的方法就是協(xié)議中的方法。
下面定義一繼承至JSExport的協(xié)議,名為jsObjDelegate的協(xié)議
@protocol jsObjDelegate <JSExport>
-(void)test:(NSString *)str;
@end
創(chuàng)建一個(gè)類,包含兩個(gè)個(gè)屬性。一個(gè)是加載網(wǎng)頁(yè)的webView,另一個(gè)是js的運(yùn)行環(huán)境JSContext
@interface webViewController ()<jsObjDelegate,UIAlertViewDelegate,UIWebViewDelegate>{
UIWebView * _webView;
JSContext * _jsContext;
}
實(shí)現(xiàn)協(xié)議中的方法
-(void)test:(NSString *)str{
UIAlertView * al = [[UIAlertView alloc]initWithTitle:@"網(wǎng)頁(yè)成功調(diào)用OC!" message:str delegate:self cancelButtonTitle:@"yes" otherButtonTitles:@"no", nil];
al.tag = 3001;
[al show];
}
在viewDidLoad里面vebView加載本地html
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"two.html" withExtension:nil];
NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];
[_webView loadRequest:request];
在vebView加載完成后,獲取網(wǎng)頁(yè)的javaScriptContext屬性并保存到_jsContext中,把當(dāng)前控制器保存到網(wǎng)頁(yè)的javaScriptContext中,名為“ ctrl”,至此網(wǎng)頁(yè)用"ctrl"這個(gè)對(duì)象就能直接調(diào)用到協(xié)議中的test方法
-(void)webViewDidFinishLoad:(UIWebView *)webView{
_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//把當(dāng)前控制器保存到網(wǎng)頁(yè)中
_jsContext[@"ctrl"] = self;
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"異常信息:%@", exceptionValue);
};
}
網(wǎng)頁(yè)調(diào)用協(xié)議中暴露的test方法
ctrl.test("方式:直接調(diào)用 \n是否回調(diào)網(wǎng)頁(yè)方法")
- Block方式
block方式viewController無(wú)需實(shí)現(xiàn)jsObjDelegate協(xié)議,在加載網(wǎng)頁(yè)完成時(shí)候 向網(wǎng)頁(yè)中的javaScriptContext注入方法即可。這里注入的方法名為“test2” 。在網(wǎng)頁(yè)中JS直接調(diào)用test2就能進(jìn)入block里面調(diào)用co代碼
-(void)webViewDidFinishLoad:(UIWebView *)webView{
_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
_jsContext[@"ctrl"] = self;
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"異常信息:%@", exceptionValue);
};
WS(weakSelf);
_jsContext[@"test2"]=^(NSString * string){
// NSArray * arr = [JSContext currentArguments ];
// JSValue * value = arr[0];
// NSString * str = [value toString];
// thread = [NSThread currentThread];
UIAlertView * al = [[UIAlertView alloc]initWithTitle:@"網(wǎng)頁(yè)成功調(diào)用OC!" message:string delegate:weakSelf cancelButtonTitle:@"yes" otherButtonTitles:@"no", nil];
al.tag = 3000;
[al show];
};
}
網(wǎng)頁(yè)調(diào)用oc中注入的test2方法
test2("方式:block \n是否回調(diào)網(wǎng)頁(yè)方法")
oc調(diào)用網(wǎng)頁(yè)的方法,向js的同一個(gè)方法傳入不同的參數(shù)
-(void)callback{
JSValue * callback = _jsContext[@"showMessage"];
[callback callWithArguments:@[@"oc調(diào)用html方法 \n是否改變第一個(gè)按鈕的背景顏色",@(1)]];
}
-(void)callback2{
JSValue * callback = _jsContext[@"showMessage"];
[callback callWithArguments:@[@"oc調(diào)用html方法 \n是否改變第二個(gè)按鈕的背景顏色",@(2)]];
}
網(wǎng)頁(yè)端
這里是完整的js代碼,通過(guò)jsObjDelegate協(xié)議和block方式調(diào)用本地代碼的調(diào)用方式都在這里。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iOS與js的交互</title>
<script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
</head>
<body>
<h1>iOS與js的交互</hi><br>
<div>
<input id="btn1" type="button" value="JSExport協(xié)議調(diào)用oc代碼"/><br>
<input id="btn2" type="button" value="Block調(diào)用oc代碼"/>
</div>
<script type="text/javascript">
$(function(){
$("#btn1").bind("click", function(){
//給btn1綁定事件,ctrl是上面保存的控制器。這里直接調(diào)用 jsObjDelegate暴露出來(lái)方法
ctrl.test("方式:直接調(diào)用 \n是否回調(diào)網(wǎng)頁(yè)方法")
});
$("#btn2").bind("click",function(){
//btn2綁定事件,這里直接調(diào)用oc中以block方式注入的方法
test2("方式:block \n是否回調(diào)網(wǎng)頁(yè)方法")});
})
//根據(jù)index的值修改按鈕的樣式。oc代碼會(huì)調(diào)用該方法
function showMessage(str,index){
if(index == 1 && confirm(str)){
$("#btn1").css("background-color","red");
return;
}
if(confirm(str)){
$("#btn2").css("background-color","green");
}
}
</script>
</body>
</html>