背景

京東App在2019年做了一輪瘦身,當(dāng)時(shí)做了全方位的瘦身,但隨著業(yè)務(wù)快速迭代和新技術(shù)框架引入以及管控力度不足,安裝包體積出現(xiàn)了反彈。結(jié)合之前治而未管和業(yè)內(nèi)一些同行的瘦身經(jīng)驗(yàn),本文介紹此次瘦身過(guò)程積累的一些實(shí)踐經(jīng)驗(yàn)以及管控方案。首先拆分安裝包梳理數(shù)據(jù),將安裝包的成份數(shù)據(jù)做成線上化看板,根據(jù)數(shù)據(jù)找出安裝包體積增長(zhǎng)主要因素,結(jié)合京東App現(xiàn)狀進(jìn)行了一系列綜合性的瘦身動(dòng)作,也沉淀了一套新的管控規(guī)范及管控平臺(tái),最終實(shí)現(xiàn)了安裝包體積下降30%以上。

安裝包成份分析

瘦身未動(dòng),“數(shù)據(jù)”先行,包瘦身的第一步是要分析出App組成成份的大小數(shù)據(jù),為包瘦身的目標(biāo)設(shè)定及任務(wù)拆解提供數(shù)據(jù)支撐,達(dá)到可度量、線上化、統(tǒng)一數(shù)據(jù)標(biāo)準(zhǔn)的目的。如何進(jìn)行安卓App的包成份分析?安卓開(kāi)發(fā)者基本都會(huì)用到Android Studio自帶的Apk Analyzer工具,將Apk文件拖入Android Studio中即可查看,下圖是京東App拖入Android Studio中顯示的包大小數(shù)據(jù),可以清晰的看出包體積里占比較大的主要是lib(存放動(dòng)態(tài)庫(kù)及安卓插件)、r(存放圖片、xml等資源)、assets目錄、dex和resources.arsc(資源映射表)幾類文件。

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

apk Analyzer工具對(duì)于初步的、特定的包大小數(shù)據(jù)查看非常方便,但是對(duì)于需要進(jìn)行的包瘦身項(xiàng)目來(lái)看,數(shù)據(jù)過(guò)于籠統(tǒng),沒(méi)有按模塊維度進(jìn)行劃分,無(wú)法將包瘦身責(zé)任劃分給對(duì)應(yīng)的研發(fā)團(tuán)隊(duì),不便于后續(xù)包瘦身項(xiàng)目的具體實(shí)施。為了度量各模塊對(duì)包大小的影響,我們需要一套精細(xì)化的包大小分析方案。

首先來(lái)看一下京東App的工程結(jié)構(gòu),簡(jiǎn)化模型如下圖所示。京東App整體采用了插件化的架構(gòu),開(kāi)發(fā)迭代過(guò)程中逐漸按照功能、業(yè)務(wù)類型拆分成了很多模塊,各模塊有獨(dú)立的項(xiàng)目工程、倉(cāng)庫(kù),日常進(jìn)行獨(dú)立的開(kāi)發(fā)維護(hù),最終集成在Application工程中。功能型的模塊基本上是以library依賴的形式引入到工程中的,比如常用的網(wǎng)絡(luò)庫(kù)、圖片庫(kù)、埋點(diǎn)庫(kù)等;業(yè)務(wù)型的模塊大多是以插件的形式存在,比如搜索、商詳、購(gòu)物車(chē)等;此外主工程中還存在少部分未拆分成模塊的歷史遺留邏輯,在日常迭代中占比非常少。

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

基于京東App模塊化的現(xiàn)狀,安裝包的成份分析可以從三個(gè)方面進(jìn)行:分析包成份的總覽數(shù)據(jù)、分析插件數(shù)據(jù)和分析library數(shù)據(jù)。

01

Apk總覽數(shù)據(jù)分析

安卓的包產(chǎn)物apk文件本質(zhì)上是一個(gè)zip文件,可以用zipinfo命令輸出壓縮包中每個(gè)文件的詳細(xì)信息日志,用法:

Zipinfo -l --t --h  xxxx.apk > xxxx.txt

輸出的日志文件打開(kāi)如下圖,每個(gè)文件的壓縮信息一行,包括文件名、原始大小、壓縮后大小等指標(biāo)。

對(duì)以上日志信息進(jìn)行逐行解析,根據(jù)解混淆后的文件名路徑、文件類型進(jìn)行歸類統(tǒng)計(jì),即可得出apk的總覽信息,包括各類型文件的數(shù)量、總大小、單一文件大小等指標(biāo),并建立文件大小索引。

02

插件數(shù)據(jù)分析

插件產(chǎn)物的本質(zhì)也是apk,目前京東App的預(yù)裝插件有50+,App打包時(shí)各插件會(huì)以.so為后綴的形式放在lib目錄中。對(duì)插件的分析可以直接基于包產(chǎn)物進(jìn)行,解析時(shí)只需要將apk解壓開(kāi)來(lái),按照文件名特征將插件從全部so文件中分離出來(lái),逐一按照上述zipinfo相同方法進(jìn)行解析即可。

