WKWebView刷新機制小探

背景

iOS的一個坑。在線上的版本中,iOS10系統中,app內使用WKWebView當作一個普通的子View來展示一個較長的Web內容組成一個hybrid頁面時,會發生白屏的。經過原生端的開發的排除,確認是WKWebView的機制問題,并不是頁面加載不完整或者是被劫持而導致的問題。

為了更嚴謹的排出問題所在,我拉去了原聲端的代碼再次確認代碼邏輯是否存在導致該問題所在的bug。因為該頁面是一個自定義的UITableView,WKWebView只是UITableView的一個Cell里面的子View,而且和UITableView的model層,也有很多的業務邏輯,看起來比較費勁。經過了幾輪的調試,知識找到了一個導致導致死循環的一個調用,那邊的開發使用了RAC綁定WKWebView內嵌UIScrollView的contentSize,去刷新UITableView,UITableView的回調獲取cell的高度的時候會導致循環調用,一直的刷新UITableView獲取cell的高度,除了會消耗性能,并沒有看出邏輯有太大問題。因為,目前并不會導致頁面出現一些莫名其妙的問題,也不知道原來寫這部分代碼邏輯的同事初衷是什么,所以并沒有改動這部分代碼。另外,用了Charles看了一下這個頁面的請求,并不是頁面劫持導致的問題。

不是請求劫持導致的問題

http請求完整

問題必現,證明是通用性問題

嘗試設置WKWebView的frame比contentSize小,在滾動WKWebView的時候,里面的內容是可以全部展示的,并沒有出現白屏的問題。可以得出的結論是:WKWebView作為一個元素放在UITabViewCell里面,是沒問題問題的(當然,性能問題在討論范圍)。

調試了大半天,并沒有找到問題的根源。于是先建立一個demo工程,先確認和排出一些問題。

UITableViewCell中嵌套WKWebView是否會導致刷新問題

UITabView中計算獲取嵌套了WKWebView的UITabViewCell計算高度是否準確

建立工程,在UITableVie的一個UITableViewCell里面嵌套了一個WKWebView來重現工程中的情況。

Reveal

先通過Reveal工具來看一下WKWebView的樹,先大概了解一些WKWebView的結構。

WKScrollView

WKScrollView繼承于UIScrollView,在初始化的時將初始化一個WKScrollViewDegelageForwarder代理實例

下圖是WKScrollView的delegate的setter方法,可以清晰的看到各個delegate的類型

在WKScrollViewDegelageForwarder的實現中,明確的看到,WKScrollView的delegate(externalDelegate實例)的消息都通過message_forward的形式轉發到WKWebView(internalDelegate)實例中。

下圖是WKScrollViewDegelageForwarder類的轉發實現

WKContentView

WKContentView就是WKWebView內容渲染的容器。在Reveal的樹狀圖上面可以看到,渲染頁面中,展示在頁面上的渲染單元是WKCompositingView,WKCompositingView可以嵌套WKCompositingView。其中的一個WKCompositingView實例,將包含多個WKCompositingView子實例。類似于UITableView的重用機制,多個WKCompositingView的父View就相當于UITableView,WKCompositingView就相當于UITableViewCell,只展示可視區域的內容,達到性能優化的目的。

從下圖可以看到,一個WKWebView加載的web內容,切割成多個WKCompositingView,單個WKCompositingView重用單元的面積是375x512點。

WKWebView

初始化

在WKWebView初始化的代碼中,可以看到這樣的一段初始化代碼

init

ScrollView回調

在WKWebView中,ScrollView相關的回調的調用鏈都是這樣的一個調用關系:

scrollview delegate's callback ->[WKWebView_updateVisibleContentRectAfterScrollInView:]->[WKWebView_updateContentRectsWithState:]->[WKContentViewdidUpdateVisibleRect:visibleRectInContentCoordinatesunobscuredRect:unobscuredRectInContentCoordinatesunobscuredRectInScrollViewCoordinates:unobscuredRect? ? ? ? ? ? ? ? ? ? ? ? obscuredInset:CGSizeMake(_obscuredInsets.left, _obscuredInsets.top)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? scale:scaleFactor? ? ? ? ? ? ? ? ? ? ? ? ? minimumScale:[_scrollView minimumZoomScale]? ? ? ? ? ? ? ? ? ? ? ? inStableState:inStableState isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively? ? ? enclosedInScrollableAncestorView:scrollViewCanScroll([self _scroller])];

