iOS和JS的交互看似兩個問題,其實要解決的問題只有一個,那就是JS如何調(diào)用native方法。因為查詢文檔我們就可以發(fā)現(xiàn),在UIWebView中,native有直接調(diào)用JS的方法, 但是JS卻沒有直接調(diào)用native的方法。
一、native直接調(diào)用js的方法:
-(NSString*)stringByEvaluatingJavaScriptFromString
:(NSString *)script;
二、JS直接調(diào)用native的方法
其實,UIWebView并沒有提供JS調(diào)用native的方法,但是我們卻可以通過間接的方法來實現(xiàn)這樣的操作??偨Y看來,間接實現(xiàn)的方式有4種:
1. 在代理方法攔截Url,識別判斷
2. Block傳值,實現(xiàn)JS調(diào)用OC
3. 模型實現(xiàn),JS直接用oc方法名來調(diào)用oc方法
4. 使用第三方工具類:WebViewJavascriptBridge
下面就來簡單介紹一下上述方法的簡單實用
1.在代理方法攔截Url,識別判斷
這種方法原理很簡單,UIWebView的界面響應會調(diào)起下面的代理方法
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType;
在該方法中我們可以識別網(wǎng)頁鏈接中的特殊字段,從而達到JS調(diào)起原生方法的目的
//第一步:使用本地的h5文件加載一個網(wǎng)頁
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關鍵代碼如下:
<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{
//獲取此時的URL
//'http://www.testwebpage/?funcName=printInfo:&&info=helloword'
NSURL *url = [request URL];
NSString *completeString = [url absoluteString];
//第一步:檢測鏈接中的特殊字段
NSString *needCheckStr = @"http://www.testwebpage/?";
NSRange jumpRange = [completeString rangeOfString:needCheckStr];
if (jumpRange.location != NSNotFound) {
/*
1.檢測到鏈接中包含有特殊字段,客戶端要接受響應并做后續(xù)處理這就相當于js調(diào)起了iOS,
2.在真實的使用時,客戶端需要和h5協(xié)調(diào),雙方需要統(tǒng)一監(jiān)聽的字段
3.參數(shù)問題:如果此時的交互需要傳遞參數(shù),參數(shù)也可以放在鏈接里,同樣通過識別字符串的方法來獲取
*/
//第二步:拿到鏈接字符串的后續(xù)部分,然后分割字符串得到參數(shù)數(shù)據(jù)
NSMutableString *linkmStr = [NSMutableString stringWithString:completeString];
NSRange deleteRange = {0,needCheckStr.length};
[linkmStr deleteCharactersInRange:deleteRange];
NSArray *params = [linkmStr componentsSeparatedByString:@"&&"];
//取出第一個參數(shù):與h5協(xié)商好的方法名
NSString *funcName = [params[0] componentsSeparatedByString:@"="][1];
//取出第二個參數(shù):信息字符串
NSString *info = [params[1] componentsSeparatedByString:@"="][1];
//第三步:調(diào)起iOS原生方法
SEL ocFunc = NSSelectorFromString(funcName);
if ([self respondsToSelector:ocFunc]) {
//使用編譯預處理,不顯示警告提示
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:ocFunc withObject:info];
#pragma clang diagnostic pop
}
//返回NO是為了不再執(zhí)行點擊原鏈接的跳轉
return NO;
}
return YES;
}
2.Block傳值,實現(xiàn)JS調(diào)用OC
這種方法需要引入頭文件
import <JavaScriptCore/JavaScriptCore.h>
具體的代碼操作如下:
JS關鍵代碼:
<p>
<button onclick="sayHello('helloword')" type="button">問候</button>
</p>
OC關鍵代碼:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//獲取JSContext對象
JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//sayHello就是js的方法名稱,使用一個block對應賦值
__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方法,即實現(xiàn)了JS對于OC的調(diào)用
[weakSelf printInfo:objString];
}
};
}
3.模型實現(xiàn),JS直接用oc方法名來調(diào)用oc方法
這種方法的優(yōu)點在于,JS可以直接用oc方法名來調(diào)用oc方法,這樣就類似于安卓的addJavaScriptInterface方法,在使用此方法時仍然要導入JavaScriptCore
//第一步:創(chuàng)建一個用與JS交互的類JSHandler繼承與NSObject
//在類中聲明一個遵守JSExport的協(xié)議,并且使JSHandler實現(xiàn)這個新的協(xié)議
@protocolJSHandlerProtocol <JSExport>
//單參數(shù)方法
- (void)sayHello:(NSString*)greeting;
//多參數(shù)的方法
//由于涉及到多參數(shù)的問題,從第二個參數(shù)開始,外部參數(shù)名都要使用大寫開頭
//因為JS調(diào)用OC方法時,是將OC方法拼接連成字符串,如果無法區(qū)分就會造成無法識別
//比如對于下面的OC方法,JS調(diào)用時
//javascript.sayHelloToWithGreeting(‘參數(shù)1’,參數(shù)2) //正確寫法
//javascript.sayHelloTowithGreeting(‘參數(shù)1’,參數(shù)2) //錯誤寫法
- (void)sayHelloTo:(NSString*)name WithGreeting:(NSString*)greeting;
@end
@interface JSHandler : NSObject<JSHandlerProtocol>
@end
//第二步:實現(xiàn)協(xié)議方法
@implementationJSHandler:NSObject
//單參數(shù)方法
- (void)sayHello:(NSString*)greeting{
NSLog(@"%s", __func__);
NSLog(@"%@",greeting);
}
//兩個參數(shù)的方法
- (void)sayHelloTo:(NSString*)name WithGreeting:(NSString*)greeting{
NSLog(@"%s", __func__);
NSLog(@"%@,%@",name,greeting);
}
@end
//第三步:在webView所在的視圖控制中,創(chuàng)建JSContext對象,使用協(xié)議方法
JSContext*jsContext = [self.webViewvalueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSHandler*jsHandler = [JSHandlernew];
//使jsContext可以識別javascript這個類的方法
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
還未使用過,暫時不做過多介紹
demo的github地址:
https://github.com/DreamcoffeeZS/OC-And-JS
參考鏈接:
http://www.cocoachina.com/ios/20160127/15105.html
http://www.itdecent.cn/p/2c7a53713e13