Hybrid App中WKWebView采坑淺談

一、iOS 平臺中 UIWebView 與 WKWebView 有什么區(qū)別?

UIWebView 是蘋果繼承于 UIView 封裝的一個加載 web 內(nèi)容的類,它可以加載任何遠(yuǎn)端的web數(shù)據(jù)展示在你的頁面上,你可以像瀏覽器一樣前進(jìn)后退刷新等操作。不過蘋果在 iOS8 以后推出了 WKWebView 來加載 Web,并應(yīng)用于 iOS 和 OSX 中,它取代了 UIWebView 和 WebView ,在兩個平臺上支持同一套 API。
它脫離于 UIWebView 的設(shè)計,將原本的設(shè)計拆分成14個類,和3個代理協(xié)議,雖然是這樣但是了解之后其實用法比較簡單,依照職責(zé)單一的原則,每個協(xié)議做的事情根據(jù)功能分類。


  • WKWebView 與 UIWebView 的區(qū)別:
    WKWebView 的內(nèi)存遠(yuǎn)遠(yuǎn)沒有 UIWebView 的開銷大,而且沒有緩存;
    WKWebView 擁有高達(dá) 60FPS 滾動刷新率及內(nèi)置手勢;
    WKWebView 支持了更多的 HTML5 特性;
    WKWebView 高效的 app 和 web 信息交換通道;
    WKWebView 允許 JavaScript 的 Nitro 庫加載并使用, UIWebView 中限制了;
    WKWebView 目前缺少關(guān)于頁碼相關(guān)的 API;
    WKWebView 提供加載網(wǎng)頁進(jìn)度的屬性;
    WKWebView 使用 Safari 相同的 JavaScript 引擎;
    WKWebView 增加加載進(jìn)度屬性: estimatedProgress ;
    WKWebView 不支持頁面緩存,需要自己注入 cookie , 而 UIWebView 是自動注入 cookie ;

  • WKWebView 無法發(fā)送 POST 參數(shù)問題;
    WKWebView 可以和js直接互調(diào)函數(shù),不像 UIWebView 需要第三方庫 WebViewJavascriptBridge 來協(xié)助處理和 js 的交互;

  • 注意:
    大多數(shù)App需要支持 iOS7 以上的版本,而 WKWebView 只在 iOS8 后才能用,所以需要一個兼容性方案,既 iOS7 下用 UIWebView , iOS8 后用 WKWebView 。但是目前 IOS10 以下的系統(tǒng)以及很少了,

  • 小結(jié):
    WKWebView 相較于 UIWebView 在整體上有較大的提升,滿足 iOS 上面使用同一套控件的功能,同時對整個內(nèi)存的開銷以及滾動刷新率和 JS 交互做了優(yōu)化的處理。
    依據(jù)職責(zé)單一原則,拆分成了三個協(xié)議去實現(xiàn) WebView 的響應(yīng),解耦了 JS 交互和加載進(jìn)度的響應(yīng)處理。
    WKWebView 沒有做緩存處理,所以對網(wǎng)頁需要緩存的加載性能要求沒那么高的還是可以考慮 UIWebView 。

二、WKWebView 有哪一些坑?

  1. WKWebView 白屏問題
    WKWebView 實際上是個多進(jìn)程組件,這也是它加載速度更快,內(nèi)存暫用更低的原因。
    在 UIWebView 上當(dāng)內(nèi)存占用太大的時候,App Process 會 crash;而在 WKWebView 上當(dāng)總體的內(nèi)存占用比較大的時候,WebContent Process 會 crash,從而出現(xiàn)白屏現(xiàn)象。
  • 解決辦法:
    a.借助 WKNavigtionDelegate
系統(tǒng)會調(diào)用回調(diào)函數(shù):
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView;
我們在該函數(shù)里執(zhí)行 [webView reload](這個時候 webView.URL 取值尚不為 nil)解決白屏問題。
在一些高內(nèi)存消耗的頁面可能會頻繁刷新當(dāng)前頁面,H5側(cè)也要做相應(yīng)的適配操作。

