WKWebView 的性能優(yōu)化

WKWebView 的性能優(yōu)化

起因

隨著移動設(shè)備性能不斷增強,web 頁面的性能體驗逐漸變得可以接受,又因為 web 開發(fā)模式的諸多好處(跨平臺,動態(tài)更新,減體積揖铜,無限擴展)贿肩,APP 客戶端里出現(xiàn)越來越多內(nèi)嵌 web 頁面)物邑,很多 APP 把一些功能模塊改成用 H5 實現(xiàn)茬射。

雖然說 H5 頁面性能變好了,但如果沒針對性地做一些優(yōu)化,體驗還是很糟糕的,主要兩部分體驗:

  1. 頁面啟動白屏時間:打開一個 H5 頁面需要做一系列處理簿煌,會有一段白屏時間,體驗糟糕夺荒。
  2. 響應(yīng)流暢度:由于 webkit 的渲染機制瞒渠,單線程,歷史包袱等原因技扼,頁面刷新/交互的性能體驗不如原生伍玖。

由于以上原因,公司準備從第一點入手剿吻,做 webview 的優(yōu)化項目(達到秒開 webview )窍箍。因為UIWebView在 iOS12 就被標記廢棄了,所以決定先從WKWebView入手研究。

思路

webview 加載過程

webview展示流程.png

打開一個頁面的過程有很多優(yōu)化點仔燕,包括前端和客戶端造垛,常規(guī)的前端和后端的性能優(yōu)化已有前輩們總結(jié)過最佳實踐,主要的是:

  • 降低請求量:合并資源晰搀,減少 HTTP 請求數(shù)五辽,minify / gzip 壓縮,webP外恕,lazyLoad杆逗。
  • 加快請求速度:預解析DNS,減少域名數(shù)鳞疲,并行加載罪郊,CDN 分發(fā)。
  • 緩存:HTTP 協(xié)議緩存請求尚洽,離線緩存 manifest悔橄,離線數(shù)據(jù)緩存 localStorage。
  • 渲染:JS/CSS優(yōu)化腺毫,加載順序癣疟,服務(wù)端渲染模板直出。
  • 客戶端:預請求web所需數(shù)據(jù)
    大家可以看出潮酒,主要是第三階段之前睛挚,用戶看到的頁面一直處于白屏。首先要優(yōu)化的就是這段時間急黎。
    打開一個頁面的過程有很多優(yōu)化點扎狱,包括前端和客戶端,常規(guī)的前端和后端的性能優(yōu)化已有前輩們總結(jié)過最佳實踐勃教,主要的是:

下面只講客戶端優(yōu)化部分:

減少第一階段耗時

  1. 在使用前預先初始化好 webView淤击,從而減小耗時。
  2. 在初始化的同時荣回,通過 Native 來完成一些網(wǎng)絡(luò)請求等過程遭贸,使得 webView 初始化不是完全的阻塞后續(xù)過程。
  3. webview 池心软,可以用兩個或多個 webview 重復使用,而不是每次打開 H5 都新建 webview著蛙。

減少第二階段耗時

  1. 離線包
    1. 預先下載離線包删铃,可以達到立即展示的效果。
    2. 離線包可以很方便地根據(jù)版本做增量更新踏堡。
    3. 離線包以壓縮包的方式下發(fā)猎唁,同時會經(jīng)過加密和校驗,防止運營商和第三方對其劫持篡改顷蟆。
  2. 數(shù)據(jù)緩存
    1. 第一次打開會有延遲诫隅,但是后續(xù)打開就會很快
    2. 可以自己控制緩存腐魂,方便管理
  3. 客戶端代替請求
    1. 客戶端可以在網(wǎng)絡(luò)請求上做像 DNS 預解析/ IP 直連/長連接/并行請求等更細致的優(yōu)化

難點

方案是通用的,不區(qū)分 UIWebView 和 WKWebView逐纬,但是目前很少有以 WKWebView 為目標的方案蛔屹,那么以上技術(shù)方案在 WKWebView 中實現(xiàn)有什么難點呢?
難點在 NSURLProtocol

WKWebView 無法使用 NSURLProtocol 攔截 http 請求

這個問題網(wǎng)上早有方案:
[WKBrowsingContextController registerSchemeForCustomProtocol:@"schemes"];

WKWebView 使用 NSURLProtocol 攔截后豁生,HTTPBody的數(shù)據(jù)會丟失

從網(wǎng)上克隆了 webkit 進行編譯調(diào)試兔毒,嘗試解決 Body 丟失的問題(體驗到了啥叫大型項目的編譯速度)


image.png

從圖上重點標注的地方可以看到:

  1. WKWebView 的網(wǎng)絡(luò)請求是在另外一個進程中操作的,然后如果 app 主進程需要攔截請求的話甸箱,通過 XPC 來進行兩個進程間的通信育叁。

  2. 蘋果出于性能或其他考慮,會在給主進程的 URLProtocol 傳輸請求時將 HTTPBodyHTTPBodyStream 置為 nil 芍殖。
    源代碼