03

library數(shù)據(jù)分析

各library模塊大多是以aar/jar依賴的形式引入到項(xiàng)目工程中,目前京東App的全部項(xiàng)目依賴庫(kù)有300+,包括直接依賴、間接依賴。對(duì)library數(shù)據(jù)的分析主要是在分析各依賴對(duì)包大小的影響和分析維護(hù)開(kāi)發(fā)者兩個(gè)方面。

01

分析依賴對(duì)包大小影響

安卓工程在構(gòu)建時(shí),Gradle構(gòu)建工具會(huì)自動(dòng)將依賴庫(kù)同步緩存到本地,與工程中的代碼資源一起編譯merge最終輸出apk。通過(guò)編寫(xiě)gradle腳本任務(wù)在構(gòu)建過(guò)程中可以取到aar/jar依賴文件,但是考慮到分析工具的獨(dú)立性,盡量避免和打包流程耦合在一起,采用了自行解析依賴的方式來(lái)實(shí)現(xiàn),整體流程如下:

a. 打包過(guò)程中執(zhí)行g(shù)radle命令生成app運(yùn)行時(shí)依賴樹(shù)日志文件,用法:

./gradlew:app:dependencies--configuration xxxReleaseRuntimeClasspath > dep.txt

生成的日志文件部分如下:

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

b.解析日志文件生成N叉樹(shù)模型,每一行日志生成一個(gè)依賴節(jié)點(diǎn),包含groupId、artifact_name、version信息,日志中的->表示版本沖突取高版本,(*)表示重復(fù)依賴,在application和common_library中添加的依賴為直接依賴,對(duì)應(yīng)根節(jié)點(diǎn)和common_library節(jié)點(diǎn)的子節(jié)點(diǎn),其它節(jié)點(diǎn)為間接依賴。

c.將N叉樹(shù)扁平化去重逐一解析依賴,下載aar/jar文件。解析過(guò)程中拼接url輪詢倉(cāng)庫(kù),為了加快解析速度,可以根據(jù)依賴的groupId區(qū)分依賴的來(lái)源,如果是jd內(nèi)部的依賴,則優(yōu)先請(qǐng)求內(nèi)部的私服,否則優(yōu)先訪問(wèn)常用的鏡像倉(cāng)庫(kù)。此外可以加入LRU緩存機(jī)制,本地存在的依賴產(chǎn)物不再請(qǐng)求倉(cāng)庫(kù),進(jìn)一步加快解析速度。存在的一個(gè)潛在問(wèn)題是快照版本的依賴會(huì)對(duì)應(yīng)多個(gè)產(chǎn)物,解析時(shí)取的最新版本可能和app構(gòu)建時(shí)用的不是同一個(gè),通常發(fā)版分支上的依賴被規(guī)定不能用快照版本,所以這個(gè)問(wèn)題也就間接規(guī)避了。

d. aar也是一種zip文件,同樣可以用zipinfo命令來(lái)解析組成成份大小,建立內(nèi)部jar、so、圖片、xml、asset等文件的索引。

e.將aar內(nèi)部的各文件根據(jù)名稱與總覽數(shù)據(jù)分析時(shí)建立的文件大小索引進(jìn)行關(guān)聯(lián),即可知道aar內(nèi)部的so、圖片、xml、asset等文件最終在apk壓縮包里的大小。由于代碼文件jar最終經(jīng)過(guò)編譯、刪減、混淆merge成了dex,無(wú)法精確的溯源,代碼部分的大小計(jì)算采用了原始大小按比例折算的方式進(jìn)行。折算比例是實(shí)驗(yàn)去掉比較獨(dú)立的依賴后打包看包大小的差值,去除非代碼部分的大小后,即可算出代碼部分的折算比例,重復(fù)N次去除不同的依賴取平均值。

02

分析模塊負(fù)責(zé)人

前述京東App有300+依賴,由于業(yè)務(wù)調(diào)整、人員變動(dòng)等原因沒(méi)有一個(gè)統(tǒng)一的library維護(hù)關(guān)系數(shù)據(jù)。對(duì)于直接依賴部分,初期通過(guò)git blame 命令輸出app、common_library工程的build.gradle文件修改記錄日志,正則匹配出依賴和維護(hù)者的對(duì)應(yīng)關(guān)系;對(duì)于間接依賴部分,將前述N叉樹(shù)的每一個(gè)間接依賴節(jié)點(diǎn),向上尋找它的父節(jié)點(diǎn)直到直接依賴節(jié)點(diǎn),則直接依賴的開(kāi)發(fā)者也是此間接依賴引入的責(zé)任人,會(huì)存在多個(gè)直接依賴引用了同一個(gè)間接依賴的情形,即某個(gè)間接依賴庫(kù)對(duì)應(yīng)多個(gè)引入責(zé)任人。

