一、背景
在實際業務中,我們app中的webview使用的場景越來越多,加載速度成爲了困擾用戶的一個痛點,尤其是h5由jsp過渡到vue後,頁面加載速度更慢了,經常是經過長時間的loading才能加載出來,雖然這和我們的整體架構有關,首頁有4-7個webview fragment,在進入首頁的時候會同時加載,各個頁面都需要加載大量的圖片以及數個請求。爲此,提高加載速度成爲了優化當中的一個方向。
二、技術探索
在查閱過相關資料後,技術方向大體分爲了兩個,一個是鵝廠的VasSonic,通過輔以x5內核對於webview的優化,加上頁面直出,整體加載速度很誇張,在我看來基本逼近了webview的加載極限,但是其難以實現之處在於侵入性很強,需要整體結構向它靠攏,後端、h5、Android三方配合,對於像我們公司以業務爲導向的團隊來說,做起來還比較困難。另一個就是離線包,通常來說,加載一個h5頁面最耗時的部分就在於頁面資源的下載,如html、css、js文件,如果這些文件不需要下載,那麼剩下的時間開銷基本就是頁面解析及渲染。我們Android在和h5溝通過以後,決定採取方案二。
三、技術實現
1.離線包的組成
離線包由h5提供,包裏面的結構基本和線上一致,本身我們的h5網頁就是放在cdn上,這次只不過是拿出來,打成壓縮包,放在Android的apk包裏
2.Android對離線包的解析
首先,離線包的zip包是放在assets文件夾下,在app啓動時,解壓zip包到相應的文件夾目錄下,拿到這個本地路徑
3.對線上地址的替換
webview在加載的時候,會調用loadurl方法,此時傳進去的url還是線上的url,Android要做的最重要的一步就是重寫webviewClient的shouldInterceptRequest方法,在裏面拿到要加載的url,並且進行替換,替換成本地url。同樣的道理,凡事線上資源都可以進行替換,如css、js、圖片資源,還可以通過glide對圖片資源進行緩存。核心代碼如下
//=============================離線化對webviewclient的改造
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String urlOrigin) {
//攔截請求,把本地頁面地址轉換成線上頁面地址
String url = UrlConfig.replaceUrlHost(urlOrigin);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));
//如果是圖片走緩存
if (("image/jpeg".equals(mimeType) || "image/png".equals(mimeType)))
return handleImageRequest(url, mimeType);
if (UrlConfig.USE_OFFLINE && !url.contains("http")) {
//構建WebResourceResponse,走重寫後的方法。super會直接load傳進來的urlOrigin
try {
URL localUri = new URL(url);
InputStream is = localUri.openConnection().getInputStream();
return new WebResourceResponse(
MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url))
, "UTF-8", is);
} catch (IOException e) {
//如果文件找不到,攔截方法會失效,還是走之前的url
if (e.getMessage().contains(".js")) {
//當前線程-Chrome_FileThread
webview.getHandler().post(new Runnable() {
@Override
public void run() {
onError.onErrorReceived();//處理白屏的情況,缺少js文件會走onError
C.OFFLINE_LOADFAIL = true;
}
});
}
e.printStackTrace();
}
}
return super.shouldInterceptRequest(view, url);
}
註釋1:UrlConfig.replaceUrlHost方法裏面是具體替換過程。舉個例子:線上地址肯定是 ww.baidu.com/index.html這種,本地地址就是file:///storage/0/emulate/baidu/index.html,把index.html之前做字符串替換就可以。
四、最終效果
經過測試同學的性能測試,頁面首次加載提升率平均50%,二次加載平均提升35%;由於網絡請求也是Android代替h5請求,所以request請求提升超過80%,這些數據是正常網絡狀態下,而在弱網狀態下更是有超過300%的提升
================================================================================================
如有問題,可加1510312433交流