前言
由于目前的工作中,原生app大量嵌入h5頁面,很多的功能需要h5來實現,但是由于h5需要從網絡加載,在弱網狀態或者請求資源大的時候必然出現白屏,再網上搜索后發現并沒有一個通用的解決方案,其中VasSonic(手Q的解決方案)侵入性太大,需要整個框架更換成本太大,經過一段時間的實踐特總結優化的思路。
總結下主要優化的地方有三塊,webview初始化的時間優化,靜態資源加載的優化, 數據請求前展示的優化
- webview初始化的時間優化
這個問題在找到webview加載各個app時間時發現的,在webview,
loadRequest
方法到- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
竟然耗時在1.5s左右,但是再次跳轉路由或者加載別的頁面時,這個時間基本就沒有,猜想可能是第一次loadRequest時同時初始化了webview內部的組件。
加載空白頁面的耗時
加載百度的耗時
先加載空白頁面,再加載百度的耗時
從上邊的測試很明顯可以證實我們的猜測
針對上邊的問題我們進行了測試,通過先加載h5項目的一個頁面再加載真正要展示的頁面時間發現第二次加載時并沒有load->start的耗時,甚至先加載about:blank也沒有這個耗時,所以基本找到了問題。
我們解決做法是做了一個webview的復用池(當然如果項目中同時只有一個webview存在時可以做成單例),在加載閃屏頁時進行初始化并加載url(我們項目是vue寫的目前是加載一個vue的空白頁,其實如果沒有做靜態資源攔截加載空白頁面就好,這個防止網絡錯誤的問題), 在需要展示的地方能過js(location.hash來改變路由或者bridge)來跳轉頁面。
直接重新loadRequest可能為導航頁面重新渲染,能過location.hash或者location.href來改變路由相當于h5內部的跳轉,不會重新加載框架
- 靜態資源,能用框架的請求時間
這個是通用的解決方法,因為h5頁頭有很多靜態資源,樣式,框架,靜態圖片,這些都會影響加載速度
針對上邊的問題我們解決方案和大部分的一樣,將h5的靜態資源打包放到本地一份,然后攔截webview請求,靜態資源本地讀取,ajax請求不攔截
但是由于我們用的webview是wkwebview也就有post請求body丟失的問題目前網上沒有可行的解決方案, VasSonic上也是用的uiwebview,項目因為有很多的h5如果換回uiwebveiw會有很多的問題,并且uiwebview性能比較低,占的內存也很大,本身準備放棄,但是在部門老大的提示下,找到了繞過的方案
- 前邊實現和網上是一樣
[NSURLProtocol registerClass:[MyNSURLProtocol class]];
- 但是只在打開wkwebview的時候進行攔截
[NSURLProtocol wk_registerScheme:@"http"];
[NSURLProtocol wk_registerScheme:@"https"];
- 但是這樣會有問題,所以需要h5配合在靜態資源文件加載完畢之后通知原生停止攔截
在
beforeCreate
方法里通知原生
[NSURLProtocol wk_unregisterScheme:@"http"];
[NSURLProtocol wk_unregisterScheme:@"https"];
由于靜態資源都是get請求,這樣就繞過了post丟失body體的問題
第二個問題是因為h5和原生版本不同步的問題,h5更新的速度一般肯定會高于原生的,這樣原生里打包的靜態文件就會失去作用,并且之前一直不能對h5進行版本控制,比如app強制升級后h5無法兼容低版本
針對這個問題,我們的解決辦法是,h5也按版本更新,在app啟動的時候與服務器比對是否需要更新靜態資源,并且判斷當前版本下h5可以訪問的最新版本,當更新完成后提示用戶然后刷新頁面,如果未更新未完成依舊使用舊版本。
- 數據請求前的展示優化
到了這一步基本js就可以接手控制了,這步我們也還在不斷優化中,有以下幾個方向
- 框架和網絡交互分離,因為我們的h5項準備使用自己維護的框架,這個方案在一直慢慢推進,如果分離,就可以像原生一樣,就算網絡很差也不會出現白屏,會先加載一個框架,等請求回來后再渲染數據
正常使用vue也是可以做到的網上有很多的方案,骨架屏方案等,實在不行可以先加載個loading圖片也可以
- 請求數據緩存,如果沒有請求回來之前可以先使用歷史數據展示,對數據請求進行緩存控制,這樣即使沒有網用戶也是可以訪問的
由于我們的項目主要是面向b端的,要求數據一致性較高, 主要采用第1種方案進行優化