序
在原理篇中,我們發現在App內存的分布中,Code是占大頭的部分,所以我們可以從App體積方面想辦法,通過減小App體積達到降低內存的目的,同時,根據權威的機構分析,體積與用戶下載和留存有很大的聯系,總之體積減小有很大的好處,本篇研究了一下滴滴開源的Booster工具,減小包體積,優化App性能。
1. Booster簡介
1.1 是什么
Booster 是滴滴開源的一款專門為移動應用設計的易用、輕量級且可擴展的質量優化框架,其目標主要是為了解決隨著 APP 復雜度的提升而帶來的性能、穩定性、包體積等一系列質量問題。
Booster 提供了性能檢測、多線程優化、資源索引內聯、資源去冗余、資源壓縮、系統 Bug 修復等一系列功能模塊,可以使得穩定性能夠提升 15% ~ 25%,包體積可以減小 1MB ~ 10MB。
Booster 主要由 Transformer 和 Task 組成,Transformer 主要用于對字節碼進行掃描或修改(取決于 Transformer 的功能),Task 主要用于構建過程中的資源處理,為了滿足特異的優化需求,Booster 提供了 Transformer SPI and VariantProcessor SPI允許開發者進行定制,以下是 Booster 的整體框架:
1.2 能做什么?
-
性能檢測:使用 Booster 可以發現潛在的性能問題,例如,在應用中調用可能阻塞 UI 線程或者主線程的 API,如,I/O API 等;
-
性能優化:對于開發者來說,線程管理一直是個頭疼的問題,特別是第三方 SDK 中的線程,過多的線程可能會導致內存不足,然而幸運的是,這些問題都能通過 Booster 來解決;
-
系統問題修復:例如全局性地修復 Android API 25 版本中 Toast 導致的崩潰;
-
應用瘦身:如,資源壓縮及冗余資源刪除、資源索引內聯及常量刪除;
1.3 目前Booster內置的一些功能
-
動態加載模塊支持差異化的優化需求,Booster 實現了模塊的動態加載,以便于開發者能在不使用配置的情況下選擇使用指定的模塊,詳見:booster-task-all、booster-transform-all,也可以定制task和transform,然后設置classpath。
-
第三方類庫注入:支持動態添加依賴或者注入某些類和庫(比如插樁、無埋點統計等),詳見:booster-transform-lint。
-
多線程優化:業務線眾多的 APP 普遍存在線程過載的問題,而線程管理一直是開發者最頭疼的問題之一,雖然可以通過制定嚴格的代碼規范來規避此類問題發生而對于第三方 SDK 來說,代碼規范則有些力不從心。為了徹底的解決這一問題,Booster 通過在編譯期間修改字節碼實現了全局線程池優化,并對線程進行重命名。詳見:booster-transform-thread。
-
SharedPreferences 優化:SharedPreferences幾乎無處不在,而在主線程中修改 SharedPreferences 會導致卡頓甚至 ANR,為了徹底的解決這一問題,Booster 對 APP 中的指令進行了全局的替換。詳見:booster-transform-shared-preferences。
-
常量字段刪除:無論是資源索引,還是其它常量字段,在編譯完成后,就沒有存在的價值了(反射除外),因此,Booster 將對資源索引字段訪問的指令替換為常量指令,將其它常量字段從類中刪除,一方面可以提升運行時性能,另一方面,還能減小包體積,資源索引(R)表面上看起來微不足道,實際上占用不少空間。
-
資源壓縮:APP 的包體積也是一個非常重要的指標,在 APP 安裝中,圖片資源占了相當大的比例,通常情況下,圖片質量降低 10%-20% 并不會影響視覺效果,因此,Booster 采用有損壓縮來降低圖片的大小,而且,圖像尺寸越小,加載速度越快,占用內存越少。Booster 提供了兩種壓縮方案:
-
pngquant 有損壓縮(需要自行安裝 pngquant 命令行工具)
-
cwebp 有損壓縮(已內置)
-
-
性能檢測:APP 的卡頓率是衡量應用運行時性能的一個重要指標,為了能提前發現潛在的卡頓問題,Booster 通過靜態分析實現了性能檢測,并生成可視化的報告幫助開發者定位問題所在,其實現原理是通過分析所有的 class 文件,構建一個全局的 Call Graph, 然后從 Call Graph 中找出在主線程中調用的鏈路(Application、四大組件、View、Widget等相關的方法),然后再將這些鏈路以類為單位分別輸出報告,詳見:booster-transform-lint。
-
WebView 預加載:為了解決 WebView 初始化導致的卡頓問題,Booster 通過注入指令的方式,在主線程空閑時提前加載 WebView。
2. 引入使用Booster
2.1 地址
-
開源地址:https://github.com/didi/booster/tree/master
-
官方Doc:https://booster.johnsonlee.io/zh/guide/
2.2 引入
集成 Booster 的最佳方式是集成真正需要的模塊來解決項目中遇到的特定問題。
buildscript {ext.boosterVersion = '4.8.0'repositories {google()mavenCentral()// OPTIONAL If you want to use SNAPSHOT version, sonatype repository is required.maven { url 'https://oss.sonatype.org/content/repositories/public' }}dependencies {classpath "com.didiglobal.booster:booster-gradle-plugin:$boosterVersion" // ① booster基礎插件// ② 弄清楚真正需要的特性,選擇正確的模塊進行集成,下面的是我們的工程中目前引入的模塊classpath "com.didiglobal.booster:booster-task-compression-cwebp:$boosterVersion" // 采用 cwebp 對資源進行壓縮classpath "com.didiglobal.booster:booster-task-compression-processed-res:$boosterVersion" // ap_ 文件壓縮classpath "com.didiglobal.booster:booster-task-resource-deredundancy:$boosterVersion" // 去冗余資源classpath "com.didiglobal.booster:booster-transform-r-inline:$boosterVersion" // 資源索引內聯classpath "com.didiglobal.booster:booster-transform-thread:$boosterVersion" // 性能優化解決線程過多問題classpath "com.didiglobal.booster:booster-transform-shared-preferences:$boosterVersion" // SharedPreferences 優化,解決卡頓問題}
}allprojects {repositories {google()mavenCentral()// OPTIONAL If you want to use SNAPSHOT version, sonatype repository is required.maven { url 'https://oss.sonatype.org/content/repositories/public' }}
}// 在你的 application 工程的build.gradle中引入,如下:
apply plugin: 'com.android.application'
apply plugin: 'com.didiglobal.booster' // ③
2.3 確認是否啟用
然后在終端用如下命令來確認 Booster 是否啟用:
./gradlew assembleDebug --dry-run
2.4 版本選擇
2.4.1 官方文檔上說
由于 AGP 8 的不兼容性變更,AGP 7.x 及以下版本已經不再支持,如果你仍在使用 AGP 7.x,請使用 Booster 4.x
大部分基于
Task
的模塊在 Booster 5.0.0 中已經不再支持,但是基于Transform
的模塊仍然支持且沒有破壞性變更。詳情請參見 [從 Booster 4.x 遷移到 5.x](遷移到 v5.x | Booster
2.4.2 我們的選擇
我們使用booster主要是為了減小包體積,其中重要的一項是資源壓縮(booster-task-compression-cwebp),測試合適的版本,經過驗證,4.8.0版本是能支持的最高版本,再高的版本就會沒有我們需要的Task(booster-task-compression-cwebp)。
所以我們選擇了能編譯過去,并且有我們需要的Task的最高版本 4.8.0。
2.5 功能組件選擇
經過查找測試,決定使用以下6個插件進行優化:
-
booster-task-compression-cwebp(采用 cwebp 對資源進行壓縮)
-
booster-task-compression-processed-res(ap_ 文件壓縮)
-
booster-task-resource-deredundancy(去冗余資源)
-
booster-transform-r-inline(資源索引內聯)
-
booster-transform-thread(性能優化解決線程過多問題)
-
booster-transform-shared-preferences(SharedPreferences 優化,解決卡頓問題)
2.6 booster-task-compression-cwebp插件的參數配置
文檔說明如下:
Property | Description | Example |
| compression quality (the default is 80) | |
| ignore wildcards (separated by comma) |
|
經過實際測試發現
-
booster.task.compression.cwebp.quality
-
發現不生效,查看代碼,應該設置為:booster.task.compression.cwebp.option.quality,驗證可用;
-
-
booster.task.compression.cwebp.ignores
-
按文檔中寫的示例配置不生效;
-
經驗證,白名單需要遵循以下規則:
-
資源名(png圖片)后沒有點和擴展名,直接文件名結尾
-
資源名前應該還有其它字符,但測試未得到正確的結果,需要再研究,現階段可以使用通配符*
-
多個白名單資源以逗號分隔,逗號前后不能有空格
-
白名單不能以雙引號或單引號包裹
-
白名單太長折行時應以反斜杠續行,如下
-
booster.task.compression.cwebp.ignores=*food_card_bg,*food_\pic_bg_noa,\*frame_fridge_520_36,\*frame_fridge_550_37,\*frame_fridge_777_36
-
-
編譯booster源碼,打印日志查看:使用帶日志的自己打出來的snapshot版的booster插件,看到Cwebp白名單過濾時,傳入的資源字符串的形式是“drawable/food_card_bg”,與之前驗證出來的pattern規則能對應上。
-
3. 總結
本文簡述了Booster的功能和其引入的方法,然后應用到我們的項目中發現的一些問題及解決方法,其它的暫未進行深入研究,后續可以引入更多的Task或Transform,也可以擴展我們自己的功能。
另外,研究Booster的過程中,發現字節也開源了一個類似的框架ByteX,后續也可以一起研究一下,取長補短,只要是對項目有用的可以逐步引入,沒有的功能也可以通過擴展實現。
4. 參考文獻
-
開源地址
-
官方Doc
-
滴滴開源 Booster:移動APP質量優化框架
-
滴滴Booster移動APP質量優化框架 學習之旅
-
Booster 移動 APP 質量優化框架
5.團隊介紹
「三翼鳥數字化技術平臺-定制平臺開發」主要負責設計工具的研發,包括營銷設計工具、家電VR設計和展示、水電暖通前置設計能力,研發并沉淀素材庫,構建家居家裝素材庫,集成戶型庫、全品類產品庫、設計方案庫、生產工藝模型,打造基于戶型和風格的AI設計能力,快速生成算量和報價;同時研發了門店設計師中心和項目中心,包括設計師管理能力和項目經理管理能力。實現了場景全生命周期管理,同時為水,空氣,廚房等產業提供商機管理工具,從而實現了以場景貫穿的B端C端全流程系統。