JS 與 OC 的交互原來(lái)沒(méi)有好好研究過(guò),用的都是比較簡(jiǎn)單攔截 Url 的方式,通過(guò)定義專(zhuān)用的 Url 來(lái)攔截關(guān)鍵字來(lái)進(jìn)行特定處理。但這只能用于簡(jiǎn)單的傳值,進(jìn)行一些簡(jiǎn)單的交互。涉及到,JS 調(diào)用 OC 方法或者 OC 調(diào)用 JS 方法,一些比較復(fù)雜的交互邏輯的時(shí)候這種方式就顯得力不從心了。滿(mǎn)足不了我們的需求。當(dāng)然也有比較好的第三方庫(kù)如:WebViewJavascriptBridge。但一般系統(tǒng)的方法足夠用的時(shí)候,就沒(méi)必要使用第三方庫(kù)。這樣即有利于減小安裝包體積,又可以減少第三方的不穩(wěn)定性等因素的干擾
一、攔截url的方式,進(jìn)行簡(jiǎn)單交互
在webView的代理方法中處理
這里簡(jiǎn)單介紹一下 URL 里面的一些屬性
NSString *scheme = url.scheme;//協(xié)議:http
NSString *host = url.host;//主機(jī)名
NSNumber *port = url.port;//端口號(hào)
NSString *path = url.path;//一般用來(lái)表示主機(jī)上的一個(gè)目錄或文件地址
NSString *query = url.query;//參數(shù),發(fā)給服務(wù)器的參數(shù)
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSURL *url = request.URL;
if ([url.scheme isEqualToString:@"nanshanyi"]) {
//在這里做JavaScript調(diào)用Objective-C的事。
//需要傳的值放在url后面的參數(shù)里如:Nanshanyi://www.php8080.com?{"title":"標(biāo)題","id":"123","des":"描述內(nèi)容"}
NSString *dataJson = url.query;//拿到后面的json字符串
NSString *str = [dataJson stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@",str);
//執(zhí)行一段js代碼,彈出提示框
[webView stringByEvaluatingJavaScriptFromString:@"alert('seccess')"];
return NO;
}
return YES;
}
二、使用JavaScriptCore實(shí)現(xiàn)交互
JavaScriptCore是封裝了JavaScript和Objective-C橋接的Objective-C API,只需要較少的的代碼,就可以實(shí)現(xiàn)JavaScript與Objective-C的相互調(diào)用。
在iOS7之前,只能通過(guò)向UIWebView發(fā)送stringByEvaluatingJavaScriptFromString:消息來(lái)執(zhí)行一段JavaScript的腳本。而且如果想用JavaScript來(lái)調(diào)用Objective-C的方法,必須打開(kāi)一個(gè)自定義的URL(例如:Nanshanyi://),然后在UIWebView的delegate方法webView:shouldStartLoadWithRequest:navigationType中進(jìn)行處理。也就是上問(wèn)中提到的方法
JavaScriptCore中類(lèi)及協(xié)議:
JSContext:給JavaScript提供運(yùn)行的上下文環(huán)境
JSValue:JavaScript和Objective-C數(shù)據(jù)和方法的橋梁
JSManagedValue:管理數(shù)據(jù)和方法的類(lèi)
JSVirtualMachine:處理線程相關(guān),使用較少
JSExport:這是一個(gè)協(xié)議,如果采用協(xié)議的方法交互,自己定義的協(xié)議必須遵守此協(xié)議
(1)使用Delegate方式實(shí)現(xiàn)
先放上js的網(wǎng)頁(yè)代碼,可以建一個(gè)HTML文件直接復(fù)制進(jìn)去即可使用
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<h1>OC和JS的交互代理方式</h1>
<div>
<!-- 生成一個(gè) button 添加點(diǎn)擊事件-->
<input type="button" value="JsToOcShare" onclick="callShare()">
</div>
<script>
function callShare() {
var shareContent = JSON.stringify({"title": "分享", "desc": "分享內(nèi)容", "shareUrl": "http://www.itdecent.cn/users/774b1d5616a7/latest_articles"});
Nanshanyi.share(shareContent);
}
<!-- OC調(diào)JS-->
function showAlert(message){
alert(message);
}
<!-- JS調(diào)OC成功后回調(diào)-->
var shareCallback = function(){
alert('success');
}
</script>
</body>
</html>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol JSObjcDelegate <JSExport>
- (void)share:(NSString *)shareContent;
@end
@interface ViewController : UIViewController<JSObjcDelegate>
@end
.m文件
#import "ViewController.h"
@interface ViewController ()<UIWebViewDelegate>
@property (nonatomic,strong)UIWebView *webView;
@property (nonatomic,strong)JSContext *jsContext;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self CustomUI];
}
- (void)CustomUI{
self.webView = [[UIWebView alloc]initWithFrame:self.view.bounds];
self.webView.delegate = self;
[self.view addSubview:_webView];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"untitled3" withExtension:@"html"];
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//代理方式JS調(diào)OC方法
//Nanshanyi 相當(dāng)于橋接,通過(guò)它將 OC 與 JS 聯(lián)系起來(lái)
_jsContext[@"Nanshanyi"] = self;
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"異常信息:%@", exceptionValue);
};
}
- (void)share:(NSString *)shareContent {
NSLog(@"share:%@", shareContent);
// 分享成功后,回調(diào)js的方法shareCallback
// 也即是 OC 調(diào)用 JS 方法,只調(diào)用方法,沒(méi)有參數(shù)傳遞
JSValue *shareCallback = self.jsContext[@"shareCallback"];
[shareCallback callWithArguments:nil];
}
(2)使用Block方式實(shí)現(xiàn)
同樣放上一段簡(jiǎn)單的JS
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<h1>OC和JS的交互Block方式?</h1>
<div>
<input type="button" value="JsToOcShare" onclick="callShare(shareContent)">
</div>
<script>
var shareContent = JSON.stringify({"title":"分享", "desc":"分享內(nèi)容", "shareUrl":"http://www.itdecent.cn/users/774b1d5616a7/latest_articles"});
function callShare(share) {
//share為形參,shareContent為實(shí)參,即要傳遞的參數(shù)
}
// OC調(diào)JS message為傳遞的參數(shù)
function showAlert(message){
alert(message);
}
</script>
</body>
</html>
WebView代理方法的實(shí)現(xiàn)
- (void)showAlert{//直接調(diào)用該方法實(shí)現(xiàn)OC調(diào)用JS,并傳參
NSString *jsStr = @"showAlert('ios js交互成功,我是網(wǎng)頁(yè) alert')";
[_jsContext evaluateScript:jsStr];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//block 方式 JS直接調(diào)用OC,并傳參,簡(jiǎn)單明了
__weak typeof (self)weakSelf = self;
_jsContext[@"callShare"] =^(id obj){
weakSelf.lable.text = obj;
//把傳過(guò)來(lái)的Json字符串,轉(zhuǎn)為字典
NSData *data = [(NSString *)obj dataUsingEncoding:NSUTF8StringEncoding ];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(@"%@",dict);
};
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
//比如把js中的方法名改掉,OC找不到相應(yīng)方法,這里就會(huì)打印異常信息
NSLog(@"異常信息:%@", exceptionValue);
};
}
至此,已經(jīng)完成了JS與OC的簡(jiǎn)單交互,實(shí)現(xiàn)了JS與OC方法的相互調(diào)用,與傳值。有什么不對(duì)的請(qǐng)批評(píng)指正,互相學(xué)習(xí)