iOS和JS的交互看似兩個(gè)問題闽寡,其實(shí)要解決的問題只有一個(gè),那就是JS如何調(diào)用native方法着绷。因?yàn)椴樵兾臋n我們就可以發(fā)現(xiàn)芭届,在UIWebView中储矩,native有直接調(diào)用JS的方法, 但是JS卻沒有直接調(diào)用native的方法。
一褂乍、native直接調(diào)用js的方法:
-(NSString*)stringByEvaluatingJavaScriptFromString
:(NSString *)script;
二持隧、JS直接調(diào)用native的方法
其實(shí),UIWebView并沒有提供JS調(diào)用native的方法逃片,但是我們卻可以通過間接的方法來實(shí)現(xiàn)這樣的操作舆蝴。總結(jié)看來题诵,間接實(shí)現(xiàn)的方式有4種:
1. 在代理方法攔截Url,識(shí)別判斷
2. Block傳值,實(shí)現(xiàn)JS調(diào)用OC
3. 模型實(shí)現(xiàn)洁仗,JS直接用oc方法名來調(diào)用oc方法
4. 使用第三方工具類:WebViewJavascriptBridge
下面就來簡(jiǎn)單介紹一下上述方法的簡(jiǎn)單實(shí)用
1.在代理方法攔截Url,識(shí)別判斷
這種方法原理很簡(jiǎn)單,UIWebView的界面響應(yīng)會(huì)調(diào)起下面的代理方法
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType;
在該方法中我們可以識(shí)別網(wǎng)頁(yè)鏈接中的特殊字段性锭,從而達(dá)到JS調(diào)起原生方法的目的
//第一步:使用本地的h5文件加載一個(gè)網(wǎng)頁(yè)
NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"testWebPage" ofType:@"html"];
NSError *error = nil;
NSString *str = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:&error];
[self.webView loadHTMLString:str baseURL:nil];
//h5文件中JS關(guān)鍵代碼如下:
<p >
<button id="chat" type="button" onclick="location.href ='http://www.testwebpage/?
funcName=printInfo:&&info=helloword'">打印信息</button>
</p>
//第二步:攔截協(xié)議
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
//獲取此時(shí)的URL
//'http://www.testwebpage/?funcName=printInfo:&&info=helloword'
NSURL *url = [request URL];
NSString *completeString = [url absoluteString];
//第一步:檢測(cè)鏈接中的特殊字段
NSString *needCheckStr = @"http://www.testwebpage/?";
NSRange jumpRange = [completeString rangeOfString:needCheckStr];
if (jumpRange.location != NSNotFound) {
/*
1.檢測(cè)到鏈接中包含有特殊字段赠潦,客戶端要接受響應(yīng)并做后續(xù)處理這就相當(dāng)于js調(diào)起了iOS,
2.在真實(shí)的使用時(shí)草冈,客戶端需要和h5協(xié)調(diào)她奥,雙方需要統(tǒng)一監(jiān)聽的字段
3.參數(shù)問題:如果此時(shí)的交互需要傳遞參數(shù)瓮增,參數(shù)也可以放在鏈接里,同樣通過識(shí)別字符串的方法來獲取
*/
//第二步:拿到鏈接字符串的后續(xù)部分哩俭,然后分割字符串得到參數(shù)數(shù)據(jù)
NSMutableString *linkmStr = [NSMutableString stringWithString:completeString];
NSRange deleteRange = {0,needCheckStr.length};
[linkmStr deleteCharactersInRange:deleteRange];
NSArray *params = [linkmStr componentsSeparatedByString:@"&&"];
//取出第一個(gè)參數(shù):與h5協(xié)商好的方法名
NSString *funcName = [params[0] componentsSeparatedByString:@"="][1];
//取出第二個(gè)參數(shù):信息字符串
NSString *info = [params[1] componentsSeparatedByString:@"="][1];
//第三步:調(diào)起iOS原生方法
SEL ocFunc = NSSelectorFromString(funcName);
if ([self respondsToSelector:ocFunc]) {
//使用編譯預(yù)處理绷跑,不顯示警告提示
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:ocFunc withObject:info];
#pragma clang diagnostic pop
}
//返回NO是為了不再執(zhí)行點(diǎn)擊原鏈接的跳轉(zhuǎn)
return NO;
}
return YES;
}
2.Block傳值,實(shí)現(xiàn)JS調(diào)用OC
這種方法需要引入頭文件
import <JavaScriptCore/JavaScriptCore.h>
具體的代碼操作如下:
JS關(guān)鍵代碼:
<p>
<button onclick="sayHello('helloword')" type="button">問候</button>
</p>
OC關(guān)鍵代碼:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//獲取JSContext對(duì)象
JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//sayHello就是js的方法名稱,使用一個(gè)block對(duì)應(yīng)賦值
__weak typeof (self) weakSelf = self;
context[@"sayHello"] = ^() {
NSArray *args = [JSContext currentArguments];
NSString *objString = [NSString stringWithFormat:@"%@",args[0]] ;
if (objString.length >0) {
//得到參數(shù)之后凡资,這里可以使用調(diào)用OC方法砸捏,即實(shí)現(xiàn)了JS對(duì)于OC的調(diào)用
[weakSelf printInfo:objString];
}
};
}
3.模型實(shí)現(xiàn),JS直接用oc方法名來調(diào)用oc方法
這種方法的優(yōu)點(diǎn)在于隙赁,JS可以直接用oc方法名來調(diào)用oc方法垦藏,這樣就類似于安卓的addJavaScriptInterface方法,在使用此方法時(shí)仍然要導(dǎo)入JavaScriptCore
//第一步:創(chuàng)建一個(gè)用與JS交互的類JSHandler繼承與NSObject
//在類中聲明一個(gè)遵守JSExport的協(xié)議伞访,并且使JSHandler實(shí)現(xiàn)這個(gè)新的協(xié)議
@protocolJSHandlerProtocol <JSExport>
//單參數(shù)方法
- (void)sayHello:(NSString*)greeting;
//多參數(shù)的方法
//由于涉及到多參數(shù)的問題掂骏,從第二個(gè)參數(shù)開始,外部參數(shù)名都要使用大寫開頭
//因?yàn)镴S調(diào)用OC方法時(shí)厚掷,是將OC方法拼接連成字符串弟灼,如果無法區(qū)分就會(huì)造成無法識(shí)別
//比如對(duì)于下面的OC方法,JS調(diào)用時(shí)
//javascript.sayHelloToWithGreeting(‘參數(shù)1’冒黑,參數(shù)2) //正確寫法
//javascript.sayHelloTowithGreeting(‘參數(shù)1’袜爪,參數(shù)2) //錯(cuò)誤寫法
- (void)sayHelloTo:(NSString*)name WithGreeting:(NSString*)greeting;
@end
@interface JSHandler : NSObject<JSHandlerProtocol>
@end
//第二步:實(shí)現(xiàn)協(xié)議方法
@implementationJSHandler:NSObject
//單參數(shù)方法
- (void)sayHello:(NSString*)greeting{
NSLog(@"%s", __func__);
NSLog(@"%@",greeting);
}
//兩個(gè)參數(shù)的方法
- (void)sayHelloTo:(NSString*)name WithGreeting:(NSString*)greeting{
NSLog(@"%s", __func__);
NSLog(@"%@,%@",name,greeting);
}
@end
//第三步:在webView所在的視圖控制中,創(chuàng)建JSContext對(duì)象薛闪,使用協(xié)議方法
JSContext*jsContext = [self.webViewvalueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSHandler*jsHandler = [JSHandlernew];
//使jsContext可以識(shí)別javascript這個(gè)類的方法
jsContext[@"javascript"] = jsHandler;
//第四步:此步驟是H5部分的操作,能夠調(diào)起OC方法的代碼如下
<p>sayHello<buttonid="opennew"type="button"onclick="javascript.sayHello('你好!')">問候1</button></p>
<p>sayHelloTo<buttonid="opennew2"type="button"onclick=
"javascript.sayHelloToWithGreeting('zhoushuai', 'Good morning!')">問候2</button></p>
4.使用第三方工具類:WebViewJavascriptBridge
還未使用過俺陋,暫時(shí)不做過多介紹
demo的github地址:
https://github.com/DreamcoffeeZS/OC-And-JS
參考鏈接:
http://www.cocoachina.com/ios/20160127/15105.html
http://www.reibang.com/p/2c7a53713e13