使用WKWebView遇到的坑

1、UIWebView 有属性 scalespageToFit,设置为YES,可以自动对页面进行缩放以适应屏幕,WKWebView怎么做可以实现自动缩放网页比例 ?

解决办法:使用scrollView的代理

//但如果这么写了的话, 需要在dealloc中把代理置nil: _wkWebView.scrollView.delegate = nil;否则会崩溃
_wkWebView.scrollView.delegate = self;

之前有引用到WKWebview,为使用方便将WKWebview设为了成员变量,然后又设置了该成员变量的scrollview的属性的代理为当前视图控制器,然后就出现了问题,每次push时候重新创建时候总会访问之前的内存,然后报错说访问了一块已经释放掉的内存,pop出栈的时候会崩溃,这样一直找不到问题的存在,后来才知道强引用了scrollview,代理释放不掉,所以会报错,解决办法,在dealloc函数或者viewwillappear等函数中将代理设为nil就解决了

2、获取不到WKWebView的高度

获取方法:在WKWebView加载成功的代理方法里获取WKWebView的UIScrollView的contentSize

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    webViewContentHeight = _wkWebView.scrollView.contentSize.height;
}

运行后,发现获取不到contentSize, 打印结果显示(width = 0, height =0).

解决办法:使用KVO监听WKWebView的contentSize
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{ 
   if (!_wkWebView.isLoading) { 
      if([keyPath isEqualToString:@"scrollView.contentSize"])
        {
            webViewContentHeight =  _wkWebView.scrollView.contentSize.height;
            CGRect frame = _wkWebView.frame;
            frame.size.height = webViewContentHeight;
            _wkWebView.frame = frame;
            [_wkWebView sizeToFit];
        }
    }
}

也可以用JS来获取:

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    NSLog(@"%f",_webView.scrollView.contentSize.height);
    MJWeakSelf
    [_wkWebView evaluateJavaScript:@"document.body.offsetHeight;" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        //获取页面高度,并重置webview的frame
        float height = [result doubleValue];
        CGRect frame = weakSelf.wkWebView.frame;
        frame.size.height = webViewContentHeight;
        weakSelf.wkWebView.frame = frame;
        [weakSelf.wkWebView sizeToFit];
    }];
}
3、移除KVO的keypath时,程序crash
- (void)dealloc {
    [_wkWebView removeObserver:self forKeyPath:@"scrollView.contentSize" context:nil];
}

这种情况通常出现在对同一个keypath进行两次remove,如父类中有一个kvo, 父类在dealloc的时候remove一次,子类dealloc的时候又remove一次。

解决办法:用Observer中的context参数来做标记,避免跟其他的重复
[_wkWebView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"wkContext"];
- (void)dealloc {
    [_wkWebView removeObserver:self forKeyPath:@"scrollView.contentSize" context:@"wkContext"];
}
4、WKWebView 白屏问题

在 UIWebView 上当内存占用太大的时候,App Process 会 crash;而在 WKWebView 上当总体的内存占用比较大的时候,WebContent Process 会 crash,从而出现白屏现象。

解决办法:借助 WKNavigtionDelegate

当 WKWebView 总体内存占用过大,页面即将白屏的时候,系统会调用上面的回调函数,我们在该函数里执行[webView reload](这个时候 webView.URL 取值尚不为 nil)解决白屏问题。在一些高内存消耗的页面可能会频繁刷新当前页面,H5则也要做相应的适配操作。

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0)); 

但并不是所有白屏都会掉用上面方法,可以在 viewWillAppear 的时候检测 webView.title 是否为空来 reload 页面。

5、WKWebView 页面样式问题

如果H5页面有透明导航、透明导航下拉刷新、全屏等需求,而webView 是从(0, 0)开始布局,我们可以通过调整webView.scrollView.contentInset 来适配特殊导航栏需求,但这个修改就会影响webView.scrollView.contentSize.height,从而导致H5页面偏移问题。

解决办法:调整webView的布局方式,尽量不调整webView.scrollView.contentInset。如果不得不调整可以用下面方法让H5正常显示:
/**设置contentInset值后通过调整webView.frame让页面恢复正常显示 
 *参考:http://km.oa.com/articles/show/277372
 */ 
webView.scrollView.contentInset = UIEdgeInsetsMake(a, 0, 0, 0); 
webView.frame = CGRectMake(webView.frame.origin.x, webView.frame.origin.y, webView.frame.size.width, webView.frame.size.height - a); 
6、JS调用window.alert()函数引起的crash

错误信息如下:

... 
28 UIKit 0x0000000190513360 UIApplicationMain + 208 
29 Qzone 0x0000000101380570 main (main.m:181) 
30 libdyld.dylib 0x00000001895205b8 _dyld_process_info_notify_release + 36 
Completion handler passed to -[QZWebController webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:] was not called

从 crash 可以看出是 WKWebView 回调函数: runJavaScriptAlertPanelWithMessage中completionHandler 没有被调用导致的。

出现情况可能是WKWebView 退出的时候,JS刚好执行了window.alert(), alert 框可能弹不出来,completionHandler 最后没有被执行,导致 crash;另一种情况是在 WKWebView 一打开,JS就执行window.alert(),这个时候由于 WKWebView 所在的 UIViewController 出现(push或present)的动画尚未结束,alert 框可能弹不出来,completionHandler 最后没有被执行,导致 crash。

解决办法如下:

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 
{ 
    if (/*UIViewController of WKWebView has finish push or present animation*/) { 
        completionHandler(); 
        return; 
    } 
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert]; 
    [alertController addAction:[UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { completionHandler(); }]]; 
    if (/*UIViewController of WKWebView is visible*/) 
     [self presentViewController:alertController animated:YES completion:^{}]; 
    else 
        completionHandler(); 
} 
7、视频自动播放

WKWebView 需要通过WKWebViewConfiguration.mediaPlaybackRequiresUserAction设置是否允许自动播放,但一定要在 WKWebView 初始化之前设置,在 WKWebView 初始化之后设置无效。

参考:
WKWebView 使用和坑
【腾讯Bugly干货分享】WKWebView 那些坑

你可能感兴趣的:(使用WKWebView遇到的坑)