WKWebView的特点:
性能高,稳定性好,占用的内存比较小
支持JS交互
支持HTML5新特性
支持内建手势
据说高达60fps的刷新频率
KVO支持进度条
不支持iOS8之前系统
WKWebView有两个委托
WKWebView代理有两个,是WKNavigationDelegate和WKUIDelegate
创建WKWebView,加载本地HTML。
1.初始化多了个configuration参数,当然这个参数我们也可以不传,直接使用默认的设置就好。
扫描二维码关注公众号,回复:
437666 查看本文章
2.WKWebView的代理有两个navigationDelegate和UIDelegate。我们要拦截URL,就要通过navigationDelegate的一个代理方法来实现。如果在HTML中要使用alert等弹窗,就必须得实现UIDelegate的相应代理方法。
创建WKWebView:
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; configuration.userContentController = [WKUserContentController new]; WKPreferences *preferences = [WKPreferences new]; //默认是不能通过JS自动打开窗口的,必须通过用户交互才能打开 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];
JS调用Native
#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:@"scheme"]) { NSString *host = [URL host]; if ([host isEqualToString:@"Click"]) { } decisionHandler(WKNavigationActionPolicyCancel); return; } //这句是必须加上的,不然会异常 decisionHandler(WKNavigationActionPolicyAllow); }
Native调用JS方法
JS调用OC方法后,有的操作可能需要将结果返回给JS。这时候就是OC调用JS方法的场景。
WKWebView 提供了一个新的方法evaluateJavaScript:completionHandler:,实现OC调用JS等场景。
//completionHandler 拥有两个参数,一个是返回错误,一个可以返回执行脚本后的返回值 NSString *jsStr = [NSString stringWithFormat:@"setVlaue('%@')",@"Value"]; [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { NSLog(@"%@----%@",result, error); }];
evaluateJavaScript:completionHandler:没有返回值,JS执行成功还是失败会在completionHandler中返回。所以使用这个API就可以避免执行耗时的JS,或者alert导致界面卡住的问题。
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]; }
注意:
在iOS 9之前,WKWebView加载本地HTML会有一些问题。(不能加载本地HTML,或者部分CSS/本地图片加载不了等) 当使用loadRequest来读取本地的HTML时,WKWebView是无法读取成功的,后台会出现如下的提示: Could not create a sandbox extension for / 原因是WKWebView是不允许通过loadRequest的方法来加载本地根目录的HTML文件。 而在iOS9的SDK中加入了以下方法来加载本地的HTML文件: [WKWebView loadFileURL:allowingReadAccessToURL:] 但是在iOS9以下的版本是没提供这个便利的方法的。以下为解决方案的思路,就是在iOS9以下版本时,先将本地HTML文件的数据copy到tmp目录中,然后再使用loadRequest来加载。但是如果在HTML中加入了其他资源文件,例如js,css,image等必须一同copy到temp中。
解决方法如下
//将文件copy到tmp目录 - (NSURL *)fileURLForBuggyWKWebView8:(NSURL *)fileURL { NSError *error = nil; if (!fileURL.fileURL || ![fileURL checkResourceIsReachableAndReturnError:&error]) { return nil; } // Create "/temp/www" directory NSFileManager *fileManager= [NSFileManager defaultManager]; NSURL *temDirURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:@"www"]; [fileManager createDirectoryAtURL:temDirURL withIntermediateDirectories:YES attributes:nil error:&error]; NSURL *dstURL = [temDirURL URLByAppendingPathComponent:fileURL.lastPathComponent]; // Now copy given file to the temp directory [fileManager removeItemAtURL:dstURL error:&error]; [fileManager copyItemAtURL:fileURL toURL:dstURL error:&error]; // Files in "/temp/www" load flawlesly :) return dstURL; } //调用逻辑 NSString *path = [[NSBundle mainBundle] pathForResource:@"indexoff" ofType:@"html"]; if(path){ if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) { // iOS9. One year later things are OK. NSURL *fileURL = [NSURL fileURLWithPath:path]; [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL]; } else { // iOS8. Things can be workaround-ed // Brave people can do just this // fileURL = try! pathForBuggyWKWebView8(fileURL) // webView.loadRequest(NSURLRequest(URL: fileURL)) NSURL *fileURL = [self.fileHelper fileURLForBuggyWKWebView8:[NSURL fileURLWithPath:path]]; NSURLRequest *request = [NSURLRequest requestWithURL:fileURL]; [self.webView loadRequest:request]; } }