WKWebView通過監(jiān)聽ContentSize更新WebView的Frame導(dǎo)致Height持續(xù)增長的bug解決方案(編輯于20180813)

問題描述

最近眼紅WKWebView相對UIWebView的高可配置和高效屯援。在最近的代碼中選擇使用WKWebView來加載JS動態(tài)頁面司倚。但是需要把WebView嵌入到另一個(gè)ScrollView中顯示谎砾,所以需要拉伸到內(nèi)容長度且不能被用戶拖動蕊退。原始代碼如下:

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    [webView evaluateJavaScript:@"document.body.scrollHeight" completionHandler:^(NSNumber *height, NSError * _Nullable error) {
        float htmlHeight =[height floatValue];
        CGRect webFrame = webView.frame;
        webFrame.size.height = htmlHeight;
        webView.frame = webFrame;
        [self addFeedBackBtn];
    }];
}

通過JS代碼得到頁面的高度坪它。
但是這樣的方法對于非靜態(tài)頁面無效营曼,高度并非正確的高度昔案。

解決辦法


編輯于20180813
下面的分割線后是最初始的解決辦法尿贫,但是在部分極端情況下還有用戶反應(yīng)會出現(xiàn)高度持續(xù)增長的問題。
最終找到的原因WKWebViewframe寬度帶有小數(shù)踏揣,而不是整數(shù)庆亡。猜測WKWebView在計(jì)算contentSize的時(shí)候是依照frame.width向下取整的寬度來計(jì)算最終的contentSizeheight的,然后導(dǎo)致KVO觀察的contentSize高度在更新frame高度后持續(xù)增加捞稿。
更新的解決辦法是對WKWebView的frame寬度求整又谋。

代碼如下_webView.frame = CGRectMake(HWFrame_IPhonePadX(20, 30), height, (NSInteger)(ScreenWidth - HWFrame_IPhonePadX(60, 80)), 0);

BTW. 之所以我們的WKWebViewframe寬度會帶小數(shù)是因?yàn)槲覀兊?code>HWFrame_IPhonePadX宏會自適應(yīng)屏幕寬高生成輸入數(shù)值對應(yīng)的實(shí)際顯示數(shù)值(這個(gè)數(shù)字是比例計(jì)算而來娱局,會帶有小數(shù)位)彰亥。所以就尷尬了,產(chǎn)生了WKWebView高度持續(xù)增加的bug衰齐。


初始解決方案
為了監(jiān)控JS動態(tài)頁面的當(dāng)前高度任斋,選擇使用KVO監(jiān)聽WKWebView.scrollView的contentSize變化。在收到變化通知是耻涛,通過當(dāng)前的contentSize更新webView的frame废酷。代碼如下:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if (object == _webView.scrollView && [keyPath isEqualToString:@"contentSize"]) {
        NSLog(@"_webView.scrollView.contentSize %f %f", self.webView.scrollView.contentSize.width, self.webView.scrollView.contentSize.height);
        CGRect webFrame = self.webView.frame;
        webFrame.size.height = self.webView.scrollView.contentSize.height;
        self.webView.frame = webFrame;
    }
}

該方法可以基本解決訪問動態(tài)頁面,實(shí)時(shí)更新頁面高度的問題抹缕。

使用KVO記得移除Observer澈蟆,同時(shí)避免過度移除的crash。可以使用下方代碼解決

- (void)removeWebViewObserver {
    @try {
        if (_webView) {
            [_webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
        }
    }
    @catch (NSException *exception) {
        NSLog(@"多次刪除kvo 報(bào)錯了");
    }
}

偶發(fā)問題

上方方法小概率下會出現(xiàn)監(jiān)聽持續(xù)被觸發(fā)卓研,contentSize.height持續(xù)不斷增加趴俘,從而使得設(shè)置的frame的高度也在不斷增加,無限循環(huán)增高鉴分。
我當(dāng)時(shí)工程內(nèi)的表現(xiàn)為高度每次加一哮幢。

解決方案一

通過

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if (object == _webView.scrollView && [keyPath isEqualToString:@"contentSize"]) {
        NSLog(@"_webView.scrollView.contentSize %f %f", self.webView.scrollView.contentSize.width, self.webView.scrollView.contentSize.height);
        CGRect webFrame = self.webView.frame;
        webFrame.size.height = self.webView.scrollView.contentSize.height - 1;    // 每次減一可以結(jié)局死循環(huán),持續(xù)增加高度志珍。
        self.webView.frame = webFrame;
    }
}

