自定义WKWebView显示内容(一)

avatar
奇舞团移动端团队 @奇舞团

级别:★☆☆☆☆
标签:「iOS WKWebView」「自定义WKWebView显示内容」
作者: WYW
审校: QiShare团队


笔者最近了解了部分关于自定义WKWebView的内容,在本文中将主要说明WKWebView的内容过滤规则(WKContentRuleList)及WKWebView加载相册中图片显示到WKWebView中的方式(WKURLSchemeHandler)。

WKContentRuleList make-https

WKContentRuleList是应用于Web内容的编译规则列表,适用于 iOS11.0+ 的设备。我们可以通过给webView.configuration.userContentController添加WKContentRuleList,使WebView的加载遵守相关规则。

  • WKContentRuleList的make-https可以更改http的URL为https,具有指定(非默认)端口的URL和使用其他协议的链接不受影响。

举个例子比如我们想要访问 www.so.com,但是写 URL 的时候写成了 www.so.com ,而 www.so.com 也可以正常访问,此时如果没有配置ATS的情况,如果配置了 make-https 那么应用中的WebView也能正常加载。

注意:如果我们要访问的另一个网址 www.xxx.com ,写URL的时候写成了www.xxx.com,此时如果 xxx.com 不支持 https,那么WebView就无法正常加载。这部分内容之前笔者还理解错了,后来感谢 Xs·Hdac_1033 的指正,并提供了一个验证当前访问的url 是否支持https的命令,下边的这个命令的输出结果也可以用于配置 Info.plist 文件中针对某些 URL 的 ATS 配置规则。

nscurl --ats-diagnostics URL

如:测试www.so.com

nscurl --ats-diagnostics http://so.com
Starting ATS Diagnostics

Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https://so.com.
A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error.
Use '--verbose' to view the ATS dictionaries used and to display the error received in URLSession:task:didCompleteWithError:.
================================================================================

Default ATS Secure Connection
---
ATS Default Connection
Result : PASS
---

像上边示例中只有 Result 有 Pass 的情况,使用 make-https 对 http 的 URL 配置才有用。

相关代码(编译添加RuleList相关代码在iOS 11.0+才支持):

- (void)configMakeHttps {

    // 提供ContentRule规则
     NSArray *jsonArr =
      @[@{
            @"trigger": @{
                // 匹配所有的 URL,值为正则表达式
                    @"url-filter": @".*"
            },
            @"action": @{
                // 设置类型为对 URL 做 make-https 处理
                    @"type": @"make-https"
            }
      },
      ];
   
    [self compileContentRuleWithJsonArray:jsonArr];
}
- (void)compileContentRuleWithJsonArray:(NSArray *)jsonArr {
    
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonArr options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    
    // 编译ContentRule规则
    [[WKContentRuleListStore defaultStore] compileContentRuleListForIdentifier:@"ContentBlockingRules"
                                                        encodedContentRuleList:jsonStr
                                                             completionHandler:^(WKContentRuleList *ruleList, NSError *err) {
        if (ruleList) {
            // 在 WebView 的配置中添加 RuleList
            [self.webView.configuration.userContentController addContentRuleList:ruleList];
            NSLog(@"编译的ruleList:%@", ruleList);
        } else {
            NSLog(@"编译的ruleList为空,错误信息:%@", err);
        }
    }];
}

下边的请求就会被转换为请求 www.so.com

