webview應(yīng)用首屏優(yōu)化

這里首屏優(yōu)化是指用戶安裝應(yīng)用后葵礼,首次打開(kāi)應(yīng)用消耗時(shí)間的優(yōu)化。 其中比較耗時(shí)的一點(diǎn)是首次打開(kāi)webview應(yīng)用并鸵,加載靜態(tài)資源鸳粉。 優(yōu)化思路是,首次打開(kāi)應(yīng)用园担,使用客戶端攔截請(qǐng)求届谈,返回本地文件。以后的請(qǐng)求優(yōu)化由ServiceWorker接管弯汰。

webview請(qǐng)求過(guò)程

一個(gè)靜態(tài)資源的請(qǐng)求艰山,分為以下4個(gè)過(guò)程按順序執(zhí)行

  1. ServiceWorker
  2. http緩存
  3. App應(yīng)用攔截
  4. 網(wǎng)絡(luò)服務(wù)

注意:sw.js文件的規(guī)則不在此列,sw.js文件好像始終請(qǐng)求網(wǎng)絡(luò)

image.png

有以下幾點(diǎn)需要注意:

第一步 ServiceWorker 必須是安裝好的

第一次進(jìn)入應(yīng)用咏闪,ServiceWorker并未安裝曙搬,所以會(huì)被直接跳過(guò),進(jìn)入http緩存

ServiceWorker的請(qǐng)求鸽嫂,也會(huì)先查看http緩存

就是說(shuō)纵装,從ServiceWorker發(fā)出的請(qǐng)求,也會(huì)遵循h(huán)ttp緩存規(guī)范据某,http緩存中有的文件橡娄,會(huì)被直接返回給ServiceWorker

只有ServiceWoker和http緩存都未命中,才會(huì)被App應(yīng)用攔截

App應(yīng)用攔截的限制

App應(yīng)用攔截webview請(qǐng)求癣籽,是通過(guò)復(fù)寫(xiě)shouldInterceptRequest方法實(shí)現(xiàn)

@TargetApi(VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view,
                    WebResourceRequest request) {

經(jīng)過(guò)測(cè)試挽唉,他有限制:
只會(huì)攔截html請(qǐng)求和寫(xiě)在html中的資源請(qǐng)求(即通過(guò)<link><script>等直接加載的資源。通過(guò)js請(qǐng)求的資源都不會(huì)被攔截筷狼,例如ajax請(qǐng)求瓶籽、main.js文件中請(qǐng)求的sw.js、ServiceWorker中發(fā)起的請(qǐng)求)埂材。沒(méi)有深入研究測(cè)試塑顺,理解也可能有誤。


優(yōu)化思路

App應(yīng)用安裝時(shí)候楞遏,將首屏所需靜態(tài)資源下載到本地文件中

首屏

首次打開(kāi)應(yīng)用茬暇,ServiceWorker未安裝首昔,也沒(méi)有任何http緩存寡喝,所以所有請(qǐng)求會(huì)直接被App應(yīng)用攔截,在這一步返回本地文件勒奇,達(dá)到秒開(kāi)效果预鬓。
同時(shí)不攔截sw.js文件(ServiceWorker的注冊(cè)文件),去網(wǎng)絡(luò)服務(wù)器請(qǐng)求sw.js文件進(jìn)行注冊(cè)安裝。

第二次打開(kāi)

因?yàn)樵谑灼链蜷_(kāi)應(yīng)用同時(shí)格二,sw.js也同時(shí)注冊(cè)安裝好了劈彪,同時(shí)通過(guò)cacheAll,也在ServiceWorker中緩存了最新的網(wǎng)絡(luò)服務(wù)器中文件顶猜。
所以第二次打開(kāi)沧奴,所有的請(qǐng)求,都可以被ServiceWorker進(jìn)行攔截處理长窄,根據(jù)上面的注意事項(xiàng)(通過(guò)js請(qǐng)求的資源都不會(huì)被App應(yīng)用攔截)滔吠,所以第二次及之后的請(qǐng)求,基本就和App應(yīng)用攔截?zé)o關(guān)了挠日。