通過(guò)上述分析方案,已經(jīng)可以完整的分析出安裝包的各成份大小及對(duì)應(yīng)的負(fù)責(zé)人,為瘦身工作的實(shí)施提供了數(shù)據(jù)指引。分析方案全部是用python腳本的方式實(shí)現(xiàn),已集成到公司內(nèi)部的CD系統(tǒng),數(shù)據(jù)看板效果如下。

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

京東App的開(kāi)發(fā)者團(tuán)隊(duì)規(guī)模較大,在安裝包成份數(shù)據(jù)線上化建設(shè)完成后,所有開(kāi)發(fā)者統(tǒng)一了看數(shù)標(biāo)準(zhǔn)和渠道,每個(gè)App版本的增長(zhǎng)與下降也可以歸因到具體模塊級(jí)別以及對(duì)應(yīng)的開(kāi)發(fā)者,同時(shí)這個(gè)數(shù)據(jù)分析看板也為瘦身的度量和管控提供了基礎(chǔ)數(shù)據(jù)能力。根據(jù)數(shù)據(jù)分析我們發(fā)現(xiàn)App內(nèi)資源文件、ReactNative、插件的數(shù)量和體積都比較大,所以瘦身重點(diǎn)圍繞這幾方面進(jìn)行專項(xiàng)治理,同時(shí)基于之前瘦身出現(xiàn)過(guò)反彈的教訓(xùn),分析發(fā)現(xiàn)在過(guò)往開(kāi)發(fā)迭代中缺乏約束管控,技術(shù)選型和研發(fā)復(fù)用也暴露了部分問(wèn)題,因此制定了精細(xì)化的管控規(guī)范并在研測(cè)流程中落地實(shí)施。

瘦身方案

借鑒業(yè)內(nèi)的瘦身措施,結(jié)合京東App自身特性制定了瘦身方案,首先進(jìn)行了常規(guī)化瘦身舉措主要包括壓縮資源、內(nèi)置ReactNative轉(zhuǎn)為下載、插件轉(zhuǎn)下載、R8編譯升級(jí)等,其次對(duì)App內(nèi)的圖片進(jìn)行專項(xiàng)治理,構(gòu)建了圖片管理平臺(tái),最終使安卓安裝包體積下降了近30%+,包體積瘦身趨勢(shì)圖如下圖。

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

01

瘦身措施

  • 插件轉(zhuǎn)下載

京東mPaaS平臺(tái)提供了安卓端插件轉(zhuǎn)下載安裝的能力,2022年初我們協(xié)同mPaaS團(tuán)隊(duì)、運(yùn)維團(tuán)隊(duì)共同對(duì)其進(jìn)行優(yōu)化提升了其可用性和穩(wěn)定性。將下載器的unknown host問(wèn)題解決,加入了httpdns能力,支持切換域名能力等,運(yùn)維團(tuán)隊(duì)通過(guò)撥測(cè)解決某些cdn節(jié)點(diǎn)異常導(dǎo)致的文件md5不一致問(wèn)題,最終在真實(shí)用戶網(wǎng)絡(luò)環(huán)境下平均單次下載網(wǎng)絡(luò)請(qǐng)求成功率在98%以上,由于在用戶進(jìn)入頁(yè)面前存在多次觸發(fā)下載的機(jī)會(huì),進(jìn)入頁(yè)面而未加載成功場(chǎng)景的概率在十萬(wàn)分之4以下,此概率已低于App的崩潰率,體驗(yàn)上已完全可以保障,實(shí)踐過(guò)程中也未出現(xiàn)用戶體驗(yàn)異常反饋。通過(guò)業(yè)務(wù)模塊的uv進(jìn)行倒排序,最終甄選了10+插件進(jìn)行了轉(zhuǎn)下載安裝。

  • RN內(nèi)置包轉(zhuǎn)下載

在優(yōu)化之初,京東大部分用React Native開(kāi)發(fā)的業(yè)務(wù)模塊均采用內(nèi)置App的方式,峰值數(shù)量達(dá)到50+個(gè)。聯(lián)合mPaaS團(tuán)隊(duì)進(jìn)行優(yōu)化,最初評(píng)估采用Brotli壓縮本地內(nèi)置包,經(jīng)評(píng)估其解壓耗時(shí)是gzip的2倍,內(nèi)存使用是幾十至幾百倍,最終放棄這個(gè)方案。統(tǒng)一采用了將內(nèi)置包轉(zhuǎn)下載安裝的方案,通過(guò)拆分基礎(chǔ)包和業(yè)務(wù)包將JSBundle體積縮小,設(shè)置了預(yù)下載非強(qiáng)制更新、預(yù)下載強(qiáng)制更新以及增加某個(gè)RN業(yè)務(wù)打開(kāi)則觸發(fā)其他未下載業(yè)務(wù)下載等策略有效提升了單周新版更新覆蓋率,提供h5降級(jí)、統(tǒng)一兜底降級(jí)等多重兜底體驗(yàn),最終提升了RN相關(guān)能力的穩(wěn)定性和可用性,保障了用戶體驗(yàn),目前內(nèi)置的RN業(yè)務(wù)模塊數(shù)已經(jīng)降至個(gè)位數(shù)。

  • 資源壓縮

