WKWebView的特点:
性能高,稳定性好,占用的内存比较小
支持JS交互
支持HTML5新特性
支持内建手势
据说高达60fps的刷新频率
KVO支持进度条
不支持iOS8之前系统
WKWebView有两个委托
WKWebView代理有两个,是WKNavigationDelegate和WKUIDelegate
创建WKWebView,加载本地HTML。
1.初始化多了个configuration参数,当然这个参数我们也可以不传,直接使用默认的设置就好。
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];
}
}