序言
之前有文章介紹使用 UIWebView 攔截 URL 的方式來處理 JS 與 OC 交互。iOS 下 JS 與原生 OC 互相調用(總結),但是由于UIWebVIew 比較耗內存,性能上不太好。并且蘋果在 iOS 8中推出了WKWebView。所以同樣可以使用WKWebView 來攔截 URL,做 JS 與 OC 的交互。
提醒:WKWebView 是iOS 8 推出的WebKit.framework中的控件,只有app 不需要兼容iOS 7及以下的時候才可以使用。
先看看動態效果圖
1.創建 WKWebView,加載本地 HTML 文件
WKWebView的創建有幾點不同:
- 初始化多了個
configuration
參數,這個參數我們可以不傳,直接使用默認的設置就好。 - WKWebView 的代理有兩個,
navigationDelegate
和UIDelegate
。我們要攔截 URL,就要通過navigationDelegate
的一個代理方法來實現。如果在HTML 中要使用 alert 等彈窗,就必須得實現UIDelegate
的相應代理方法。 - 在 iOS9之前,WKWebView 加載本地 HTML 會有一些問題(不能加載本地HTML,或者部分CSS/本地圖片加載不了等)
創建WKWebView的示例代碼如下:
- (void)initWKWebView {
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = [WKUserContentController new];
WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
preferences.minimumFontSize = 30.0;
configuration.preferences = preferences;
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
// load
NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:@""];
NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
[self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];
}
加載本地HTML 內容,之前有講解過,感興趣的讀者可以看看上面的連接,這里不再過多的介紹。
2.攔截 URL
使用WKNavigationDelegate
中的代理方法,攔截自定義的 URL 來實現 JS 調用 OC 方法。
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *URL = navigationAction.request.URL;
NSString *scheme = [URL scheme];
if ([scheme isEqualToString:@"haleyaction"]) {
[self handleCustomAction:URL];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
需要注意的是
1.如果實現了這個代理方法,就必須得調用
decisionHandler
這個 block,否則會導致 app 奔潰。block 參數是一個枚舉值,WKNavigationActionPolicyCancel
代表取消加載,相當于UIWebView的代理方法return NO的情況;WKNavigationActionPolicyAllow
代表允許加載,相當于UIWebView的代理方法中 return YES的情況。
關于如何區分執行不同的OC 方法,也與UIWebView的處理方式一樣,通過URL 的host 來區分執行不同的方法:
#pragma mark - dealwith custom action
- (void)handleCustomAction:(NSURL *)URL {
NSString *host = [URL host];
if ([host isEqualToString:@"shareClick"]) {
[self share:URL];
} else if ([host isEqualToString:@"getLocation"]) {
[self getLocation:URL];
} else if ([host isEqualToString:@"setBGColor"]) {
[self setBGColor:URL];
} else if ([host isEqualToString:@"payAction"]) {
[self payAction:URL];
} else if ([host isEqualToString:@"shake"]) {
[self shakeAction];
} else if ([host isEqualToString:@"back"]) {
[self goBack];
}
}
3.OC 調用 JS 方法
JS 調用OC 方法后,有的操作可能需要將結果返回給JS。這時候就是OC 調用JS 方法的場景。
WKWebView 提供了一個新的方法evaluateJavaScript:completionHandler:
,實現OC 調用JS 等場景。
- (void)getLocation:(NSURL *)URL {
// 獲取位置信息
NSLog(@"原生獲取位置信息操作");
// 將結果返回給 JS
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"廣東省廣州市白云區豪泉大廈"];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
}
evaluateJavaScript:completionHandler:
沒有返回值,JS 執行成功還是失敗會在completionHandler 中返回。所以使用這個API 就可以避免執行耗時的JS,或者alert 導致界面卡住的問題。
4.WKWebView 中使用彈窗
在上面提到,如果在WKWebView中使用alert、confirm 等彈窗,就得實現WKWebView的WKUIDelegate
中相應的代理方法。
例如,我在JS中要顯示alert 彈窗,就必須實現如下代理方法,否則alert 并不會彈出。
#pragma mark - WKUIDelegate
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
其中completionHandler
這個block 一定得調用,至于在哪里調用,倒是無所謂,我們也可以寫在方法實現的第一行,或者最后一行。
本文參考iOS下JS與OC互相調用(二)--WKWebView 攔截URL,非常感謝該作者。
更多 JS 與 OC 交互文章請看下面
iOS下 JS 與OC 互相調用(一) - UIWebView 攔截 URL
iOS下 JS 與OC 互相調用(二) - JavaScriptCore
iOS下JS與OC互相調用(四)-MessageHandler
iOS下 JS 與 OC 互相調用(五) - UIWebView+WebViewJavascriptBridge
iOS下 JS 與 OC 互相調用(六) - WKWebView+WKWebViewJavascriptBridge