該辦法可以解決持續(xù)增加高度的問題橙垢。但是沒有找到根本原因,無法確定所有頁面都是每次加一伦糯,還是有其他可能的情況柜某。所以該方法放棄嗽元。

解決方案二

把WKWebView更換為UIWebView,同樣也通過監(jiān)聽contentSize來動態(tài)更新webView高度喂击,沒有出現(xiàn)上方的偶發(fā)問題剂癌,高度不會持續(xù)增加。
但是WKWebView比UIWebView更加高效和蘋果更加推薦翰绊,所以也放棄佩谷。

解決方案三

測試代碼,發(fā)現(xiàn)如果不僅僅更新frame的height监嗜,取而代之的通過contentSize同時(shí)更新webView的frame的寬高谐檀,就不會出現(xiàn)高度的持續(xù)增高。但是頁面內(nèi)容寬度會失去限制裁奇,超過webView頁面范圍桐猬。

最終解決方案是通過JS代碼限制webView的內(nèi)容寬度。
方案是不更改監(jiān)聽代碼刽肠,也不對監(jiān)聽得到的高度減一溃肪。更新WKNavigationDelegate的- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation如下:

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    if (webView == _webView) {
        NSString *meta = [NSString stringWithFormat:@"document.getElementsByName(\"viewport\")[0].content = \"width=self.webView.frame.size.width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\""];
        [_webView evaluateJavaScript:meta completionHandler:^(id _Nullable complete, NSError * _Nullable error) {
            if (complete != nil) {
                NSLog(@"complete %@", complete);
            } else if (error) {
                NSLog(@"error %@", error);
            }
        }];
    }
}

通過強(qiáng)制設(shè)置頁面的寬度為我們當(dāng)前的webView的寬度。解決偶爾出現(xiàn)的高度持續(xù)增加的Bug音五。

Reference

How to determine the content size of a UIWebView?
iOS 修改webView字體大小,設(shè)置寬度及縮放效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惫撰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子放仗,更是在濱河造成了極大的恐慌润绎,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诞挨,死亡現(xiàn)場離奇詭異,居然都是意外死亡呢蛤,警方通過查閱死者的電腦和手機(jī)惶傻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來其障,“玉大人银室,你說我怎么就攤上這事±恚” “怎么了蜈敢?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長汽抚。 經(jīng)常有香客問我抓狭,道長,這世上最難降的妖魔是什么造烁? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任否过,我火速辦了婚禮午笛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘苗桂。我一直安慰自己药磺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布煤伟。 她就那樣靜靜地躺著癌佩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪便锨。 梳的紋絲不亂的頭發(fā)上围辙,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機(jī)與錄音鸿秆,去河邊找鬼酌畜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛卿叽,可吹牛的內(nèi)容都是我干的桥胞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼考婴,長吁一口氣:“原來是場噩夢啊……” “哼贩虾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沥阱,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤缎罢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后考杉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體策精,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年崇棠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了咽袜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡枕稀,死狀恐怖询刹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情萎坷,我是刑警寧澤凹联,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站哆档,受9級特大地震影響蔽挠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虐呻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一象泵、第九天 我趴在偏房一處隱蔽的房頂上張望寞秃。 院中可真熱鬧,春花似錦偶惠、人聲如沸春寿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绑改。三九已至,卻和暖如春兄一,著一層夾襖步出監(jiān)牢的瞬間厘线,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工出革, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留造壮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓骂束,卻偏偏與公主長得像耳璧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子展箱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容