針對(duì)圖片壓縮,借助集成TinyPNG壓縮工具對(duì)10K以上的圖片進(jìn)行壓縮;受限于Android工程minSdkVersion=16,不能將所有的png圖片都轉(zhuǎn)成webp格式,只能將無(wú)透明通道的圖片轉(zhuǎn)成webp。后期對(duì)包大小更嚴(yán)格的要求,可以考慮將圖片遠(yuǎn)程化。

  • iconfont

借助瘦身腳本分析工具掃描安裝包中方正純色的小圖片轉(zhuǎn)成iconfont,包內(nèi)掃描出800多張可轉(zhuǎn)成iconfont,數(shù)量較多需要長(zhǎng)期治理,雖然收益不明顯但利于各個(gè)業(yè)務(wù)零散的小圖標(biāo)進(jìn)行統(tǒng)一管理,同時(shí)有利于App整體視覺(jué)風(fēng)格的統(tǒng)一。

  • R文件內(nèi)聯(lián)

通過(guò)自定義Gradle插件利用ASM對(duì)class文件進(jìn)行字節(jié)碼操作,將class文件中引用到R類資源id替換成對(duì)應(yīng)的常量值并刪除R文件,達(dá)到減少包體積的目的。由于京東App采用插件化的方式開(kāi)發(fā)業(yè)務(wù),每個(gè)業(yè)務(wù)插件都會(huì)引用公共資源,不能簡(jiǎn)單的將公共資源id添加到白名單中,所以結(jié)合京東App插件化方案(aura)的公共資源id固定的能力,實(shí)現(xiàn)插件化工程中的公共資源內(nèi)聯(lián)。目前開(kāi)啟R文件內(nèi)聯(lián)已完成灰度,后續(xù)會(huì)陸續(xù)上線,包體積整體收益5.5MB以上。

  • 開(kāi)啟R8編譯

隨Target31適配升級(jí)AGP到4.1版本,同步開(kāi)啟了R8編譯,需要注意R8會(huì)忽略部分Proguard混淆規(guī)則,針對(duì)R8編譯對(duì)混淆規(guī)則的變更點(diǎn),編寫(xiě)了mapping文件檢測(cè)腳本工具,對(duì)Proguard和R8編譯生成的mapping混淆文件進(jìn)行對(duì)比,檢測(cè)網(wǎng)絡(luò)解析、反射相關(guān)的類是否添加了正確的混淆規(guī)則,利用工具保障了升級(jí)R8編譯后App的穩(wěn)定性。R8編譯對(duì)代碼混淆優(yōu)化效果要優(yōu)于Proguard,開(kāi)啟R8后,包體積減少1.6MB,構(gòu)建耗時(shí)也降低30%(3min)以上。

  • 7Zip壓縮

7Zip兼容Zip格式,支持Zip的Deflate算法,使用7zip極限壓縮模式比Android打包默認(rèn)的zip壓縮率高,可以將加固好的apk文件進(jìn)行7zip解壓縮后重新簽名,包體積降低約2.2%(2MB)。為了驗(yàn)證其穩(wěn)定性與可用性,計(jì)劃對(duì)內(nèi)部和外部市場(chǎng)都分別進(jìn)行灰度,通過(guò)京東內(nèi)部灰度渠道已灰度完成,對(duì)外部的各個(gè)渠道將包直接投遞到渠道,如小米、華為等在灰度進(jìn)行中。

在完成這些常規(guī)瘦身方案優(yōu)化后,App安裝包大小依舊較大。先前圖片資源優(yōu)化主要是通過(guò)圖片壓縮、使用一套分辨率xhdpi圖片、圖片轉(zhuǎn)webp、資源名混淆等方式進(jìn)行,這些優(yōu)化方式都是將內(nèi)置的圖片進(jìn)行瘦身優(yōu)化,隨著業(yè)務(wù)功能的不斷迭代,瘦身收益將越來(lái)越少。京東App各個(gè)業(yè)務(wù)的開(kāi)發(fā)方式是以插件化的形式進(jìn)行,通過(guò)對(duì)這些業(yè)務(wù)插件包的分析,發(fā)現(xiàn)這些業(yè)務(wù)模塊中內(nèi)置的圖片資源大小占各自插件包總大小的25%以上,針對(duì)內(nèi)置圖片資源過(guò)多問(wèn)題,提出一種圖片資源遠(yuǎn)程化的優(yōu)化方案。

02

圖片資源遠(yuǎn)程化