ServiceWoker緩存的更新

  1. 在每次請(qǐng)求時(shí)候疮绷,返回ServiceWorker緩存同時(shí),請(qǐng)求最新文件(副作用嚣潜,在每次頁(yè)面版本發(fā)生改變時(shí)候冬骚,第二次進(jìn)入應(yīng)用會(huì)卡,因?yàn)榈谝淮畏祷豐erviceWorker緩存懂算,不會(huì)卡只冻,但是請(qǐng)求到了新的index.html川抡,第二次進(jìn)入應(yīng)用活烙,根據(jù)新的index.html,發(fā)生變化的靜態(tài)資源籽慢,都會(huì)從網(wǎng)絡(luò)請(qǐng)求等待酸役,第三次進(jìn)入應(yīng)用才不會(huì)卡)
  2. 更新sw.js文件時(shí)候住诸,更新所有靜態(tài)資源文件(未實(shí)踐,應(yīng)該可行涣澡,且無(wú)上面的副作用)

ServiceWoker文件sw.js自身的更新

對(duì)sw.js不設(shè)置緩存贱呐,每次都到網(wǎng)絡(luò)請(qǐng)求最新sw.js文件即可(對(duì)于如何安裝更新sw.js,本文不探討)

具體實(shí)現(xiàn)

首屏加載

首屏資源請(qǐng)求流程
sw.js文件返回后入桂,請(qǐng)求最新資源流程

1. App緩存文件存放位置

image.png

2. 聲明攔截列表

private void initData() {
        // 主頁(yè)
        mMap.put(BaseUrl, "index.html");
        mMap.put(BaseUrl+"/", "index.html");
        mMap.put(BaseUrl + "/index.html", "index.html");
        // js文件
        mMap.put(BaseUrl + "/main-v1.js", "main.js");
        // css文件
        mMap.put(BaseUrl + "/static/css/main-v1.css", "static/css/main-v1.css");
        // 圖片
        mMap.put(BaseUrl + "/favicon.ico", "favicon.ico");
        mMap.put(BaseUrl + "/images/log.png", "images/log.png");
    }

3. App應(yīng)用攔截

            @TargetApi(VERSION_CODES.LOLLIPOP)
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view,
                    WebResourceRequest request) {
                String url = request.getUrl().toString();
                Log.d(TAG, "shouldInterceptRequest>5.0: url = " + url);
                if (!mIsLoadLocal) {

                    return super.shouldInterceptRequest(view, request);
                }
                if (mDataHelper.hasLocalResource(url)) {
                    Log.d(TAG, "shouldInterceptRequest>5.0: 資源命中:url="+url);
                    // super.shouldInterceptRequest(view, request); // 同時(shí)去請(qǐng)求網(wǎng)絡(luò)
                    WebResourceResponse response =
                            mDataHelper.getReplacedWebResourceResponse(getApplicationContext(),
                                    url);
                    if (response != null) {
                        return response;
                    }
                }
                return super.shouldInterceptRequest(view, request);
            }

第二次加載

第二次加載資源請(qǐng)求流程
ServiceWorker處理流程

之后的處理流程都是類(lèi)似的

說(shuō)明

1. 和http緩存結(jié)合使用

ServiceWorker中的請(qǐng)求奄薇,也會(huì)去http緩存中抓取的,所以可以結(jié)合使用抗愁,緩存策略:

  • index.html設(shè)定no-cache
  • 靜態(tài)資源文件緩存1年(通過(guò)每次打包后新版本號(hào)更新)
    以Nginx為例:
        location / {
            # root   html;
            root /Users/frru/nginxServers;
            index  index.html index.htm;
            autoindex on;               ##顯示索引  
            autoindex_exact_size on;    ##顯示大小
            autoindex_localtime on;     ##顯示時(shí)間
            if ($request_uri ~* ".html|htm") {
                add_header Cache-Control  "no-cache";
            }
            if ($request_uri ~* ".css|js|png") {
                expires 360d;
                # add_header Cache-Control "public, max-age=2592000, s-maxage=2592000";
                add_header wall  "hey!guys!give me a star.";
            }
        }

2. 每次項(xiàng)目打包時(shí)候馁蒂,請(qǐng)同步更新sw.js文件,主要是更新其中cacheAll部分文件列表

例如版本變?yōu)関2之后蜘腌,sw.js中cacheAll部分應(yīng)該為

