iOS與JS交互的方法:
1.攔截url(適用于UIWebView和WKWebView)?
2.JavaScriptCore(只適用于UIWebView,iOS7+)?
3.WKScriptMessageHandler(只適用于WKWebView,iOS8+)?
4.WebViewJavascriptBridge(適用于UIWebView和WKWebView,屬于第三方框架)
下面以假設的需求進行示例代碼講解,需求:?
(1)h5頁面調用原生掃二維碼(h5調用原生)?
(2)原生掃碼成功后,將結果返回給h5(原生調用h5)
(1)web調用原生:
<1>和后端同事協定好協議,如jxaction://scan表示啟動二維碼掃描,jxaction://location表示獲取定位。?
<2>實現UIWebView代理的shouldStartLoadWithRequest:navigationType:方法,在方法中對url進行攔截,如果是步奏<1>中定義好的協議則執行對應原生代碼,返回false,否則返回true繼續加載原url。
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType{
if([request.URL.absoluteStringhasPrefix:@"jxaction://scan"]) {
//調用原生掃描二維碼returnNO;? ??
}returnYES;}
h5代碼:
掃一掃(攔截url)
(2)原生調用js
若(1)中掃描二維碼結束后,需要把掃描結果返回給web頁,直接調用UIWebView的stringByEvaluatingJavaScriptFromString:方法,或者WKWebView的 evaluateJavaScript:completionHandler:方法。
[self.webViewstringByEvaluatingJavaScriptFromString:@"scanResult('我是掃描結果~')"];
方法一web調用原生只適合簡單的調用,如果要傳遞參數,雖然也可以拼接在url上,如jxaction://scan?method=aaa,但是需要我們自行對字符串進行分割解析,并且特殊字符需要編碼。在iOS7系統提供了JavaScriptCore,可以更優雅地實現js與原生的交互。?
(1)js調用原生?
<1>新建類繼承自NSObject(如AppJSObject)。?
<2>.h文件中聲明一個代理并遵循JSExport,代理內的方法和js定義的方法名一致。?
<3>.m文件中實現<2>代理中對應的方法,可以在方法內處理事件或通知代理。
AppJSObject.h
\#import\#import
@protocol
AppJSObjectDelegate
-(void)scan:(NSString*)message;
@end
@interfaceAppJSObject:NSObject
@property(nonatomic,weak)id delegate;
@end
AppJSObject.m
#import"AppJSObject.h"@implementationAppJSObject-(void)scan:(NSString*)message{? ? [self.delegatescan:message];
}
@end
h5代碼:
掃描結果://調用APP的掃描方法?
?h5->appfunctionscan(){
app.scan('scanResult');? ??
}
//掃描結果回調方法? ??
app->h5functionscanResult(result){
document.getElementById("result").innerHTML ='掃描結果:'+ result;? ? ?
?}
<4>在UIWebView加載完成的代理中把AppJSObject實例對象類注入到JS中,那么在js中調用方法就會調用到原生AppJSObject實例對象中對應的方法了。
-(void)webViewDidFinishLoad:(UIWebView *)webView{? ?
?JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];? ??
AppJSObject *jsObject = [AppJSObjectnew];? ?
?jsObject.delegate= self;? ??
context[@"app"] = jsObject;
}
代碼:https://github.com/dolacmeng/JSDemo/tree/master?
*也可以通過block實現而不創建新類AppJSObject:
context[@"openAlbum"] = ^(){
NSLog(@"js調用oc打開相冊");
};
(2)原生調用js
可以通過一中的方法,也可以通過JSContext:
JSContext *context=[_mainWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString*alertJS= [NSStringstringWithFormat:@"%@('%@')",_photoMethod,fileUrl];
[context evaluateScript:alertJS];
現在很多app都是支持iOS8+,很多人使用WKWebView代替了UIWebView,但是WKWebView并不支持方法二。此時我們可以使用WKWebView的WKScriptMessageHandler?
<1>初始化WKWebView時,調用addScriptMessageHandler:name:方法,name為js中的方法名,如scan:
- (void)setupWKWebView{? ??
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];configuration.userContentController= [[WKUserContentController alloc] init];[configuration.userContentControlleraddScriptMessageHandler:self name:@"scan"];
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frameconfiguration:configuration];
webView.UIDelegate= self;
}
h5:
window.webkit.messageHandlers.scan.postMessage()
<2>實現WKScriptMessageHandler代理方法,當js調用scan方法時,會回調此代理方法:
-(void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message{??
? if([message.name isEqualToString:@"scan"]){? ? ??
? //調用原生掃碼? ?
?}}
是一個第三方框架,官方文檔和demo都很完整,不再累贅,GitHub地址:?
https://github.com/marcuswestin/WebViewJavascriptBridge
簡書代碼格式混亂,建議看原文,我這里只是給自己留個備份
原文:https://blog.csdn.net/dolacmeng/article/details/79623708