使用WKWebView遇到的坑

作者: 乔兰伊雪 | 来源:发表于2018-05-29 14:29 被阅读2次
    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遇到的坑

        本文链接:https://www.haomeiwen.com/subject/jdbojftx.html