直接將圖片資源轉(zhuǎn)成在線加載可能會(huì)影響用戶體驗(yàn),將內(nèi)置的圖片資源從App應(yīng)用內(nèi)剝離,然后將圖片上傳到CDN獲取到圖片的網(wǎng)絡(luò)鏈接,應(yīng)用通過(guò)加載圖片鏈接進(jìn)行在線加載的方式來(lái)展示圖片,在線加載圖片需要經(jīng)過(guò)下載圖片的過(guò)程,考慮到用戶所處的網(wǎng)絡(luò)環(huán)境受多種因素的影響,常使用默認(rèn)的兜底圖在圖片展示區(qū)域進(jìn)行占位,或者使用全屏的加載中動(dòng)畫(huà)進(jìn)行過(guò)渡等方式來(lái)優(yōu)化用戶體驗(yàn)。從優(yōu)化用戶體驗(yàn)角度出發(fā),提出一種2層網(wǎng)絡(luò)加載+3層降級(jí)措施的優(yōu)化方案,可以提高網(wǎng)絡(luò)圖片的加載成功率,同時(shí)給用戶展示圖片的體驗(yàn)如同加載應(yīng)用內(nèi)置圖片資源一樣,整體方案如下:

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

該優(yōu)化方案主要由圖片管理CMS平臺(tái)和獲取圖片信息的客戶端組件組成,由業(yè)務(wù)研發(fā)在CMS配置各自模塊的圖片信息,客戶端通過(guò)組件獲取圖片地址展示圖片。

01

CMS圖片管理

  1. CMS支持圖片類型包括png、jgp、webp、點(diǎn)9圖等,由業(yè)務(wù)模塊梳理出內(nèi)置的圖片素材;
  2. CMS以用戶為單位,創(chuàng)建業(yè)務(wù)模塊,在模塊內(nèi)上傳圖片獲取圖片CDN鏈接,提供2x、3x兩個(gè)分辨率設(shè)置,同時(shí)可以設(shè)置圖片在客戶端生效的版本范圍以及生效平臺(tái)Android或iOS;
  3. CMS提供將圖片打包成zip壓縮包的功能,在用戶上傳完圖片后,會(huì)根據(jù)各個(gè)圖片生效的客戶端版本區(qū)間,生成不同版本區(qū)間以及2x、3x兩種分辨率的zip包,會(huì)根據(jù)客戶端請(qǐng)求接口中的分辨率參數(shù)下發(fā)不同分辨率的zip包鏈接;
  4. CMS提供zip包的預(yù)加載策略,分為App啟動(dòng)時(shí)預(yù)加載、App首頁(yè)加載成功后x秒開(kāi)始預(yù)加載、進(jìn)入某頁(yè)面時(shí)預(yù)加載等;
  5. 用戶根據(jù)前面步驟配置完成后,將業(yè)務(wù)模塊內(nèi)的圖片名和對(duì)應(yīng)的CDN鏈接組成配置信息由CMS導(dǎo)出,然后將該配置信息文件內(nèi)置到客戶端,提供跟隨安裝包的兜底體驗(yàn)。

02

客戶端圖片預(yù)加載與緩存

  1. 客戶端組件在App啟動(dòng)時(shí)請(qǐng)求CMS后臺(tái)提供的查詢接口,獲取當(dāng)前客戶端版本對(duì)應(yīng)的配置信息,與本地兜底配置信息進(jìn)行比較,得到的差分信息進(jìn)行本地持久化;
  2. 客戶端組件同時(shí)解析后臺(tái)接口下發(fā)的圖片zip包信息,根據(jù)zip包的預(yù)加載策略下載對(duì)應(yīng)的圖片zip包,下載完成后解壓到以模塊名命名的本地文件夾中;
  3. 當(dāng)展示圖片時(shí),客戶端組件根據(jù)模塊ID+圖片ID優(yōu)先查詢本地zip包解壓目錄中該圖片是否已存在,如果該圖片已下載,則直接返回該圖片的本地路徑path,客戶端直接使用該本地路徑path展示圖片;如果該圖片還未下載完成,或不存在,則從內(nèi)置的配置信息文件中獲取該圖片的CDN鏈接,同之前一樣加載圖片的網(wǎng)絡(luò)鏈接;如果加載該網(wǎng)絡(luò)鏈接還是失敗,則展示默認(rèn)的兜底圖。

該優(yōu)化方案中,2層網(wǎng)絡(luò)加載的第一層網(wǎng)絡(luò)加載是指業(yè)務(wù)模塊的zip包,下載一次多版本復(fù)用;第二層網(wǎng)絡(luò)加載是指圖片zip包預(yù)加載未完成或失敗時(shí),通過(guò)安裝包中內(nèi)置的圖片CDN鏈接兜底配置信息加載圖片網(wǎng)絡(luò)鏈接來(lái)展示圖片,該兜底配置信息以圖片名+圖片CDN鏈接鍵值對(duì)的形式保存。