b. 檢測 webView.title 是否為空
并不是所有 H5 頁面白屏的時候都會調(diào)用上面的回調(diào)函數(shù),比如,最近遇到在一個高內(nèi)存消耗的 H5 頁面上 present 系統(tǒng)相機(jī),拍照完畢后返回原來頁面的時候出現(xiàn)白屏現(xiàn)象(拍照過程消耗了大量內(nèi)存,導(dǎo)致內(nèi)存緊張,WebContent Process 被系統(tǒng)掛起),但上面的回調(diào)函數(shù)并沒有被調(diào)用。在 WKWebView 白屏的時候,另一種現(xiàn)象是 webView.titile 會被置空, 因此,可以在 viewWillAppear的時候檢測 webView.title 是否為空來 reload 頁面。

  1. WKWebView Cookie 問題
    WKWebView Cookie 問題在于 WKWebView 發(fā)起的請求不會自動帶上存儲于 NSHTTPCookieStorage 容器中的 Cookie,而在 UIWebView 會自動帶上 Cookie。
    原因是:
    WKWebView 擁有自己的私有存儲,不會將 Cookie 存入到標(biāo)準(zhǔn)的 Cookie 容器 NSHTTPCookieStorage 中。
    實踐發(fā)現(xiàn) WKWebView 實例其實也會將 Cookie 存儲于 NSHTTPCookieStorage 中,但存儲時機(jī)有延遲,在 iOS8上,當(dāng)頁面跳轉(zhuǎn)的時候,當(dāng)前頁面的 Cookie 會寫入 NSHTTPCookieStorage 中,而在 iOS10 上,JS 執(zhí)行 document.cookie 或服務(wù)器 set-cookie 注入的 Cookie 會很快同步到 NSHTTPCookieStorage 中,F(xiàn)ireFox 工程師曾建議通過 resetWKProcessPool 來觸發(fā) Cookie 同步到 NSHTTPCookieStorage 中,實踐發(fā)現(xiàn)不起作用,并可能會引發(fā)當(dāng)前頁面 session cookie丟失等問題。
  • 解決辦法1:
    WKWebViewloadRequest 前,在 request header 中設(shè)置 Cookie, 解決首個請求 Cookie 帶不上的問題;
  • 解決辦法2:
    通過 document.cookie 設(shè)置 Cookie 解決后續(xù)頁面(同域) Ajax``、iframe 請求的 Cookie 問題;(注意: document.cookie() 無法跨域設(shè)置 cookie)。
  1. WKWebView loadRequest 問題
    在 WKWebView 上通過 loadRequest 發(fā)起的 post 請求 body 數(shù)據(jù)會丟失,同樣是由于進(jìn)程間通信性能問題, HTTPBody 字段被丟棄。
  2. WKWebView NSURLProtocol問題
    WKWebView 在獨立于 app 進(jìn)程之外的進(jìn)程中執(zhí)行網(wǎng)絡(luò)請求,請求數(shù)據(jù)不經(jīng)過主進(jìn)程,因此,在 WKWebView 上直接使用 NSURLProtocol 無法攔截請求。
  • 解決辦法:
    由于 WKWebView 在獨立進(jìn)程里執(zhí)行網(wǎng)絡(luò)請求。一旦注冊 http(s)scheme 后,網(wǎng)絡(luò)請求將從 NetworkProcess 發(fā)送到 AppProcess,這樣 NSURLProtocol 才能攔截網(wǎng)絡(luò)請求。在 webkit2 的設(shè)計里使用 MessageQueue 進(jìn)行進(jìn)程之間的通信,Network Process 會將請求 encode 成一個 Message,然后通過 IPC 發(fā)送給 AppProcess。出于性能的原因, encode 的時候 HTTPBody 和 HTTPBodyStream 這兩個字段會被丟棄掉了。
  1. WKWebView 頁面樣式問題
    在 WKWebView 適配過程中,我們發(fā)現(xiàn)部分 H5 頁面元素位置向下偏移或被拉伸變形,追蹤后發(fā)現(xiàn)主要是 H5 頁面高度值異常導(dǎo)致。
  • 解決辦法:
    調(diào)整 WKWebView 布局方式,避免調(diào)整 webView.scrollView.contentInset 。實際上,即便在UIWebView 上也不建議直接調(diào)整 webView.scrollView.contentInset 的值,這確實會帶來一些奇怪的問題。如果某些特殊情況下非得調(diào)整 contentInset 不可的話,可以通過下面方式讓H5頁面恢復(fù)正常顯示。
  1. WKWebView 截屏問題
    WKWebView 下通過 -[CALayer renderInContext:]實現(xiàn)截屏的方式失效,需要通過以下方式實現(xiàn)截屏功能:
