记录WKWebView坑: 神奇的中国移动

最近遇到这么一件事儿,网页在个别中国移动4G网络下,访问白屏

环境:iOS 14 部分移动4G网络
问题: WKWebView, 回调commitNavigation 之后,一直在等待,didFinish一直执行不到。
经过测试,定位到 script位置,script使用了一个并不存在的网络地址,放到wkWebview中就导致了页面一直在加载,但是加载不出来,直到网页超时(一般30-60秒)
html代码如下(伪代码)

测试发现,就算在iphone的safari中,直接访问一个不存在地址,safari地址栏下的进度条会一直在读条,持续进5分钟才会提示无法链接。

为了解决这个问题

其实这个是中国移动的问题,他通过dns没找到,那就报错呗,他就不,任性
提出了几种方案

  1. 拦截h5页面,提前处理掉有问题的h5
  2. 拦截相关请求,直接返回失败。
  3. H5改
  • 方案1: 失败!
    在webView request的之前,通过AFNetWorking直接请求H5的text,然后替换文字,替换后直接使用
[aWebView loadHTMLString:@"替换后的htmlString" baseURL: baseURL];

但是问题出现了:因为变成了本地的string,因此html里面一些相对地址的资源文件都丢失了,如 图片、css、js等等。
如果都转成本地,那么代价就太大了

因此这边想了一个办法,拦截相关的请求

*方案2:
wkWebView提供了WKURLSchemeHandler供我们拦截请求,但不允许拦截http https ftp等,但是可以通过Category 重写系统方法来实现,具体做法百度知道。

也发生了个bug,百度提的不多,就是拦截的请求回丢失body,导致其他的相关请求都失败了! 失败的代码如下:

if ([urlSchemeTask.request.URL.absoluteString isEqualToString:@"https://some.host.com/www/cordova.js"] || [urlSchemeTask.request.URL.absoluteString isEqualToString:@"https://some.host.com/www/js/index.js"]) {
        NSError * error = [NSError errorWithDomain:NSURLErrorDomain code:404 userInfo:@{NSLocalizedDescriptionKey: @"request unsupportted js content"}];
        [urlSchemeTask didFailWithError:error];
    }

解决问题的方法也很简单,就是使用AF,直接请求网页数据,通过WKURLSchemeHandler提供的代理方法传递给webView,做法与拦截自定义sheme后,加载本地资源的过程如出一辙,代码如下:

if ([urlSchemeTask.request.URL.absoluteString isEqualToString:@"https://some.host.com/www/cordova.js"] || [urlSchemeTask.request.URL.absoluteString isEqualToString:@"https://some.host.com/www/js/index.js"]) {
        NSError * error = [NSError errorWithDomain:NSURLErrorDomain code:404 userInfo:@{NSLocalizedDescriptionKey: @"request unsupportted js content"}];
        [urlSchemeTask didFailWithError:error];
    } else {
        
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlSchemeTask.request.URL];

         AFURLSessionManager * manager = [[AFURLSessionManager alloc]initWithSessionConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration];
         
         manager.responseSerializer = [AFHTTPResponseSerializer serializer];
         
        NSURLSessionDataTask * task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
            
            NSData * data = (NSData *)responseObject;
            [urlSchemeTask didReceiveResponse:response];
            [urlSchemeTask didReceiveData:data];
            [urlSchemeTask didFinish];
         }];
         [task resume];
    }
  • 方案3: 最好了,我就不说了。

其实,还是建议直接使用第三种方式,这才是从源头上解决问题,方案2虽然可行,但一方面,私有api,上线困难,并且,为了一小撮,结果把所有的https拦截了,简直就是丧心病狂!

你可能感兴趣的:(记录WKWebView坑: 神奇的中国移动)