3層降級(jí)措施的第一層降級(jí)是獲取圖片zip包預(yù)加載的本地緩存圖片;第二層降級(jí)是當(dāng)本地圖片緩存失效時(shí),獲取內(nèi)置的圖片CDN鏈接加載;第三層降級(jí)則是默認(rèn)的兜底圖。瘦身業(yè)務(wù)模塊開(kāi)啟圖片zip預(yù)加載功能時(shí),CMS支持業(yè)務(wù)模塊設(shè)置zip包預(yù)加載策略,業(yè)務(wù)模塊根據(jù)實(shí)際情況選擇不同的加載策略,例如某些業(yè)務(wù)模塊頁(yè)面入口比較深,這些業(yè)務(wù)模塊就可以選擇用戶在進(jìn)入頁(yè)面時(shí)觸發(fā)zip包的預(yù)加載;

某些業(yè)務(wù)模塊進(jìn)入頁(yè)面入口比較淺就可以設(shè)置App啟動(dòng)后空閑時(shí)預(yù)加載,其他二級(jí)、三級(jí)的頁(yè)面可以設(shè)置App啟動(dòng)后x秒(隨機(jī)時(shí)間)才開(kāi)始下載。通過(guò)設(shè)置這些預(yù)加載策略,將圖片zip包分散在不同時(shí)間段下載,降低圖片加載時(shí)的網(wǎng)絡(luò)流量峰值。

上述方案需要業(yè)務(wù)研發(fā)積極配合,需要業(yè)務(wù)模塊額外通過(guò)固定的模塊ID+圖片ID優(yōu)先獲取本地緩存的方式加載圖片,使用過(guò)程較繁瑣,缺乏靈活性,為方便開(kāi)發(fā)者更容易使用,提供更多選擇,降低接入成本,我們?cè)贑MS和客戶端作了些改進(jìn),又提出了下面的優(yōu)化方案:

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

  • 圖片CMS變更點(diǎn)

CMS后臺(tái)對(duì)圖片zip打包做額外處理:取圖片CDN鏈接中固定路徑計(jì)算MD5值,并將該MD5值重命名圖片名稱,不保留圖片類型后綴。例如鏈接:https://xxx/jfs/xxx/name.png,對(duì)鏈接中jfs開(kāi)頭和.png之間的路徑字符串進(jìn)行MD5值計(jì)算:MD5(/jfs/xxx/name) =MD5-Value ,以該MD5-Value值作為圖片名稱,并且移除圖片類型后綴名(.png等), 其他圖片同樣按照該步驟進(jìn)行重命名,最后打包成以模塊名命名的圖片壓縮包。

  • 客戶端變更點(diǎn)

提供一個(gè)工具類,以模塊名和圖片CDN鏈接作為入?yún)ⅲ瑢?duì)圖片CDN鏈接進(jìn)行相同的處理,獲取CDN鏈接中固定路徑字符串的MD5值,然后根據(jù)模塊名和MD5值查找該圖片本地緩存是否已存在,即圖片zip包預(yù)加載是否成功,如果圖片已成功緩存則將該圖片的緩存路徑(file://協(xié)議)返回給圖片加載框架,如果圖片緩存不存在,則原樣返回圖片CDN鏈接(http://協(xié)議)。同樣也可以結(jié)合圖片加載框架實(shí)現(xiàn),新增以業(yè)務(wù)模塊名作為別名的圖片加載屬性,該別名屬性就是業(yè)務(wù)模塊圖片緩存本地的目錄,如果設(shè)置了該屬性,圖片加載框架就會(huì)優(yōu)先判斷該圖片是否已緩存成功,若圖片已緩存成功,則通過(guò)本地路徑展示圖片,若緩存未成功,則直接在線加載圖片,該方案需要客戶端圖片加載框架同時(shí)支持file協(xié)議和http協(xié)議。該方案也可以應(yīng)用于大促等場(chǎng)景的圖片預(yù)加載。

通過(guò)埋點(diǎn)數(shù)據(jù)查看zip包預(yù)加載成功率,圖片zip包預(yù)加載在配置首頁(yè)啟動(dòng)后x秒下載,iOS端的zip包加載成功率在98.9%~99.1%波動(dòng),Android端的zip加載成功率在96.7%~98.1%波動(dòng),剩余1%~3%的用戶則通過(guò)內(nèi)置的兜底cdn鏈接在線加載,倆者結(jié)合展示圖片的成功率接近100%;客戶端從本地緩存加載圖片的效率要高于從網(wǎng)絡(luò)在線加載圖片,省去了等待圖片下載的過(guò)程,降低了默認(rèn)兜底圖的展示概率,在體驗(yàn)上接近于本地內(nèi)置圖片加載的效果。

管控

京東App在2019年專項(xiàng)瘦身后經(jīng)過(guò)一段時(shí)間又反彈了50%,一方面因?yàn)闃I(yè)務(wù)快速迭代發(fā)展以及新引入了一些比較大的基礎(chǔ)庫(kù),另一方面原因就是重點(diǎn)做了瘦身治理卻沒(méi)有深入做管控準(zhǔn)入防止劣化。因此在新一輪瘦身優(yōu)化過(guò)程中,我們一邊做瘦身治理,一邊在探索常態(tài)化的管控機(jī)制,最終沉淀了一套管控規(guī)范和管控平臺(tái)。

