背景
京東App在2019年做了一輪瘦身,當(dāng)時做了全方位的瘦身,但隨著業(yè)務(wù)快速迭代和新技術(shù)框架引入以及管控力度不足,安裝包體積出現(xiàn)了反彈。結(jié)合之前治而未管和業(yè)內(nèi)一些同行的瘦身經(jīng)驗,本文介紹此次瘦身過程積累的一些實踐經(jīng)驗以及管控方案。首先拆分安裝包梳理數(shù)據(jù),將安裝包的成份數(shù)據(jù)做成線上化看板,根據(jù)數(shù)據(jù)找出安裝包體積增長主要因素,結(jié)合京東App現(xiàn)狀進(jìn)行了一系列綜合性的瘦身動作,也沉淀了一套新的管控規(guī)范及管控平臺,最終實現(xiàn)了安裝包體積下降30%以上。
安裝包成份分析
瘦身未動,“數(shù)據(jù)”先行,包瘦身的第一步是要分析出App組成成份的大小數(shù)據(jù),為包瘦身的目標(biāo)設(shè)定及任務(wù)拆解提供數(shù)據(jù)支撐,達(dá)到可度量、線上化、統(tǒng)一數(shù)據(jù)標(biāo)準(zhǔn)的目的。如何進(jìn)行安卓App的包成份分析?安卓開發(fā)者基本都會用到Android Studio自帶的Apk Analyzer工具,將Apk文件拖入Android Studio中即可查看,下圖是京東App拖入Android Studio中顯示的包大小數(shù)據(jù),可以清晰的看出包體積里占比較大的主要是lib(存放動態(tài)庫及安卓插件)、r(存放圖片、xml等資源)、assets目錄、dex和resources.arsc(資源映射表)幾類文件。
apk Analyzer工具對于初步的、特定的包大小數(shù)據(jù)查看非常方便,但是對于需要進(jìn)行的包瘦身項目來看,數(shù)據(jù)過于籠統(tǒng),沒有按模塊維度進(jìn)行劃分,無法將包瘦身責(zé)任劃分給對應(yīng)的研發(fā)團(tuán)隊,不便于后續(xù)包瘦身項目的具體實施。為了度量各模塊對包大小的影響,我們需要一套精細(xì)化的包大小分析方案。
首先來看一下京東App的工程結(jié)構(gòu),簡化模型如下圖所示。京東App整體采用了插件化的架構(gòu),開發(fā)迭代過程中逐漸按照功能、業(yè)務(wù)類型拆分成了很多模塊,各模塊有獨立的項目工程、倉庫,日常進(jìn)行獨立的開發(fā)維護(hù),最終集成在Application工程中。功能型的模塊基本上是以library依賴的形式引入到工程中的,比如常用的網(wǎng)絡(luò)庫、圖片庫、埋點庫等;業(yè)務(wù)型的模塊大多是以插件的形式存在,比如搜索、商詳、購物車等;此外主工程中還存在少部分未拆分成模塊的歷史遺留邏輯,在日常迭代中占比非常少。
基于京東App模塊化的現(xiàn)狀,安裝包的成份分析可以從三個方面進(jìn)行:分析包成份的總覽數(shù)據(jù)、分析插件數(shù)據(jù)和分析library數(shù)據(jù)。
01
Apk總覽數(shù)據(jù)分析
安卓的包產(chǎn)物apk文件本質(zhì)上是一個zip文件,可以用zipinfo命令輸出壓縮包中每個文件的詳細(xì)信息日志,用法:
Zipinfo -l --t --h xxxx.apk > xxxx.txt
輸出的日志文件打開如下圖,每個文件的壓縮信息一行,包括文件名、原始大小、壓縮后大小等指標(biāo)。
對以上日志信息進(jìn)行逐行解析,根據(jù)解混淆后的文件名路徑、文件類型進(jìn)行歸類統(tǒng)計,即可得出apk的總覽信息,包括各類型文件的數(shù)量、總大小、單一文件大小等指標(biāo),并建立文件大小索引。
02
插件數(shù)據(jù)分析
插件產(chǎn)物的本質(zhì)也是apk,目前京東App的預(yù)裝插件有50+,App打包時各插件會以.so為后綴的形式放在lib目錄中。對插件的分析可以直接基于包產(chǎn)物進(jìn)行,解析時只需要將apk解壓開來,按照文件名特征將插件從全部so文件中分離出來,逐一按照上述zipinfo相同方法進(jìn)行解析即可。
03
library數(shù)據(jù)分析
各library模塊大多是以aar/jar依賴的形式引入到項目工程中,目前京東App的全部項目依賴庫有300+,包括直接依賴、間接依賴。對library數(shù)據(jù)的分析主要是在分析各依賴對包大小的影響和分析維護(hù)開發(fā)者兩個方面。
01
分析依賴對包大小影響
安卓工程在構(gòu)建時,Gradle構(gòu)建工具會自動將依賴庫同步緩存到本地,與工程中的代碼資源一起編譯merge最終輸出apk。通過編寫gradle腳本任務(wù)在構(gòu)建過程中可以取到aar/jar依賴文件,但是考慮到分析工具的獨立性,盡量避免和打包流程耦合在一起,采用了自行解析依賴的方式來實現(xiàn),整體流程如下:
a. 打包過程中執(zhí)行g(shù)radle命令生成app運(yùn)行時依賴樹日志文件,用法:
./gradlew:app:dependencies--configuration xxxReleaseRuntimeClasspath > dep.txt
生成的日志文件部分如下:
b.解析日志文件生成N叉樹模型,每一行日志生成一個依賴節(jié)點,包含groupId、artifact_name、version信息,日志中的->表示版本沖突取高版本,(*)表示重復(fù)依賴,在application和common_library中添加的依賴為直接依賴,對應(yīng)根節(jié)點和common_library節(jié)點的子節(jié)點,其它節(jié)點為間接依賴。
c.將N叉樹扁平化去重逐一解析依賴,下載aar/jar文件。解析過程中拼接url輪詢倉庫,為了加快解析速度,可以根據(jù)依賴的groupId區(qū)分依賴的來源,如果是jd內(nèi)部的依賴,則優(yōu)先請求內(nèi)部的私服,否則優(yōu)先訪問常用的鏡像倉庫。此外可以加入LRU緩存機(jī)制,本地存在的依賴產(chǎn)物不再請求倉庫,進(jìn)一步加快解析速度。存在的一個潛在問題是快照版本的依賴會對應(yīng)多個產(chǎn)物,解析時取的最新版本可能和app構(gòu)建時用的不是同一個,通常發(fā)版分支上的依賴被規(guī)定不能用快照版本,所以這個問題也就間接規(guī)避了。
d. aar也是一種zip文件,同樣可以用zipinfo命令來解析組成成份大小,建立內(nèi)部jar、so、圖片、xml、asset等文件的索引。
e.將aar內(nèi)部的各文件根據(jù)名稱與總覽數(shù)據(jù)分析時建立的文件大小索引進(jìn)行關(guān)聯(lián),即可知道aar內(nèi)部的so、圖片、xml、asset等文件最終在apk壓縮包里的大小。由于代碼文件jar最終經(jīng)過編譯、刪減、混淆merge成了dex,無法精確的溯源,代碼部分的大小計算采用了原始大小按比例折算的方式進(jìn)行。折算比例是實驗去掉比較獨立的依賴后打包看包大小的差值,去除非代碼部分的大小后,即可算出代碼部分的折算比例,重復(fù)N次去除不同的依賴取平均值。
02
分析模塊負(fù)責(zé)人
前述京東App有300+依賴,由于業(yè)務(wù)調(diào)整、人員變動等原因沒有一個統(tǒng)一的library維護(hù)關(guān)系數(shù)據(jù)。對于直接依賴部分,初期通過git blame 命令輸出app、common_library工程的build.gradle文件修改記錄日志,正則匹配出依賴和維護(hù)者的對應(yīng)關(guān)系;對于間接依賴部分,將前述N叉樹的每一個間接依賴節(jié)點,向上尋找它的父節(jié)點直到直接依賴節(jié)點,則直接依賴的開發(fā)者也是此間接依賴引入的責(zé)任人,會存在多個直接依賴引用了同一個間接依賴的情形,即某個間接依賴庫對應(yīng)多個引入責(zé)任人。
通過上述分析方案,已經(jīng)可以完整的分析出安裝包的各成份大小及對應(yīng)的負(fù)責(zé)人,為瘦身工作的實施提供了數(shù)據(jù)指引。分析方案全部是用python腳本的方式實現(xiàn),已集成到公司內(nèi)部的CD系統(tǒng),數(shù)據(jù)看板效果如下。
京東App的開發(fā)者團(tuán)隊規(guī)模較大,在安裝包成份數(shù)據(jù)線上化建設(shè)完成后,所有開發(fā)者統(tǒng)一了看數(shù)標(biāo)準(zhǔn)和渠道,每個App版本的增長與下降也可以歸因到具體模塊級別以及對應(yīng)的開發(fā)者,同時這個數(shù)據(jù)分析看板也為瘦身的度量和管控提供了基礎(chǔ)數(shù)據(jù)能力。根據(jù)數(shù)據(jù)分析我們發(fā)現(xiàn)App內(nèi)資源文件、ReactNative、插件的數(shù)量和體積都比較大,所以瘦身重點圍繞這幾方面進(jìn)行專項治理,同時基于之前瘦身出現(xiàn)過反彈的教訓(xùn),分析發(fā)現(xiàn)在過往開發(fā)迭代中缺乏約束管控,技術(shù)選型和研發(fā)復(fù)用也暴露了部分問題,因此制定了精細(xì)化的管控規(guī)范并在研測流程中落地實施。
瘦身方案
借鑒業(yè)內(nèi)的瘦身措施,結(jié)合京東App自身特性制定了瘦身方案,首先進(jìn)行了常規(guī)化瘦身舉措主要包括壓縮資源、內(nèi)置ReactNative轉(zhuǎn)為下載、插件轉(zhuǎn)下載、R8編譯升級等,其次對App內(nèi)的圖片進(jìn)行專項治理,構(gòu)建了圖片管理平臺,最終使安卓安裝包體積下降了近30%+,包體積瘦身趨勢圖如下圖。
01
瘦身措施
- 插件轉(zhuǎn)下載
京東mPaaS平臺提供了安卓端插件轉(zhuǎn)下載安裝的能力,2022年初我們協(xié)同mPaaS團(tuán)隊、運(yùn)維團(tuán)隊共同對其進(jìn)行優(yōu)化提升了其可用性和穩(wěn)定性。將下載器的unknown host問題解決,加入了httpdns能力,支持切換域名能力等,運(yùn)維團(tuán)隊通過撥測解決某些cdn節(jié)點異常導(dǎo)致的文件md5不一致問題,最終在真實用戶網(wǎng)絡(luò)環(huán)境下平均單次下載網(wǎng)絡(luò)請求成功率在98%以上,由于在用戶進(jìn)入頁面前存在多次觸發(fā)下載的機(jī)會,進(jìn)入頁面而未加載成功場景的概率在十萬分之4以下,此概率已低于App的崩潰率,體驗上已完全可以保障,實踐過程中也未出現(xiàn)用戶體驗異常反饋。通過業(yè)務(wù)模塊的uv進(jìn)行倒排序,最終甄選了10+插件進(jìn)行了轉(zhuǎn)下載安裝。
- RN內(nèi)置包轉(zhuǎn)下載
在優(yōu)化之初,京東大部分用React Native開發(fā)的業(yè)務(wù)模塊均采用內(nèi)置App的方式,峰值數(shù)量達(dá)到50+個。聯(lián)合mPaaS團(tuán)隊進(jìn)行優(yōu)化,最初評估采用Brotli壓縮本地內(nèi)置包,經(jīng)評估其解壓耗時是gzip的2倍,內(nèi)存使用是幾十至幾百倍,最終放棄這個方案。統(tǒng)一采用了將內(nèi)置包轉(zhuǎn)下載安裝的方案,通過拆分基礎(chǔ)包和業(yè)務(wù)包將JSBundle體積縮小,設(shè)置了預(yù)下載非強(qiáng)制更新、預(yù)下載強(qiáng)制更新以及增加某個RN業(yè)務(wù)打開則觸發(fā)其他未下載業(yè)務(wù)下載等策略有效提升了單周新版更新覆蓋率,提供h5降級、統(tǒng)一兜底降級等多重兜底體驗,最終提升了RN相關(guān)能力的穩(wěn)定性和可用性,保障了用戶體驗,目前內(nèi)置的RN業(yè)務(wù)模塊數(shù)已經(jīng)降至個位數(shù)。
- 資源壓縮
針對圖片壓縮,借助集成TinyPNG壓縮工具對10K以上的圖片進(jìn)行壓縮;受限于Android工程minSdkVersion=16,不能將所有的png圖片都轉(zhuǎn)成webp格式,只能將無透明通道的圖片轉(zhuǎn)成webp。后期對包大小更嚴(yán)格的要求,可以考慮將圖片遠(yuǎn)程化。
- iconfont
借助瘦身腳本分析工具掃描安裝包中方正純色的小圖片轉(zhuǎn)成iconfont,包內(nèi)掃描出800多張可轉(zhuǎn)成iconfont,數(shù)量較多需要長期治理,雖然收益不明顯但利于各個業(yè)務(wù)零散的小圖標(biāo)進(jìn)行統(tǒng)一管理,同時有利于App整體視覺風(fēng)格的統(tǒng)一。
- R文件內(nèi)聯(lián)
通過自定義Gradle插件利用ASM對class文件進(jìn)行字節(jié)碼操作,將class文件中引用到R類資源id替換成對應(yīng)的常量值并刪除R文件,達(dá)到減少包體積的目的。由于京東App采用插件化的方式開發(fā)業(yè)務(wù),每個業(yè)務(wù)插件都會引用公共資源,不能簡單的將公共資源id添加到白名單中,所以結(jié)合京東App插件化方案(aura)的公共資源id固定的能力,實現(xiàn)插件化工程中的公共資源內(nèi)聯(lián)。目前開啟R文件內(nèi)聯(lián)已完成灰度,后續(xù)會陸續(xù)上線,包體積整體收益5.5MB以上。
- 開啟R8編譯
隨Target31適配升級AGP到4.1版本,同步開啟了R8編譯,需要注意R8會忽略部分Proguard混淆規(guī)則,針對R8編譯對混淆規(guī)則的變更點,編寫了mapping文件檢測腳本工具,對Proguard和R8編譯生成的mapping混淆文件進(jìn)行對比,檢測網(wǎng)絡(luò)解析、反射相關(guān)的類是否添加了正確的混淆規(guī)則,利用工具保障了升級R8編譯后App的穩(wěn)定性。R8編譯對代碼混淆優(yōu)化效果要優(yōu)于Proguard,開啟R8后,包體積減少1.6MB,構(gòu)建耗時也降低30%(3min)以上。
- 7Zip壓縮
7Zip兼容Zip格式,支持Zip的Deflate算法,使用7zip極限壓縮模式比Android打包默認(rèn)的zip壓縮率高,可以將加固好的apk文件進(jìn)行7zip解壓縮后重新簽名,包體積降低約2.2%(2MB)。為了驗證其穩(wěn)定性與可用性,計劃對內(nèi)部和外部市場都分別進(jìn)行灰度,通過京東內(nèi)部灰度渠道已灰度完成,對外部的各個渠道將包直接投遞到渠道,如小米、華為等在灰度進(jìn)行中。
在完成這些常規(guī)瘦身方案優(yōu)化后,App安裝包大小依舊較大。先前圖片資源優(yōu)化主要是通過圖片壓縮、使用一套分辨率xhdpi圖片、圖片轉(zhuǎn)webp、資源名混淆等方式進(jìn)行,這些優(yōu)化方式都是將內(nèi)置的圖片進(jìn)行瘦身優(yōu)化,隨著業(yè)務(wù)功能的不斷迭代,瘦身收益將越來越少。京東App各個業(yè)務(wù)的開發(fā)方式是以插件化的形式進(jìn)行,通過對這些業(yè)務(wù)插件包的分析,發(fā)現(xiàn)這些業(yè)務(wù)模塊中內(nèi)置的圖片資源大小占各自插件包總大小的25%以上,針對內(nèi)置圖片資源過多問題,提出一種圖片資源遠(yuǎn)程化的優(yōu)化方案。
02
圖片資源遠(yuǎn)程化
直接將圖片資源轉(zhuǎn)成在線加載可能會影響用戶體驗,將內(nèi)置的圖片資源從App應(yīng)用內(nèi)剝離,然后將圖片上傳到CDN獲取到圖片的網(wǎng)絡(luò)鏈接,應(yīng)用通過加載圖片鏈接進(jìn)行在線加載的方式來展示圖片,在線加載圖片需要經(jīng)過下載圖片的過程,考慮到用戶所處的網(wǎng)絡(luò)環(huán)境受多種因素的影響,常使用默認(rèn)的兜底圖在圖片展示區(qū)域進(jìn)行占位,或者使用全屏的加載中動畫進(jìn)行過渡等方式來優(yōu)化用戶體驗。從優(yōu)化用戶體驗角度出發(fā),提出一種2層網(wǎng)絡(luò)加載+3層降級措施的優(yōu)化方案,可以提高網(wǎng)絡(luò)圖片的加載成功率,同時給用戶展示圖片的體驗如同加載應(yīng)用內(nèi)置圖片資源一樣,整體方案如下:
該優(yōu)化方案主要由圖片管理CMS平臺和獲取圖片信息的客戶端組件組成,由業(yè)務(wù)研發(fā)在CMS配置各自模塊的圖片信息,客戶端通過組件獲取圖片地址展示圖片。
01
CMS圖片管理
- CMS支持圖片類型包括png、jgp、webp、點9圖等,由業(yè)務(wù)模塊梳理出內(nèi)置的圖片素材;
- CMS以用戶為單位,創(chuàng)建業(yè)務(wù)模塊,在模塊內(nèi)上傳圖片獲取圖片CDN鏈接,提供2x、3x兩個分辨率設(shè)置,同時可以設(shè)置圖片在客戶端生效的版本范圍以及生效平臺Android或iOS;
- CMS提供將圖片打包成zip壓縮包的功能,在用戶上傳完圖片后,會根據(jù)各個圖片生效的客戶端版本區(qū)間,生成不同版本區(qū)間以及2x、3x兩種分辨率的zip包,會根據(jù)客戶端請求接口中的分辨率參數(shù)下發(fā)不同分辨率的zip包鏈接;
- CMS提供zip包的預(yù)加載策略,分為App啟動時預(yù)加載、App首頁加載成功后x秒開始預(yù)加載、進(jìn)入某頁面時預(yù)加載等;
- 用戶根據(jù)前面步驟配置完成后,將業(yè)務(wù)模塊內(nèi)的圖片名和對應(yīng)的CDN鏈接組成配置信息由CMS導(dǎo)出,然后將該配置信息文件內(nèi)置到客戶端,提供跟隨安裝包的兜底體驗。
02
客戶端圖片預(yù)加載與緩存
- 客戶端組件在App啟動時請求CMS后臺提供的查詢接口,獲取當(dāng)前客戶端版本對應(yīng)的配置信息,與本地兜底配置信息進(jìn)行比較,得到的差分信息進(jìn)行本地持久化;
- 客戶端組件同時解析后臺接口下發(fā)的圖片zip包信息,根據(jù)zip包的預(yù)加載策略下載對應(yīng)的圖片zip包,下載完成后解壓到以模塊名命名的本地文件夾中;
- 當(dāng)展示圖片時,客戶端組件根據(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ù)加載未完成或失敗時,通過安裝包中內(nèi)置的圖片CDN鏈接兜底配置信息加載圖片網(wǎng)絡(luò)鏈接來展示圖片,該兜底配置信息以圖片名+圖片CDN鏈接鍵值對的形式保存。
3層降級措施的第一層降級是獲取圖片zip包預(yù)加載的本地緩存圖片;第二層降級是當(dāng)本地圖片緩存失效時,獲取內(nèi)置的圖片CDN鏈接加載;第三層降級則是默認(rèn)的兜底圖。瘦身業(yè)務(wù)模塊開啟圖片zip預(yù)加載功能時,CMS支持業(yè)務(wù)模塊設(shè)置zip包預(yù)加載策略,業(yè)務(wù)模塊根據(jù)實際情況選擇不同的加載策略,例如某些業(yè)務(wù)模塊頁面入口比較深,這些業(yè)務(wù)模塊就可以選擇用戶在進(jìn)入頁面時觸發(fā)zip包的預(yù)加載;
某些業(yè)務(wù)模塊進(jìn)入頁面入口比較淺就可以設(shè)置App啟動后空閑時預(yù)加載,其他二級、三級的頁面可以設(shè)置App啟動后x秒(隨機(jī)時間)才開始下載。通過設(shè)置這些預(yù)加載策略,將圖片zip包分散在不同時間段下載,降低圖片加載時的網(wǎng)絡(luò)流量峰值。
上述方案需要業(yè)務(wù)研發(fā)積極配合,需要業(yè)務(wù)模塊額外通過固定的模塊ID+圖片ID優(yōu)先獲取本地緩存的方式加載圖片,使用過程較繁瑣,缺乏靈活性,為方便開發(fā)者更容易使用,提供更多選擇,降低接入成本,我們在CMS和客戶端作了些改進(jìn),又提出了下面的優(yōu)化方案:
- 圖片CMS變更點
CMS后臺對圖片zip打包做額外處理:取圖片CDN鏈接中固定路徑計算MD5值,并將該MD5值重命名圖片名稱,不保留圖片類型后綴。例如鏈接:https://xxx/jfs/xxx/name.png,對鏈接中jfs開頭和.png之間的路徑字符串進(jìn)行MD5值計算:MD5(/jfs/xxx/name) =MD5-Value ,以該MD5-Value值作為圖片名稱,并且移除圖片類型后綴名(.png等), 其他圖片同樣按照該步驟進(jìn)行重命名,最后打包成以模塊名命名的圖片壓縮包。
- 客戶端變更點
提供一個工具類,以模塊名和圖片CDN鏈接作為入?yún)?,對圖片CDN鏈接進(jìn)行相同的處理,獲取CDN鏈接中固定路徑字符串的MD5值,然后根據(jù)模塊名和MD5值查找該圖片本地緩存是否已存在,即圖片zip包預(yù)加載是否成功,如果圖片已成功緩存則將該圖片的緩存路徑(file://協(xié)議)返回給圖片加載框架,如果圖片緩存不存在,則原樣返回圖片CDN鏈接(http://協(xié)議)。同樣也可以結(jié)合圖片加載框架實現(xiàn),新增以業(yè)務(wù)模塊名作為別名的圖片加載屬性,該別名屬性就是業(yè)務(wù)模塊圖片緩存本地的目錄,如果設(shè)置了該屬性,圖片加載框架就會優(yōu)先判斷該圖片是否已緩存成功,若圖片已緩存成功,則通過本地路徑展示圖片,若緩存未成功,則直接在線加載圖片,該方案需要客戶端圖片加載框架同時支持file協(xié)議和http協(xié)議。該方案也可以應(yīng)用于大促等場景的圖片預(yù)加載。
通過埋點數(shù)據(jù)查看zip包預(yù)加載成功率,圖片zip包預(yù)加載在配置首頁啟動后x秒下載,iOS端的zip包加載成功率在98.9%~99.1%波動,Android端的zip加載成功率在96.7%~98.1%波動,剩余1%~3%的用戶則通過內(nèi)置的兜底cdn鏈接在線加載,倆者結(jié)合展示圖片的成功率接近100%;客戶端從本地緩存加載圖片的效率要高于從網(wǎng)絡(luò)在線加載圖片,省去了等待圖片下載的過程,降低了默認(rèn)兜底圖的展示概率,在體驗上接近于本地內(nèi)置圖片加載的效果。
管控
京東App在2019年專項瘦身后經(jīng)過一段時間又反彈了50%,一方面因為業(yè)務(wù)快速迭代發(fā)展以及新引入了一些比較大的基礎(chǔ)庫,另一方面原因就是重點做了瘦身治理卻沒有深入做管控準(zhǔn)入防止劣化。因此在新一輪瘦身優(yōu)化過程中,我們一邊做瘦身治理,一邊在探索常態(tài)化的管控機(jī)制,最終沉淀了一套管控規(guī)范和管控平臺。
管控的目的不是為了限制需求迭代與增加代碼,目的是做好把控讓合理的代碼放進(jìn)來,不合理的拒絕掉以及淘汰陳舊的代碼,提升開發(fā)者們的瘦身意識。管控對產(chǎn)研全鏈路提出了新的要求,對于以往粗放型的需求開發(fā)迭代方式會有所約束,產(chǎn)品側(cè)需要及時的配合研發(fā)側(cè)將ABTest的廢棄實驗代碼下線,研發(fā)側(cè)需要做好技術(shù)規(guī)劃和技術(shù)選型,盡可能的精簡代碼和復(fù)用代碼,加強(qiáng)技術(shù)團(tuán)隊之間的協(xié)同,不放置過大或冗余的資源文件等。
管控的前提是基于App已經(jīng)充分的組件化解耦,且App開發(fā)人員規(guī)模相對比較大,比如京東App當(dāng)前安卓端是由業(yè)務(wù)插件和AAR依賴庫組成。App的組成成份整體上是由一個配置表來表示,配置表內(nèi)描述所有組件的配置版本信息,一個組件是否允許集成到App內(nèi)的前提是這個組件體積增長大小符合我們制定的規(guī)范,然后組件的最新版本才可以集成到配置表內(nèi)。我們管控的核心機(jī)制就是控制配置表的更新集成權(quán)限,以此來約束每個組件的開發(fā)者,通過App架構(gòu)師委員會(京東內(nèi)由架構(gòu)師形成的虛擬組織)制定的公共管控規(guī)范來評判每個組件體積增長是否合規(guī),合規(guī)則準(zhǔn)入更新配置表,否則走異常申請流程。
01
管控流程與方案
管控流程是伴隨著開發(fā)、測試、發(fā)布整個流程進(jìn)行的,整體的流程如圖所示。開發(fā)者開發(fā)完成后,由開發(fā)者在京東內(nèi)部的組件構(gòu)建與發(fā)布平臺(mPaaS)發(fā)布形成新的組件版本,在構(gòu)建完成后開發(fā)者在打包平臺(Bamboo)基于臨時配置表進(jìn)行打包并提測,在此過程中會基于包計算出對應(yīng)組件的體積變化數(shù)據(jù),同時打包系統(tǒng)會以郵件形式將數(shù)據(jù)同步至開發(fā)者,盡可能前置的告知開發(fā)者是否存在不合規(guī);
測試通過后開發(fā)者申請集成組件版本信息至配置表,若合規(guī)則更新配置表且流程結(jié)束,若不合規(guī)開發(fā)者可以進(jìn)行代碼優(yōu)化后在申請集成,或者申請異常審批流程至App架構(gòu)師委員會。常規(guī)的業(yè)務(wù)迭代大部分不會出現(xiàn)違規(guī),但也會存在部分異常的情況,異常的處理往往會產(chǎn)生較多的爭議,研發(fā)的安裝包體積管控需要頂住產(chǎn)品和業(yè)務(wù)的壓力,異常處理的流程需要客觀、透明、靈活,異常處理流程如圖所示。
某個組件違規(guī)了發(fā)起申請,對于三方庫、國家要求的隱私整改、安卓系統(tǒng)升級適配等情況,可以審核準(zhǔn)許通過,其他一些特殊情況也可以通過,由App架構(gòu)師委員會來酌情把控。對于一些正常情況下產(chǎn)生了組件體積增長超限違規(guī),短期無法優(yōu)化瘦回可以申請設(shè)置未來n個版本后瘦回,或者A組件協(xié)商B、C組件來協(xié)助分擔(dān)瘦回,最終瘦身方案由App架構(gòu)師委員會判斷合理性,后續(xù)在n個版本內(nèi)由平臺自動計算瘦身的階段性進(jìn)展數(shù)據(jù)告知瘦身發(fā)起的相關(guān)人員;在n個版本后若未達(dá)成瘦身既定計劃的目標(biāo)則進(jìn)行線下專項討論,重新制定計劃或做一些公示性處罰。
判斷一個組件合規(guī)與否依賴于管控規(guī)范,管控規(guī)范由App架構(gòu)師委員會共同討論制定,最初我們設(shè)定的管控規(guī)范比較粗糙:每個組件當(dāng)前版本相對于上個版本應(yīng)小于等于n KB(起初n設(shè)置為100),隨著瘦身進(jìn)展到后期發(fā)現(xiàn)其存在比較多的弊端,對于體積大的模塊其往往是多個開發(fā)者協(xié)作經(jīng)常容易出現(xiàn)違規(guī),對于體積小的模塊往往參與人少迭代變化也不頻繁,所以規(guī)范根本對其不起作用。
基于這個情況我們改進(jìn)了規(guī)范:將組件分為A1和A2兩類,A1類組件>=n MB,A2類組件<n MB,對于A1類組件限定其年增幅應(yīng)小于等于x%,對于A2類組件限定其單個版本增量應(yīng)<=yKB。A1類模塊一般迭代頻率高且開發(fā)人員多,限定年增幅度每個版本的回旋調(diào)整余地更大;對于A2類模塊迭代頻率一般不高,設(shè)定單個版本增量更小也可以對應(yīng)的約束其增長;對于一些三方庫、公共庫設(shè)置白名單處理;從全局來看管控規(guī)范基本兼具一定的公平性和合理性。結(jié)合App實際情況,通過合理的設(shè)定n、x及y值,可以將增幅控制在計劃范圍內(nèi)。
總結(jié)
隨著業(yè)務(wù)和用戶需求的發(fā)展,App的體積會保持向上增長的趨勢,業(yè)內(nèi)各個體積較大的App都在進(jìn)行著瘦身。我們借鑒了業(yè)內(nèi)一些優(yōu)秀的瘦身方案,結(jié)合京東App的實際場景進(jìn)行了多項措施相結(jié)合的綜合性瘦身方案,提出了既要治理又要管控的思路,沉淀了一套管控規(guī)范,并將其落地到研發(fā)測試流程系統(tǒng)內(nèi)。隨著新技術(shù)的迭代更新,新的瘦身方案與措施會不斷涌現(xiàn),我們會持續(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)化實踐:https://tech.meituan.com/2017/04/07/android-shrink-overall-solution.html
5、百度App Android包體積優(yōu)化實踐: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)隊
來源:微信公眾號:京東零售技術(shù)
出處:https://mp.weixin.qq.com/s/sSpbbq-v04CAB5ifKmC20g
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點僅代表作者本人。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至 sumchina520@foxmail.com 舉報,一經(jīng)查實,本站將立刻刪除。