WKUIWebView(Javascript) 原理

WKWebView的特点:

性能高,稳定性好,占用的内存比较小

支持JS交互

支持HTML5新特性

支持内建手势

据说高达60fps的刷新频率

KVO支持进度条

不支持iOS8之前系统

WKWebView有两个委托

WKWebView代理有两个,是WKNavigationDelegateWKUIDelegate


创建WKWebView,加载本地HTML


1.初始化多了个configuration参数,当然这个参数我们也可以不传,直接使用默认的设置就好。

扫描二维码关注公众号,回复: 437666 查看本文章

2.WKWebView的代理有两个navigationDelegateUIDelegate。我们要拦截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中使用alertconfirm等弹窗,就得实现WKWebViewWKUIDelegate中相应的代理方法。

例如,我在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];
    }
}






猜你喜欢

转载自blog.csdn.net/shubinniu/article/details/53097009
今日推荐