嘗試解決方案:
  1. 使用 runtime 黑魔法豪嗽,在其將 HTTPBody 置為 nil 之前,先保存下來豌骏?
    因為網(wǎng)絡(luò)請求是在其他進程中操作昵骤,沒有辦法在主進程使用 runtime 進行攔截。也就是說在 app 中決定攔截 http 請求的那一刻起肯适,攔截到的請求注定是沒有 HTTPBody 的变秦。
  2. 使用 任何方式進入到 Networking 進程做一些操作 ?
    嘗試了 Mac 端的 XPC demo框舔,XPC 的回調(diào)是在各自進程蹦玫,是不能操作其他進程的。
  3. HTTPBody 置為 nil 之前刘绣,是否會有代碼走到主進程樱溉,然后拿到 request 進行操作?
    抱歉纬凤,經(jīng)過測試福贞,在 HTTPBody 置為 nil 之前,主進程不會收到關(guān)于 request 的調(diào)用
xpc 的 demo

解決

難到就沒有任何方法解決了么停士?無意中看到一個特別有趣的想法又點燃了我的希望挖帘。

既然 Networking 進程會將 HTTPBody 置為 nil ,那我要做的就是兩點:
1. 不讓其置為 nil
2. 或者在其置為 nil 之前恋技,先將 HTTPBody 保存下來

第一點:上面已經(jīng)嘗試失斈匆ā;第二點:在 native 端也嘗試失敗蜻底,那在 H5 側(cè)做保存操作呢骄崩?
要攔截的是 H5 的請求,那說明 H5 側(cè)肯定是知道請求參數(shù)的。

嘗試 H5 與 native 結(jié)合來解決 HTTPBody 丟失問題

H5 發(fā)起發(fā)起請求有三種方式:
1. Form
2. XMLHttpRequest
3. Fetch

Fetch是在 iOS10 以后支持的要拂,從通用場景看抠璃,只需要處理 FormXMLHttpRequest 發(fā)起的帶 HTTPBody 的請求就可以.

基本所有 H5 開發(fā)者,肯定知道 H5 里面也有黑魔法脱惰,就是原型:
XMLHttpRequest 對應(yīng)的是 XMLHttpRequest.prototype.send 方法
Form 對應(yīng)的是 HTMLFormElement.prototype.submit 方法

我們對以上方法使用 WKUserScriptWKUserScriptInjectionTimeAtDocumentStart 時機做對應(yīng)攔截搏嗡。這樣 H5 在發(fā)起請求前,先將 POST 的數(shù)據(jù)發(fā)送給 native 存儲(WKScriptMessageHandler)枪芒。然后在 native 攔截到匹配到的請求彻况,嘗試接管,并重新設(shè)置 HTTPBody舅踪,而且由于攔截到的是 request 纽甘,只需要補齊HTTPBody,其他在 h5 中原本對 request 做的各種操作也是存在的抽碌,這樣就能解決問題了

這個方法提供了一種解決HTTPBody 丟失問題的可能悍赢,并且大部分 app,使用應(yīng)該完全夠用货徙。本人已經(jīng)按照上述方案實現(xiàn)左权,并接入到 app 中,在解決了一些細節(jié)問題后痴颊,將各個流程中的 H5 頁面走了一遍赏迟,目前沒有發(fā)現(xiàn)不支持的請求。


感興趣的可以自己下載編譯 webkit
XPCDemo


參考:
WebView性能蠢棱、體驗分析與優(yōu)化
移動 H5 首屏秒開優(yōu)化方案探討
IMYWebLoader
VasSonic

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锌杀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子泻仙,更是在濱河造成了極大的恐慌糕再,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玉转,死亡現(xiàn)場離奇詭異突想,居然都是意外死亡,警方通過查閱死者的電腦和手機究抓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門猾担,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人漩蟆,你說我怎么就攤上這事垒探。” “怎么了怠李?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我捺癞,道長夷蚊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任髓介,我火速辦了婚禮惕鼓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唐础。我一直安慰自己箱歧,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布一膨。 她就那樣靜靜地躺著呀邢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪豹绪。 梳的紋絲不亂的頭發(fā)上价淌,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音瞒津,去河邊找鬼蝉衣。 笑死,一個胖子當著我的面吹牛巷蚪,可吹牛的內(nèi)容都是我干的病毡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼屁柏,長吁一口氣:“原來是場噩夢啊……” “哼啦膜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起前联,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤功戚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后似嗤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啸臀,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年烁落,在試婚紗的時候發(fā)現(xiàn)自己被綠了乘粒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡伤塌,死狀恐怖灯萍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情每聪,我是刑警寧澤旦棉,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布齿风,位于F島的核電站,受9級特大地震影響绑洛,放射性物質(zhì)發(fā)生泄漏救斑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一真屯、第九天 我趴在偏房一處隱蔽的房頂上張望脸候。 院中可真熱鬧,春花似錦绑蔫、人聲如沸运沦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽携添。三九已至,卻和暖如春凉馆,著一層夾襖步出監(jiān)牢的瞬間薪寓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工澜共, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留向叉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓嗦董,卻偏偏與公主長得像母谎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子京革,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

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