從調用鏈上清晰可以看到,當WKScrollView滾動的時候,WKScrollView滾動相關回調的消息,將會發送到WKWebView內,WKWebView實例內scrollView的的回調將會調用WKContntView的刷新方法,刷新需要渲染的web內容。

猜想

當了解到WKWebView內容的刷新機制以后,就可以合理的進行猜想了。

因為WKWebView作為一個普通的UIView添加在UITableViewCell的contentView上,因為項目中UITableView和WKWebView的ScrollView都是豎向滾動的,這兩個手勢動作將會沖突,WKWebView只是一個子View,需要通過設置內置ScrollView的滾動屬性來將WKWebView的滾動功能關閉,保證父View--UITableView滾動功能的正常使用。

因為WKWebView使用過綁定內置ScrollView的滾動回調來刷新WKContentView內需要渲染的web內容的,因為WKWebView已經被設定為禁止滾動,自然不會再刷新需要渲染當初在不在可視區域的內容了。因為UITableView的滾動回調并沒有和WKWebView的內的滾動是綁定關系,所以在UITableView滾動的時候,并不會觸發WKWebView的刷新。這就是為什么在進入頁面的時候,上面一部分內容可以正常顯示,二下半部分顯示白屏的原因。當然,在目前來說只是一個猜想。

驗證

前面的猜想,在經過對源代碼的閱讀,理論上是說得通的。現在就通過demo的代碼驗證。有了上面的原理,那么UITablbeView滾動的時候,觸發WKWebView刷新頁面即可?可知的是,WKWebView是調用_updateVisibleContentRectAfterScrollInView:方法來對WKContentView來刷新內容的。

由下圖可知,而WKWebView的_updateVisibleContentRects方法實現,也只是調用了_updateVisibleContentRectAfterScrollInView:,也就是說直接調用WKWebView實例的_updateVisibleContentRects就可以刷新了。

下面,用RAC來監聽一下UITableView實例的contentOffset屬性,在contentOffset發生變化的時候,也就是UITableView實例滾動的時候,就去調用一下WKWebView實例的_updateVisibleContentRects方法去刷新需要渲染的內容。

@weakify(self);? ? [RACObserve(self.tableView, contentOffset) subscribeNext:^(idx) {? ? ? ? @strongify(self);if([self.webView respondsToSelector:@selector(_updateVisibleContentRects)]) {? ? ? ? ? ? ((void(*)(id,SEL,BOOL))objc_msgSend)(self.webView,@selector(_updateVisibleContentRects),NO);? ? ? ? }? ? }];

在運行demo工程的時候,結果按照猜想的發生了,滾動到WKWebView下方時,原來會白屏的區域正常的渲染內容了。

解決方案

上方猜想被證實了,那么說這個方案時可以行的,而且對源代碼的理解并沒有太大的偏差。按照原理,可以使用一下幾個方法來解決白屏的問題

用KVO方法監聽UITableView的contnetOffset屬性,contentOffset發生變化也就是說UITableView發生滾動,調用WKWebView實例的_updateVisibleContentRects,刷新需要渲染的內容

UITableView是繼承自UIScrollView的,在代碼中實現UIScrollView的delegate,在delegate實現中手動調用WKWebView實例等UIScrollViewDelegate的方法,原理和第一種方法一樣

使用CADisplayLink類,在CADisplayLink的回調方法里面調用WKWebView實例的_updateVisibleContentRects即可

上面三種方法的其實都是大同小異的,只是適合不同的場景。優劣也不用說了,一眼就能看出來了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容

  • create at 2016.11.07 20:58 背景 iOS的一個坑。在線上的版本中,iOS10系統中,ap...
    笨魚BennettPenn閱讀 29,987評論 40 94
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,155評論 4 61
  • 我選擇了一條生活的不歸路,快被折磨得了無生氣,卻p都不想放個,下班的路上硬生把想念憋回去,然后是今晚又該煮什么黑暗料理呢
    Flower_sky閱讀 303評論 0 0
  • 01找對象要找什么樣的?找一個說話不累的。 有個朋友發信息跟我說,最近跟一個有好感的男生聊天,原本這是件好事,有了...
    墨六風閱讀 1,292評論 0 2
  • 寫作,是一個部分完整的梳理思路的過程,每天我幾乎都會產生一些,細微的對世界的不同看法和改變,依此而言,每天的記錄,...
    三杯倒不倒女俠閱讀 283評論 2 1