目錄
- 引言:Html加載流程
- 加載流程各節(jié)點(diǎn)耗時(shí)分析優(yōu)化
- 加載流程結(jié)構(gòu)優(yōu)化
- 客戶端優(yōu)化
Html加載流程
- 創(chuàng)建并初始化WebView
- 下載網(wǎng)頁所需資源文件
- 渲染展示網(wǎng)頁
加載流程各節(jié)點(diǎn)耗時(shí)分析優(yōu)化
-
WebView創(chuàng)建初始化
首次初始化WebView會(huì)比第二次初始化慢很多臊诊。初始化后另锋,即使WebView已釋放,但一些多WebView共用的全局服務(wù)/資源對想仍未釋放摘能,而第二次初始化不需要生成腔彰,因此初始化變快诵盼。1. 提前初始化, 提前預(yù)備全局WebView畅卓,Application中初始化WebView備用 @Override public void onCreate() { // Application中提前初始化WebView WebView mWebView = new WebView(new MutableContextWrapper(this)) }
注:該方式會(huì)增加冷啟動(dòng)時(shí)間
2. WebView復(fù)用绊袋,維護(hù)WebView pool,避免每次打開網(wǎng)頁創(chuàng)建WebView璃岳。
例如:VasSonic方案
-
DNS解析耗時(shí)
html網(wǎng)頁文件獲取過程中年缎,首先需要將url鏈接解析成ip地址,根據(jù)ip地址獲取到對應(yīng)html文件铃慷。1. DNS會(huì)在系統(tǒng)級別進(jìn)行緩存单芜,對于WebView的地址,如果使用的域名與原生api的相同犁柜,則可直接使用緩存洲鸠,避免DNS解析耗時(shí)。
-
資源文件下載耗時(shí)
弱網(wǎng)情況下馋缅,下載網(wǎng)頁資源耗時(shí)扒腕,導(dǎo)致白屏?xí)r間過長。1. 網(wǎng)頁資源壓縮萤悴,并CDN加速處理瘾腰,縮短請求耗時(shí)。 2. 服務(wù)端下發(fā)填充好首屏數(shù)據(jù)的網(wǎng)頁稚疹,作為網(wǎng)頁首屏展示居灯,減少網(wǎng)頁上數(shù)據(jù)請求時(shí)間。 3. App閑置狀態(tài)時(shí)内狗,下載離線包到本地怪嫌,加載時(shí)優(yōu)先加載離線包數(shù)據(jù)。后續(xù)更新接收下發(fā)的差異包柳沙,與當(dāng)前離線包合并成完整包岩灭。
HTML解析耗時(shí)
解析html文件,構(gòu)建DOM樹赂鲤,耗時(shí)取決于html節(jié)點(diǎn)嵌套復(fù)雜程度噪径,與硬件解析能力強(qiáng)弱柱恤。-
css文件加載解析、js加載
一般來說Html在開始接收到數(shù)據(jù)返回?cái)?shù)據(jù)時(shí)就開始解析并構(gòu)建DOM樹找爱,如果沒有JS阻塞的話一般會(huì)相繼完成梗顺,通常情況下,下面代碼的link部分和script部分如果單獨(dú)出現(xiàn)车摄,都不會(huì)阻塞頁面的解析寺谤,但,當(dāng)兩部分同時(shí)出現(xiàn)時(shí)吮播,css加載會(huì)阻塞下面的內(nèi)聯(lián)JS的執(zhí)行变屁,從而阻塞阻塞Html文件的解析。1. 為防止JS阻塞Html的解析意狠,Web端需延遲JS解析粟关。
-
繪制渲染
布局繪制是一個(gè)遞歸過程,從呈現(xiàn)根節(jié)點(diǎn)開始环戈,遞歸遍歷子節(jié)點(diǎn)闷板,計(jì)算幾何集合信息。因此谷市,html標(biāo)簽越復(fù)雜蛔垢、嵌套越深击孩,則布局耗時(shí)越久迫悠。1. 優(yōu)化網(wǎng)頁布局,減少布局層次巩梢。
加載流程結(jié)構(gòu)優(yōu)化
- 流程優(yōu)化
默認(rèn)狀態(tài)下创泄,WebView初始化與資源文件下載為線性同步執(zhí)行,此時(shí)WebView初始化時(shí)括蝠,網(wǎng)絡(luò)為空閑狀態(tài)鞠抑,并行處理WebView初始化與資源文件下載可縮短網(wǎng)頁顯示的總耗時(shí)。第一階段為:創(chuàng)建初始化WebView(Launch WebView)
第二階段為:請求網(wǎng)頁資源(Native(Sonic) Request)
但忌警,由于WebView初始化與請求網(wǎng)頁資源操作結(jié)束時(shí)間先后無可得知搁拙。
方案:流式攔截
,加入中間層來橋接內(nèi)核和數(shù)據(jù)
- 啟動(dòng)子線程請求頁面主資源法绵,子線程中不斷將網(wǎng)絡(luò)數(shù)據(jù)讀取到內(nèi)存中箕速。
- WebView初始化完成的時(shí)候,提供中間層BridgeStream來連接WebView和數(shù)據(jù)流朋譬;
- WebView讀取數(shù)據(jù)時(shí)盐茎,中間層BridgeStream先把內(nèi)存的數(shù)據(jù)讀取返回后,再繼續(xù)讀取網(wǎng)絡(luò)的數(shù)據(jù)徙赢。
通過橋接流的方式字柠,整個(gè)內(nèi)核無需等待探越,邊加載邊解析
客戶端優(yōu)化
-
合理使用WebView提供的幾種緩存方式
1. 瀏覽器緩存。內(nèi)置自動(dòng)實(shí)現(xiàn)
2. Application Cache 緩存webSettings.setAppCacheEnabled(true)
webSettings.setAppCacheMaxSize(yourCacheSize)
webSettings.setAppCachePath(yourCacheDirPath)- DOM Storage 緩存
setDomStorageEnabled(true)
- Web SQL Database 緩存
webSettings.setDatabaseEnabled(true)
webSettings.setDatabasePath(yourCacheDirPath)- Indexed Database 緩存窑业。Android 4.4以上支持
webSettings.setJavaScriptEnabled(true)
如何緩存html钦幔、js、css常柄、圖片等文件节槐,通過緩存機(jī)制,對于應(yīng)用提高資源文件的加載速度拐纱、流量優(yōu)化有很大意義铜异。而具體該針對哪種資源使用哪個(gè)緩存字段,以及緩存時(shí)長設(shè)置就比較重要秸架。若時(shí)長設(shè)置的太短揍庄,則緩存效果受影響,若時(shí)長設(shè)置過長东抹,則不能及時(shí)獲取服務(wù)器最新數(shù)據(jù)蚂子。
html、js缭黔、css資源
考慮到這些文件會(huì)隨著業(yè)務(wù)需求經(jīng)常變化食茎。為此,這些文件可以使用Last-Modified(Etag)
來控制緩存圖片馏谨、音視頻資源
圖片也可以通過Last-Modified(Etag)
來控制緩存别渔。但這樣每次都需向服務(wù)器發(fā)起查詢請求,考慮到圖片文件長時(shí)間變動(dòng)不大惧互,推薦使用Cache-Control
設(shè)置一個(gè)較長的時(shí)間來緩存哎媚。除此之外,也可以使用
Application Cache
機(jī)制喊儡,由前端控制緩存文件拨与,客戶端設(shè)置緩存路徑和大小。
由于艾猜,WebView各緩存機(jī)制的緩存大小有限买喧,時(shí)常導(dǎo)致最開始的緩存被清理;瀏覽器緩存Last-Modied
和ETag
控制不完全匆赃,依然無法很好的避免過渡請求網(wǎng)頁資源淤毛,因此,需要一套可控的緩存策略炸庞,來突破緩存容量過小和圖片緩存策略統(tǒng)一的問題钱床。
-
資源本地化
網(wǎng)頁加載到顯示,需要下載大量文件埠居,其中不乏有些體積大并且基本固定不動(dòng)的資源查牌,此時(shí)事期,可把這些資源預(yù)置在項(xiàng)目中,加載時(shí)從本地加載纸颜,方案與離線包
方案類似兽泣。
大致操作如下:
- 方式一、JS方法注入
// 1. 固定資源放到項(xiàng)目文件夾胁孙,如/Assets文件夾中
// 2. 注入JS方法
webView.addJavascriptInterface(new JsInterface(), "JsInterface")
private class JsInterface {
@JavascriptInterface
public String getLocalSrc(String src) {
return "file://storage/emulated/0/app/file/a.jpeg"
}
}
// 3. 頁面加載完成時(shí)唠倦,修改圖片標(biāo)簽
private class MyWebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
String js = "javascript:(function() {
var objs = document.getElementsByTagName('img');
for (var i = 0; i < objs.length; i++) {
var imgUrl = objs[i].getAttribute('src');
var localUrl = window.local_obj.getLocalSrc(imgUrl);
if (localUrl) {
objs[i].setAttribute('src', localUrl);
}
}
})()"
view.loadUrl(js);
}
}
- 方式二、請求攔截
webView.setWebViewClient(new WebViewClient() {
// 為方便涮较,此處進(jìn)寫Api 21以下方法稠鼻,Api21 以上雷同
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
// 1. 判斷攔截資源的條件
if (url.contains("logo.gif")) {
// 假設(shè)網(wǎng)頁圖片資源為:http://abc.com/image/logo.gif
// 圖片資源文件名為:logo.gif
// 2. 創(chuàng)建輸入流
InputStream is = null
try {
// 3. 獲得需要替換的資源(存放在assets文件夾中)
is = getApplicationContext().getAssets().open("image/abc.png")
} catch (IOException e) {
e.printStackTrace()
}
// 4. 替換資源
WebResourceResponse reponse = new WebResourceResponse("image/png", "utf-8", is)
return response
}
return super.shouldInterceptRequest(view, url)
}
})
此外,客戶端需要預(yù)置資源狂票,并維護(hù)網(wǎng)絡(luò)圖片url和本地圖片自檢的關(guān)聯(lián)候齿,根據(jù)一定策略保證本地預(yù)置資源為最新資源。若預(yù)置資源不限于圖片資源闺属,由于html慌盯、js、css等資源容易發(fā)生變化掂器,因此還需實(shí)現(xiàn)一套機(jī)制實(shí)現(xiàn)本地資源和服務(wù)端數(shù)據(jù)及時(shí)的更新亚皂。即服務(wù)端需要支持版本控制和資源增量下發(fā)等功能。
總結(jié)
結(jié)合手Q国瓮、網(wǎng)易嚴(yán)選灭必、美團(tuán)等其他方面優(yōu)化方案,大致如下:
- WebView在Application中提前初始化
- 實(shí)現(xiàn)WebView復(fù)用
- 另開WebView進(jìn)程
- DNS解析優(yōu)化(接口與網(wǎng)頁主域名一致)
- 線上資源壓縮巍膘、CDN加速
- 靜態(tài)直出厂财,直接下發(fā)首屏html
- 離線預(yù)推,下發(fā)離線包峡懈,并增量更新
- WebView創(chuàng)建與網(wǎng)絡(luò)請求并行
- 網(wǎng)頁按節(jié)點(diǎn)局部刷新
- 自定義實(shí)現(xiàn)圖片資源緩存
- 重新定義圖片加載格式,
shareP
- 本地資源攔截替換