WKwebview 白屏問題——(WebApp/HybirdApp)

我們app從ReactNative轉H5app,在開發過程中發現一個頑固性問題。點擊H5的tabbar或者頁面之間點擊跳轉會偶現白屏問題。或者app退到後臺一段時間喚醒app會出現白屏。

白屏原因:

WKWebView是一個多進程組件,Network Loading以及UI Rendering在其它進程中執行。所以UIWebView上當內存佔用太大的時候,App Process會crash;而在WKWebView上當總體的內存佔用比較大的時候,WebContent Process會crash,從而出現白屏現象。這種一般是操作中交互點擊內存過大可能會突然白屏,然後這種你查看圖層還會看到界面UI,但是頁面就是白屏。後臺放置一段時間喚醒會白屏,這種感覺也是程序在內存中被銷燬,打開白屏。查看圖層會發現白屏的WebView的中缺少一個WKCompositingView視圖(WKWebView的渲染單元,屬於渲染進程)。目前白屏現象發現有這兩種表象。

我們處理白屏方案:

方案一:後臺放置一段時間喚醒會白屏

解決方式:退到後臺再喚醒,我們native 超過10分鐘會刷新,一是頁面數據定時更新需要刷新,二是防止內存殺死白屏。但是仍然存在偶現白屏。

方案二:判斷webView.titile

在白屏的時候,有些時候頁面 webView.titile 會被置空,所有會在viewWillAppear判斷標題爲空的重新reload頁面。

- (void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];

    self.navigationController.navigationBar.hidden = true;

    if (!self.isFirstLoad && StrIsEmpty(self.wkWebView.title)) {

        [self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:Active_Path]]];

    }

方案三:內層過大會執行webViewWebContentProcessDidTerminate進程終止方法

有些情況當日在web一直操作時會突然白屏,有的時候是因爲內容過大導致程序終止。所以採用如下方法處理

    // 此方法適用iOS9.0以上     iOS8用監聽另行處理

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0){

    NSLog(@"進程被終止");

    [self loadActiveRequestWithUrl:Active_Path];

    

}

    // 防止白屏,單web應用,後面路由切換不會加載

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    if (object == self.wkWebView && [keyPath isEqualToString:@"URL"])

    {

        NSURL *newUrl = [change objectForKey:NSKeyValueChangeNewKey];

        NSURL *oldUrl = [change objectForKey:NSKeyValueChangeOldKey];

        

        if (ObjIsNilOrNull(newUrl) && !ObjIsNilOrNull(oldUrl)) {

            [self loadActiveRequestWithUrl:Active_Path];

        }

    }

}

這三種方案基本解決了我項目裏99%的白屏,復現機率很少。但是最近還遇到過2回白屏。最近逛簡書發現還有一種方案。

補充方案:待驗證

可以遍歷WKWebView的subviews,通過是否包含WKCompositingView來判斷是否白屏。按照網絡方案,清緩存、reload和setNeedsLayout都不能解決白屏,所以只能回收舊webview(webview = nil 後記得清除代理,移除監聽,要不然會crash)創建新的 webview, 然後重新request。

// 判斷是否白屏

- (BOOL)isBlankView:(UIView*)view { // YES:blank

    ClasswkCompositingView =NSClassFromString(@"WKCompositingView");

    if ([viewisKindOfClass:[wkCompositingView class]]) {

        returnNO;

    }

    for(UIView*subViewinview.subviews) {

        if (![selfisBlankView:subView]) {

            returnNO;

        }

    }

returnYES;

}

補充方案來源簡書作者如下:
作者:zhoutq
鏈接:https://www.jianshu.com/p/de67f5a752b6
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章