@implementation UIView (ImageSnapshot)
- (UIImage*)imageSnapshot {    
    UIGraphicsBeginImageContextWithOptions(self.bounds.size,YES,self.contentScaleFactor);
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
@end

然而這種方式依然解決不了 webGL 頁面的截屏問題,截屏結(jié)果不是空白就是純黑圖片。

  • 解決辦法:
    無奈之下,我們只能約定一個JS接口,讓游戲開發(fā)商實現(xiàn)該接口,具體是通過 canvas getImageData()方法取得圖片數(shù)據(jù)后返回 base64 格式的數(shù)據(jù),客戶端在需要截圖的時候,調(diào)用這個JS接口獲取 base64String并轉(zhuǎn)換成 UIImage。
  1. WKWebView crash問題
    如果 WKWebView 退出的時候,JS剛好執(zhí)行了 window.alert(), alert 框可能彈不出來, completionHandler 最后沒有被執(zhí)行,導(dǎo)致 crash;
    另一種情況是在 WKWebView 一打開,JS就執(zhí)行 window.alert(),這個時候由于 WKWebView 所在的 UIViewController 出現(xiàn)( push 或 present )的動畫尚未結(jié)束,alert 框可能彈不出來, completionHandler最后沒有被執(zhí)行,導(dǎo)致 crash。
  2. 視頻自動播放
    WKWebView 需要通過 WKWebViewConfiguration.mediaPlaybackRequiresUserAction 設(shè)置是否允許自動播放,但一定要在 WKWebView 初始化之前設(shè)置,在 WKWebView 初始化之后設(shè)置無效。
  3. goBack API問題
    WKWebView 上調(diào)用 -[WKWebViewgoBack], 回退到上一個頁面后不會觸發(fā) window.onload() 函數(shù)、不會執(zhí)行JS。
  4. 頁面滾動速率
    WKWebView 需要通過 scrollViewdelegate 調(diào)整滾動速率:
- (void )scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}

四、常見的 WebView 性能優(yōu)化方案有哪一些?

  1. 問題分析
    首先需要了解,對于一個普通用戶來講,打開一個 WebView 通常會經(jīng)歷哪幾個階段,一般有這些:
    a.交互無反饋;
    b.到達(dá)新的頁面,頁面白屏;
    c.頁面基本框架出現(xiàn),但是沒有數(shù)據(jù);頁面處于loading狀態(tài);
    出現(xiàn)所需的數(shù)據(jù);

當(dāng) App 首次打開時,默認(rèn)是并不初始化瀏覽器內(nèi)核的;只有當(dāng)創(chuàng)建 WebView 實例的時候,才會創(chuàng)建 WebView 的基礎(chǔ)框架。
所以與瀏覽器不同,App 中打開 WebView 的第一步并不是建立連接,而是啟動瀏覽器內(nèi)核。
于是我們找到了“為什么WebView總是很慢”的原因之一:

而在客戶端中,客戶端需要先花費時間初始化 WebView 完成后,才開始加載。
而這段時間,由于WebView還不存在,所有后續(xù)的過程是完全阻塞的。
因此由于這段過程發(fā)生在 native 的代碼中,單純靠前端代碼是無法優(yōu)化的;

大部分的方案都是前端和客戶端協(xié)作完成,以下是幾個業(yè)界采用過的方案:

  1. 全局 WebView池
  2. WebView 預(yù)加載
  3. 獨立的web進(jìn)程,與主進(jìn)程隔開
  4. WebView 釋放防止內(nèi)存泄露

參考文章:[《UIWebView與WKWebView》] (http://www.cocoachina.com/articles/17337)
參考文章:[《WKWebView 那些坑》] (https://kknews.cc/tech/x2rzg3g.html)

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

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