管控的目的不是為了限制需求迭代與增加代碼,目的是做好把控讓合理的代碼放進(jìn)來(lái),不合理的拒絕掉以及淘汰陳舊的代碼,提升開(kāi)發(fā)者們的瘦身意識(shí)。管控對(duì)產(chǎn)研全鏈路提出了新的要求,對(duì)于以往粗放型的需求開(kāi)發(fā)迭代方式會(huì)有所約束,產(chǎn)品側(cè)需要及時(shí)的配合研發(fā)側(cè)將ABTest的廢棄實(shí)驗(yàn)代碼下線,研發(fā)側(cè)需要做好技術(shù)規(guī)劃和技術(shù)選型,盡可能的精簡(jiǎn)代碼和復(fù)用代碼,加強(qiáng)技術(shù)團(tuán)隊(duì)之間的協(xié)同,不放置過(guò)大或冗余的資源文件等。

管控的前提是基于App已經(jīng)充分的組件化解耦,且App開(kāi)發(fā)人員規(guī)模相對(duì)比較大,比如京東App當(dāng)前安卓端是由業(yè)務(wù)插件和AAR依賴庫(kù)組成。App的組成成份整體上是由一個(gè)配置表來(lái)表示,配置表內(nèi)描述所有組件的配置版本信息,一個(gè)組件是否允許集成到App內(nèi)的前提是這個(gè)組件體積增長(zhǎng)大小符合我們制定的規(guī)范,然后組件的最新版本才可以集成到配置表內(nèi)。我們管控的核心機(jī)制就是控制配置表的更新集成權(quán)限,以此來(lái)約束每個(gè)組件的開(kāi)發(fā)者,通過(guò)App架構(gòu)師委員會(huì)(京東內(nèi)由架構(gòu)師形成的虛擬組織)制定的公共管控規(guī)范來(lái)評(píng)判每個(gè)組件體積增長(zhǎng)是否合規(guī),合規(guī)則準(zhǔn)入更新配置表,否則走異常申請(qǐng)流程。

01

管控流程與方案

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

管控流程是伴隨著開(kāi)發(fā)、測(cè)試、發(fā)布整個(gè)流程進(jìn)行的,整體的流程如圖所示。開(kāi)發(fā)者開(kāi)發(fā)完成后,由開(kāi)發(fā)者在京東內(nèi)部的組件構(gòu)建與發(fā)布平臺(tái)(mPaaS)發(fā)布形成新的組件版本,在構(gòu)建完成后開(kāi)發(fā)者在打包平臺(tái)(Bamboo)基于臨時(shí)配置表進(jìn)行打包并提測(cè),在此過(guò)程中會(huì)基于包計(jì)算出對(duì)應(yīng)組件的體積變化數(shù)據(jù),同時(shí)打包系統(tǒng)會(huì)以郵件形式將數(shù)據(jù)同步至開(kāi)發(fā)者,盡可能前置的告知開(kāi)發(fā)者是否存在不合規(guī);

測(cè)試通過(guò)后開(kāi)發(fā)者申請(qǐng)集成組件版本信息至配置表,若合規(guī)則更新配置表且流程結(jié)束,若不合規(guī)開(kāi)發(fā)者可以進(jìn)行代碼優(yōu)化后在申請(qǐng)集成,或者申請(qǐng)異常審批流程至App架構(gòu)師委員會(huì)。常規(guī)的業(yè)務(wù)迭代大部分不會(huì)出現(xiàn)違規(guī),但也會(huì)存在部分異常的情況,異常的處理往往會(huì)產(chǎn)生較多的爭(zhēng)議,研發(fā)的安裝包體積管控需要頂住產(chǎn)品和業(yè)務(wù)的壓力,異常處理的流程需要客觀、透明、靈活,異常處理流程如圖所示。

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

某個(gè)組件違規(guī)了發(fā)起申請(qǐng),對(duì)于三方庫(kù)、國(guó)家要求的隱私整改、安卓系統(tǒng)升級(jí)適配等情況,可以審核準(zhǔn)許通過(guò),其他一些特殊情況也可以通過(guò),由App架構(gòu)師委員會(huì)來(lái)酌情把控。對(duì)于一些正常情況下產(chǎn)生了組件體積增長(zhǎng)超限違規(guī),短期無(wú)法優(yōu)化瘦回可以申請(qǐng)?jiān)O(shè)置未來(lái)n個(gè)版本后瘦回,或者A組件協(xié)商B、C組件來(lái)協(xié)助分擔(dān)瘦回,最終瘦身方案由App架構(gòu)師委員會(huì)判斷合理性,后續(xù)在n個(gè)版本內(nèi)由平臺(tái)自動(dòng)計(jì)算瘦身的階段性進(jìn)展數(shù)據(jù)告知瘦身發(fā)起的相關(guān)人員;在n個(gè)版本后若未達(dá)成瘦身既定計(jì)劃的目標(biāo)則進(jìn)行線下專項(xiàng)討論,重新制定計(jì)劃或做一些公示性處罰。