//Service Worker安裝事件沫屡,其中可以預(yù)緩存資源
this.addEventListener('install', function(event) {
 console.log('install'); 
  //需要緩存的頁(yè)面資源
  var urlsToPrefetch = [
    './index.html',
    './main-v2.js',
    './static/css/main-v2.css',
    './static/image/log.png',
  ];

  event.waitUntil(
    caches.open(OFFLINE_CACHE_NAME).then(function(cache) {
      return cache.addAll(urlsToPrefetch);
    })
  );      
});

3. 注意:并未實(shí)踐

以上部分,關(guān)于sw.js部分的主動(dòng)更新文件撮珠,我并未實(shí)現(xiàn)調(diào)試沮脖,理論上可行。之前我是采取邊返還ServiceWorker緩存,邊請(qǐng)求最新數(shù)據(jù)的方案勺届,副作用上面已經(jīng)說(shuō)明了驶俊。

4. sw.js主動(dòng)更新文件和邊返回緩存,邊加載新資源免姿,可以結(jié)合使用

5. 關(guān)于緩存文件列表

現(xiàn)在打包工具一般都會(huì)生成靜態(tài)資源列表饼酿,例如Create React App打包項(xiàng)目會(huì)生成一個(gè)asset-manifest.json文件:

{
  "main.css": "./static/css/main.484bfb43.chunk.css",
  "main.js": "./static/js/main.a763f74c.chunk.js",
  "main.js.map": "./static/js/main.a763f74c.chunk.js.map",
  "runtime~main.js": "./static/js/runtime~main.9eb600ee.js",
  "runtime~main.js.map": "./static/js/runtime~main.9eb600ee.js.map",
  "static/css/2.81f174d0.chunk.css": "./static/css/2.81f174d0.chunk.css",
  "static/js/2.3caf1636.chunk.js": "./static/js/2.3caf1636.chunk.js",
  "static/js/2.3caf1636.chunk.js.map": "./static/js/2.3caf1636.chunk.js.map",
  "index.html": "./index.html",
  "precache-manifest.95764df349dcc4f784ad6dbed9254278.js": "./precache-manifest.95764df349dcc4f784ad6dbed9254278.js",
  "service-worker.js": "./service-worker.js",
  "static/css/2.81f174d0.chunk.css.map": "./static/css/2.81f174d0.chunk.css.map",
  "static/css/main.484bfb43.chunk.css.map": "./static/css/main.484bfb43.chunk.css.map"
}

App應(yīng)用可以利用,拉取靜態(tài)文件胚膊。
也可以用來(lái)生成ServiceWorker主動(dòng)獲取文件列表

騰訊VasSonic框架

簡(jiǎn)介:騰訊SNG增值產(chǎn)品部技術(shù)團(tuán)隊(duì)研發(fā)的輕量級(jí)高性能Hybrid框架VasSonic
官方介紹文檔

業(yè)務(wù)場(chǎng)景

主要是應(yīng)對(duì)手Q的業(yè)務(wù)嗜湃,一些重點(diǎn)常用業(yè)務(wù),例如游戲分發(fā)中心澜掩、會(huì)員特權(quán)中心购披、個(gè)性裝扮商場(chǎng)等,是H5頁(yè)面肩榕,首屏加載時(shí)候刚陡,會(huì)比較慢。
隨著業(yè)務(wù)發(fā)展株汉,有些業(yè)務(wù)形態(tài)發(fā)生了變化筐乳,例如個(gè)性推薦是動(dòng)態(tài)內(nèi)容。

解決方案

VasSonic的前身

  1. 終端優(yōu)化
    一些常見(jiàn)的首頁(yè)優(yōu)化:懶加載乔妈、X5內(nèi)核預(yù)加載蝙云、WebView對(duì)象復(fù)用
  2. 靜態(tài)直出
  3. 離線預(yù)推(即熟悉的離線包)
    VasSonic做了功能增強(qiáng),即離線增量包路召,大大減少了包大小勃刨。
  4. 動(dòng)態(tài)直出功能
    因?yàn)闃I(yè)務(wù)形態(tài)發(fā)生了變化(個(gè)性推薦),做了對(duì)應(yīng)的功能股淡。
    實(shí)時(shí)拉取用戶數(shù)據(jù)并在服務(wù)端渲染后返回給客戶端身隐,也就是動(dòng)態(tài)直出的方案。
  5. webso的嘗試
    QQ空間技術(shù)團(tuán)隊(duì)在解決動(dòng)態(tài)直出方面的wns+html解決方案唯灵。不太適合手Q業(yè)務(wù)場(chǎng)景贾铝。有一定的借鑒參考。