[_webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.so.com"]]];

WKContentRuleList block

  • block的作用:停止加载资源。 如果已缓存资源,则忽略缓存。

block阻塞加载特定URL

使用 block 可以阻塞部分 URL 不能正常显示。下文中笔者阻塞加载特定的图片 URL 的效果如下:

contentRuleList1.png

关键代码如下:

- (void)configBlockURL {
    
    NSArray *jsonArr =
        @[
            @{
                @"trigger": @{
                        // 配置特定的URL 也可以通过正则匹配符合其他条件的URL
                        @"url-filter": @"(https://upload.jianshu.io/users/upload_avatars/2628633/c6a17aeb-04be-4862-9b2d-01db2a3dd16c.png)",
    
                },
                 @"action": @{
                         @"type": @"block"
                 }
             },
            // 下边字典 笔者又测试了一次make-https 把http 转为https
            @{
                  @"trigger": @{
                          @"url-filter": @".*"
                  },
                  @"action": @{
                          @"type": @"make-https"
                  }
            },
        ];
    [self compileContentRuleWithJsonArray:jsonArr];
}
[_webView loadFileURL:[[NSBundle mainBundle] URLForResource:@"QiContentRule" withExtension:@"html"] allowingReadAccessToURL:[[NSBundle mainBundle] bundleURL]];

笔者用到的QiContentRule.html内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
            <title>QiWKWebView</title>
    </head>
    <body>
        测试加载支持https的http链接的图片http://upload.jianshu.io/collections/images/1673367/8.png
        <br>
        <img src="http://upload.jianshu.io/collections/images/1673367/8.png?imageMogr2/auto-orient/strip" width="300">
            <br>
            测试block图片加载https://upload.jianshu.io/users/upload_avatars/2628633/c6a17aeb-04be-4862-9b2d-01db2a3dd16c.png
            <br>
<!--            <img src="http://p0.qhimg.com/d/QiShare/QiShare.png" width="300" height="300">-->
            <br>
            <img src="https://upload.jianshu.io/users/upload_avatars/2628633/c6a17aeb-04be-4862-9b2d-01db2a3dd16c.png" alt="测试block图片 图片加载失败" width="300" height= "300">
            <br>
    </body>
</html>

block阻塞加载某些资源

笔者使用 block 结合 if-domain(控制如果是某个域名下),resource-type(把image类型放到数组中)阻塞了简书的图片资源的访问,效果如下:

QiContentRuleList3.gif

相关代码如下:

//! 配置阻塞某些资源的加载
- (void)configBlockLoadSomeResource {
    
        NSArray *jsonArr =
      @[
    // block资源
      @{
          @"trigger": @{
                  @"url-filter": @".*",
                  // @"resource-type": @[@"image", @"style-sheet", @"font", @"script", @"document", @"media", @"popup"],
                  @"resource-type": @[@"image"],
                  // @"unless-domain": @[@"www.jianshu.com"],
                  @"if-domain": @[@"www.jianshu.com"],
          },
          @"action": @{
                  //block:Stops loading of the resource. If the resource was cached, the cache is ignored.
                  // 停止加载资源。 如果已缓存资源,则忽略缓存。
                   @"type": @"block"
          }
      }
      ];
    [self compileContentRuleWithJsonArray:jsonArr];
}
[_webView loadRequest: [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.jianshu.com/u/3db23baa08c7"]]];

更多ContentRule的规则见 Creating a Content Blocker

WKURLSchemeHandler

WKURLSchemeHandler 是用于加载自定义的 URL Schemes(非WKWebView自身本来就能处理的https等URL Scheme)资源的时候的协议。笔者做了一个通过自定义协议,加载相册中图片回显到WebView的Demo。

WKURLSchemeHandler加载相册图片回显到WKWebView

下图展示使用WKURLSchemeHandler,控制从相册中获取图片回显到WebView的img。整个过程中,我们需要设置给WKWebViewConfiguration 设置 URLSchemeHandler 处理对象及要处理的 URLScheme。这样当加载到我们要处理的 URLScheme 的时候,就会调用 WKURLSchemeHandler 的 startURLSchemeTask、stopURLSchemeTask 的代理方法。我们就可以在相应代理方法中准备、并提供相应数据内容给WebView任务,进行相应数据显示。

QiCustomResource.gif

笔者用到的相关代码如下:

- (void)loadView {

    WKWebViewConfiguration *webConfig = [WKWebViewConfiguration new];
    _schemeHandler = [QiCustomSchemeHandler new];
    [webConfig setURLSchemeHandler:_schemeHandler forURLScheme:@"qiLocal"];

    _webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webConfig];
    _webView.allowsBackForwardNavigationGestures = YES;
    _webView.backgroundColor = [UIColor whiteColor];
    self.view = _webView;
}
[_webView loadFileURL:[[NSBundle mainBundle] URLForResource:@"QiCustomResource" withExtension:@"html"] allowingReadAccessToURL:[[NSBundle mainBundle] bundleURL]];
- (void)webView:(WKWebView *)webView startURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask {
    
    if ([urlSchemeTask.request.URL.absoluteString hasPrefix:@"qilocal://"]) { // qiLocal
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageDataBlock = ^(NSData * _Nonnull data, NSURLResponse * _Nonnull response) {
                [urlSchemeTask didReceiveResponse:response];
                [urlSchemeTask didReceiveData:data];
                [urlSchemeTask didFinish];
            };
            UIImagePickerController *imagePicker = [UIImagePickerController new];
            imagePicker.delegate = self.sourceViewController;
            imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
            [self.sourceViewController showViewController:imagePicker sender:nil];
            self.imagePickerController = imagePicker;
        });
    }
}

笔者用到的 QiCustomResource.html 如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
            <title>QiWKWebView</title>
    </head>
    <body>
        <a href="qiLocal://locaResource.com" rel="external nofollow" target="_top">QiLocalCustomResource</a>
        <br>
        <img src="qiLocal://locaResource.com" alt="从手机端获取图片" width="300">
    </body>
</html>

Demo

详情见Demo:QiWKWebView

参考学习网址


了解更多iOS及相关新技术,请关注我们的公众号:

可添加如下小编微信,并备注加入QiShare技术交流群,小编会邀请你加入《QiShare技术交流群》。

小编微信

关注我们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)

推荐文章:
Swift 5.1 (6) - 函数
Swift 5.1 (5) - 控制流
Xcode11 新建工程中的SceneDelegate
iOS App启动优化(二)—— 使用“Time Profiler”工具监控App的启动耗时
iOS App启动优化(一)—— 了解App的启动流程
iOS WKWebView的基本使用
Swift 5.1 (4) - 集合类型
奇舞周刊