在上篇文章中讲述了使用UIWebView拦截URL的方式来处理JS与OC交互。 因为UIWebView比较耗内存,性能上不太好,而苹果在iOS 8中推出了WKWebView。 一样的用WKWebView也能够拦截URL,作JS 与OC交互。关于WKWebView与UIWebView的对比,你们请自动百度或者google。html
打开百度网页前 | 打开百度网页后 |
---|---|
UIWebView | 内存47M |
WKWebView | 内存47M |
WKWebView 与 UIWebView 拦截URL 的处理方式基本同样。除了代理方法和WKWebView的使用不太同样,关于WKWebView更详尽的讲解和用法,仍是自行搜索学习,本文重点仍是讲解如何实现JS 与OC 互相调用。java
提醒:WKWebView 是iOS 8 推出的WebKit.framework中的控件,只有app 不须要兼容iOS 7及如下的时候才可使用。git
先看动态效果图:github
WKWebView的建立有几点不一样:web
configuration
参数,固然这个参数咱们也能够不传,直接使用默认的设置就好。navigationDelegate
和UIDelegate
。咱们要拦截URL,就要经过navigationDelegate
的一个代理方法来实现。若是在HTML中要使用alert等弹窗,就必须得实现UIDelegate
的相应代理方法。我这里建立WKWebView的示例代码是这样的:bash
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.frame configuration:configuration];
NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil];
NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
[self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];
复制代码
由于加载的本地HTML内容,跟上一篇UIWebView中介绍的HTML内容同样,因此关于HTML中的内容就再也不讲解了。app
使用WKNavigationDelegate中的代理方法,拦截自定义的URL来实现JS调用OC方法。ide
#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的状况。学习
2.其余的关于为何要统一设置scheme,在上一篇中讲过。
关于如何区分执行不一样的OC 方法,也与UIWebView的处理方式同样,经过URL 的host 来区分执行不一样的方法:
#pragma mark - private method
- (void)handleCustomAction:(NSURL *)URL
{
NSString *host = [URL host];
if ([host isEqualToString:@"scanClick"]) {
NSLog(@"扫一扫");
} else if ([host isEqualToString:@"shareClick"]) {
[self share:URL];
} else if ([host isEqualToString:@"getLocation"]) {
[self getLocation];
} else if ([host isEqualToString:@"setColor"]) {
[self changeBGColor:URL];
} else if ([host isEqualToString:@"payAction"]) {
[self payAction:URL];
} else if ([host isEqualToString:@"shake"]) {
[self shakeAction];
} else if ([host isEqualToString:@"goBack"]) {
[self goBack];
}
}
复制代码
JS 调用OC 方法后,有的操做可能须要将结果返回给JS。这时候就是OC 调用JS 方法的场景。 WKWebView 提供了一个新的方法evaluateJavaScript:completionHandler:
,实现OC 调用JS 等场景。
- (void)getLocation
{
// 获取位置信息
// 将结果返回给js
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省深圳市南山区学府路XXXX号"];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
}
复制代码
evaluateJavaScript:completionHandler:
没有返回值,JS 执行成功仍是失败会在completionHandler 中返回。因此使用这个API 就能够避免执行耗时的JS,或者alert 致使界面卡住的问题。
在上面提到,若是在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 必定得调用,至于在哪里调用,却是无所谓,咱们也能够写在方法实现的第一行,或者最后一行。
示例工程地址:JS_OC_URL