綜上埠帕,不管改進(jìn)下垢揩,最后誕生了VasSonic。

VasSonic的誕生

  1. 并行加載
    就是把WebView初始化和請(qǐng)求資源由原來(lái)的串行改成并行敛瓷,減少等待時(shí)間叁巨。
  2. 動(dòng)態(tài)緩存
    把頁(yè)面拆分成靜態(tài)部分和動(dòng)態(tài)部分,動(dòng)態(tài)部分更新后去主動(dòng)更新界面琐驴。
  3. 頁(yè)面分離
    對(duì)上面動(dòng)態(tài)緩存的具體實(shí)現(xiàn)

后面的小章節(jié)都是具體使用VasSonic的規(guī)范俘种。

?绝淡?宙刘?

VasSonic預(yù)加載

這兩種方式感覺(jué)都是針對(duì)手Q業(yè)務(wù)場(chǎng)景,在用戶打開(kāi)手Q時(shí)候牢酵,預(yù)加載一些重要頁(yè)面和預(yù)判頁(yè)面悬包。

騰訊瀏覽服務(wù) Service Worker最佳實(shí)踐

官文

ServiceWorker的不用講了,這里關(guān)于首屏的加載馍乙,比較狠布近,直接打成壓縮文件,讓x5內(nèi)核注冊(cè)成ServiceWorker丝格,省去了用戶需要打開(kāi)頁(yè)面才能注冊(cè)ServiceWorker的過(guò)程撑瞧。

X5內(nèi)核Service Worker功能擴(kuò)展

首次訪問(wèn)解決方案

首次訪問(wèn)解決方案旨在用戶訪問(wèn)業(yè)務(wù)前實(shí)現(xiàn)業(yè)務(wù)的資源緩存,讓用戶在第一次真正訪問(wèn)業(yè)務(wù)時(shí)能夠讓業(yè)務(wù)頁(yè)面以最快的速度展示出來(lái)显蝌。針對(duì)該主旨预伺,X5內(nèi)核實(shí)現(xiàn)了三套具體實(shí)現(xiàn)方案:

  1. 離線包方式
  2. X5內(nèi)核后臺(tái)云下發(fā)指令
  3. X5內(nèi)核擴(kuò)展接口
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市曼尊,隨后出現(xiàn)的幾起案子酬诀,更是在濱河造成了極大的恐慌,老刑警劉巖骆撇,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞒御,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡神郊,警方通過(guò)查閱死者的電腦和手機(jī)肴裙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涌乳,“玉大人践宴,你說(shuō)我怎么就攤上這事∫常” “怎么了阻肩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)运授。 經(jīng)常有香客問(wèn)我烤惊,道長(zhǎng),這世上最難降的妖魔是什么吁朦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任柒室,我火速辦了婚禮,結(jié)果婚禮上逗宜,老公的妹妹穿的比我還像新娘雄右。我一直安慰自己空骚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布擂仍。 她就那樣靜靜地躺著囤屹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逢渔。 梳的紋絲不亂的頭發(fā)上肋坚,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音肃廓,去河邊找鬼智厌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛盲赊,可吹牛的內(nèi)容都是我干的铣鹏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼哀蘑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吝沫!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起递礼,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤惨险,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后脊髓,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辫愉,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年将硝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恭朗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡依疼,死狀恐怖痰腮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情律罢,我是刑警寧澤膀值,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站误辑,受9級(jí)特大地震影響沧踏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巾钉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一翘狱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧砰苍,春花似錦潦匈、人聲如沸阱高。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赤惊。三九已至,卻和暖如春寒屯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背黍少。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工寡夹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厂置。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓菩掏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親昵济。 傳聞我的和親對(duì)象是個(gè)殘疾皇子智绸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345