導讀:這是在今年項目體積優化時,記錄的一些實戰筆記,文中主要針對APK的包內容優化.其中優化手段主要有:字節碼,資源,打包配置等優化手段.
前言
移動網絡從2G->4G->5G,網速一步步提升,網絡資費也逐漸便宜起來了. 記得上高中的時候5塊錢/30M流量,能happy一個月.現在給我300M流量,說不定一會刷完
前幾年開始Android開發的職業生涯,那會公司對APP的包體積還特別敏感,到了今天,對APP的包體積已經不在是特別敏感了
但是對於
- 出海應用APP,非洲,印度那些網絡資源匱乏的地方,APP包體積還是特別敏感的
- 日活,流量比較大的APP,如微信,抖音等APP,對包體積還是比較關注的
所以今天還是把我之前對APP瘦身的筆記分享給大家,與此共勉(內容不包含插件化,Split APK等動態下發技術,Only客戶端自己的優化)
APK包結構簡介
APK包結構主要包含
- assets目錄:用於存放需要打包到APK中的靜態文件和res的不同點在於,assets目錄支持任意深度的子目錄,用戶可以根據自己的需求任意部署文件夾架構,而且res目錄下的文件會在.R文件中生成對應的資源ID,assets不會自動生成對應的ID(在不動業務邏輯,或者代碼邏輯的情況下,針對此項很難優化)
- lib目錄:存放應用程序依賴的native庫文件, .so的形式存在
- res目錄:res是resource的縮寫,這個目錄存放資源文件
- resources.arsc文件:編譯後的二進制資源文件
- META-INF目錄:保存應用簽名信息,此處可驗證APK的完整性,簽名等
- AndroidManifest.xml:應件文件配置信息
- classes.dex:
下面我們來說一下優化的具體實施有哪些.
classes.dex 中常量 R文件及內斂類的刪除 * .R$ *
我們知道,Android的Res資源會生成R文件的引用,如下
public final class R {
private R() {
}
public static final class id {
public static final int action_container = 2131165209;
public static final int action_divider = 2131165211;
public static final int action_image = 2131165212;
public static final int action_text = 2131165218;
public static final int actions = 2131165219;
public static final int async = 2131165226;
public static final int blocking = 2131165232;
public static final int chronometer = 2131165246;
public static final int forever = 2131165290;
public static final int icon = 2131165299;
public static final int icon_group = 2131165300;
public static final int info = 2131165305;
public static final int italic = 2131165309;
public static final int normal = 2131165373;
public static final int notification_background = 2131165374;
public static final int notification_main_column = 2131165375;
public static final int notification_main_column_container = 2131165376;
public static final int right_icon = 2131165405;
public static final int right_side = 2131165406;
public static final int tag_transition_group = 2131165453;
public static final int text = 2131165456;
public static final int text2 = 2131165457;
public static final int time = 2131165461;
public static final int title = 2131165462;
private id() {
}
}
public static final class drawable {
.......
}
public static final class dimen {
...
}
....
}
這都是些常量,那我們有沒有辦法刪除這個文件呢,引用的地方直接使用常量的值?事實是可以的.
根據APK打包的編譯過程,在編譯過程中使用Android的Transform替換所有的類裏面的常量. BuildConfig, Rlayout, R$string,AppConstans, etc
目前滴滴開源了一個booster 可以直接使用,不用在自己造輪子
booster-transform-shrink
效果
組件化後或者依賴第三方 R文件越來越多,常量比較多時,效果比較顯著
據抖音的一哥們說,他們項目針對此項目優化後,包體積減少2M左右.
在我們項目上使用,不是很明顯,優化體積1M左右.
注意事項
因爲是刪除常量,所有使用反射的地方也需要keep住,如果使用滴滴的booster,可以參考 issues
Res資源
Android Lint 去除無用資源
當我們項目迭代不斷迭代,總有些資源逐漸不在使用,成爲了冗餘,當很多時候又懶得刪,或者怕刪了出問題. Android Studio自帶lint工具可以幫助我們清楚這些無用資源.(這裏的清楚和shrinkResources去除無用是不一樣的)
使用方法入口
除了Android Studio Analyze下的Android Lint(Inspect Code) 用來去除無用資源,包體積優化,對於我們的代碼一些自動優化也有很明顯的效果. (性能,安全,bug預防等)
- Android > Lint > Correctness (可能影響程序正確性)
- Android > Lint > Performance (可能影響程序性能)
- Android > Lint > Security (可能影響程序安全性)
Lint詳細使用說明:google.cn/studio/lint
還有Code Cleanup也很強大,可以減少一些人爲代碼review不規範的地方.
圖片
針對圖片的優化,主要有一下幾點
.9圖片
使用.9圖片來代替一些可重複區域的大圖,可以藉助Android Studio或者sdk下的.9工具來製作.9圖片
xh-dpi
國內應用除了應用的icon,大部分應用只設置了一套資源xh-dpi,所以推薦使用一套圖片資源
Android原生對於WebP的支持
我們知道Webp的壓縮比例要比 png,jpg/jpeg的壓縮比高,使用webp能減少一些包體積.
- Android 4.0開始(sdk >= 14 ),原生的ImageView開始支持Webp,但是未支持透明通道
- Android 4.2開始 (sdk >= 18)開始前面支持Webp
也就是說你項目的 minSdk是4.2以上 >= 18 那麼恭喜你,你可以把所有圖片轉成webp格式,方法直接圖片右鍵就可以轉換.
如果只是在4.0與4.2之間的那麼,你就只能轉一些不帶透明通道的圖片,如果其他你還想要Webp接入一個庫,那增大包體積,和原生ImageView不支持,帶來的成本挺大.
圖片壓縮
圖片壓縮也是隻要的一個環節. 圖片壓縮的工具很多,png,webp都可以很容易的壓縮,對於應用質量體積有較高要求的,建議使用有損壓縮,對圖片視覺上的效果影響不大.
這裏還是推薦 使用booster的壓縮工具,可以png和webp壓縮,針對webp的壓縮針對了不同minSdk版本,進行了不同壓縮策略.
booster-task-compression
resources.ars優化
我們知道 res裏面的資源文件名引用一般是這樣的,例如將res/drawable/welcome.png那麼打包的時候,是不是可以改成這樣r/s/a.png.
事實是可以的,類似java的混淆規則去混淆資源,這樣,所佔用的字節數就會降低.
但是存在一個問題就是,這些資源資源ID已經被編譯成32位int值,放入了resources.arsc.那麼混淆的同時就要修改resources.arsc.
張紹文 tinker作者,前微信的技術大年,開源了AndResGuard,可以解決這樣的方案,並且優化還可以.具體使用詳解 AndResGuard
build.gradle 配置
com.android.tools.build:gradle 是Android打包的工具,在打包時也可以對生成的APK包,體積優化,這裏列舉了一些常見的優化策略.
buildTypes {
release {
buildConfigField 'String', 'TINKER_APP_ID', '"d499a164a6"'
debuggable false //debug false
shrinkResources true //移除無用資源
zipAlignEnabled true //開啓壓縮
resConfigs "zh" //表示只使用中文
resConfigs "xhdpi" // 表示只是用xhdpi目錄下的資源文件
minifyEnabled true //開啓混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
ndk {
//選擇要添加的對應cpu類型的.so庫。
abiFilters 'armeabi-v7a'
}
}
}
以上是一些常用的配置,其中需要注意的是
- 開啓混淆,必須主要項目中的keep規則是否考慮全面
- resConfigs 需要和產品設計協商後,在開啓
- ndk中,目前國內大部分應用都只支持了armabi-v7a(支持浮點類型,精度更高),我所在的應用也只使用了aremabi-v7a架構,這種架構幾乎所有的arm手機都支持.
文末
APP瘦身就介紹完了,上述方案都在項目中實踐過的.如果文中存在錯誤,請各路大神指教.