京東下載并安裝,京東購(gòu)物官網(wǎng)免費(fèi)下載?

判斷一個(gè)組件合規(guī)與否依賴于管控規(guī)范,管控規(guī)范由App架構(gòu)師委員會(huì)共同討論制定,最初我們?cè)O(shè)定的管控規(guī)范比較粗糙:每個(gè)組件當(dāng)前版本相對(duì)于上個(gè)版本應(yīng)小于等于n KB(起初n設(shè)置為100),隨著瘦身進(jìn)展到后期發(fā)現(xiàn)其存在比較多的弊端,對(duì)于體積大的模塊其往往是多個(gè)開(kāi)發(fā)者協(xié)作經(jīng)常容易出現(xiàn)違規(guī),對(duì)于體積小的模塊往往參與人少迭代變化也不頻繁,所以規(guī)范根本對(duì)其不起作用。

基于這個(gè)情況我們改進(jìn)了規(guī)范:將組件分為A1和A2兩類,A1類組件>=n MB,A2類組件<n MB,對(duì)于A1類組件限定其年增幅應(yīng)小于等于x%,對(duì)于A2類組件限定其單個(gè)版本增量應(yīng)<=yKB。A1類模塊一般迭代頻率高且開(kāi)發(fā)人員多,限定年增幅度每個(gè)版本的回旋調(diào)整余地更大;對(duì)于A2類模塊迭代頻率一般不高,設(shè)定單個(gè)版本增量更小也可以對(duì)應(yīng)的約束其增長(zhǎng);對(duì)于一些三方庫(kù)、公共庫(kù)設(shè)置白名單處理;從全局來(lái)看管控規(guī)范基本兼具一定的公平性和合理性。結(jié)合App實(shí)際情況,通過(guò)合理的設(shè)定n、x及y值,可以將增幅控制在計(jì)劃范圍內(nèi)。

總結(jié)

隨著業(yè)務(wù)和用戶需求的發(fā)展,App的體積會(huì)保持向上增長(zhǎng)的趨勢(shì),業(yè)內(nèi)各個(gè)體積較大的App都在進(jìn)行著瘦身。我們借鑒了業(yè)內(nèi)一些優(yōu)秀的瘦身方案,結(jié)合京東App的實(shí)際場(chǎng)景進(jìn)行了多項(xiàng)措施相結(jié)合的綜合性瘦身方案,提出了既要治理又要管控的思路,沉淀了一套管控規(guī)范,并將其落地到研發(fā)測(cè)試流程系統(tǒng)內(nèi)。隨著新技術(shù)的迭代更新,新的瘦身方案與措施會(huì)不斷涌現(xiàn),我們會(huì)持續(xù)保持跟蹤,歡迎讀者們交流拍磚。

【參考資料】

1、5年磨一劍|優(yōu)酷Android包瘦身治理思路全解:https://developer.aliyun.com/article/953463

2、抖音包大小優(yōu)化-資源優(yōu)化:https://juejin.cn/post/6844904106696376334

3、Google縮減應(yīng)用大?。?/span>https://developer.android.google.cn/studio/build/shrink-code#shrink-resources

4、Android App包瘦身優(yōu)化實(shí)踐:https://tech.meituan.com/2017/04/07/android-shrink-overall-solution.html

5、百度App Android包體積優(yōu)化實(shí)踐:https://mp.weixin.qq.com/s?__biz=MzUxMzk2ODI1NQ==&mid=2247485123&idx=1&sn=09e7fb181f8d1e8d0736931c42be0707&chksm=f94c57d3ce3bdec52c78db8b86e1fdac1f4564ccff94382aec1e5fb060b543ab134de7ac9c3d&scene=21#wechat_redirect

6、R8:https://r8.googlesource.com/r8

7、京東插件化工程R文件瘦身技術(shù)方案:https://mp.weixin.qq.com/s/JgNugWIyor23J-nrKMC6dg

8、京東到家Android瘦身探索:https://mp.weixin.qq.com/s/qqa931j9Jw2ojCX18E1–g

作者:App瘦身團(tuán)隊(duì)

來(lái)源:微信公眾號(hào):京東零售技術(shù)

出處:https://mp.weixin.qq.com/s/sSpbbq-v04CAB5ifKmC20g

版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 sumchina520@foxmail.com 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。

相關(guān)新聞

聯(lián)系我們

聯(lián)系我們

400-9010-860

在線咨詢:點(diǎn)擊這里給我發(fā)消息

微信:85018612

商夢(mèng)建站客服

工作時(shí)間:周一至周六

9:00-18:30,節(jié)假日休息

關(guān)注微信
關(guān)注微信
分享本頁(yè)
返回頂部