要盡可能減小 APK 文件帽芽,我們應(yīng)該啟用壓縮來(lái)移除發(fā)布構(gòu)建中未使用的代碼和資源。
1. 使用 ProGuard 混淆代碼
在 Android 中代碼混淆和壓縮都是通過(guò) ProGuard 來(lái)實(shí)現(xiàn)的,ProGuard 會(huì)檢測(cè)和移除代碼中未使用的類(lèi)手趣、字段阁最、方法和屬性,除此外還可以?xún)?yōu)化字節(jié)碼成玫,移除未使用的代碼指令加酵,以及用短名稱(chēng)混淆類(lèi)拳喻、字段和方法。
在 build.gradle 中猪腕,使用 minifyEnabled 屬性來(lái)開(kāi)啟代碼混淆:
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}
2. 使用 shrinkResources 壓縮資源
在 build.gradle 中使用 shrinkResources 屬性來(lái)開(kāi)啟資源壓縮冗澈,它在構(gòu)建 apk 時(shí)可以移除那些沒(méi)有引用到的資源文件,通常它必須與 minifyEnabled 屬性一起使用:
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
需要注意的是码撰,開(kāi)啟該屬性設(shè)置后渗柿,它并不會(huì)移除 values/ 文件夾中定義的資源,例如:字符串脖岛、顏色朵栖、樣式等等。
3. 混淆壓縮對(duì)比
為了鑒定一下代碼混淆與資源壓縮到底有多大作用柴梆,我們隨便找個(gè)簡(jiǎn)單的 app 工程來(lái)實(shí)驗(yàn)一下陨溅。
minifyEnabled | shrinkResources | apk大小 |
---|---|---|
false | false | 4,285,579 字節(jié),約4.3M |
true | false | 3,781,347 字節(jié)绍在,約3.8M |
true | true | 3,779,525 字節(jié)门扇,約3.8M |
false | true | 無(wú)法編譯 |
從中我們可以得到一些結(jié)論:
- 開(kāi)啟代碼混淆和資源壓縮后,apk 大小減少了約0.5M偿渡,一個(gè)小工程都尚且如此臼寄,在一個(gè)比較龐大的工程中開(kāi)啟這倆選項(xiàng),壓縮的大小還是很可觀的溜宽。
- 開(kāi)啟資源壓縮與不開(kāi)啟相比吉拳,只減少了約2000多字節(jié)的大小,可見(jiàn)大頭還是靠代碼混淆适揉,資源壓縮只能起到錦上添花的作用留攒。
- 關(guān)閉代碼混淆開(kāi)啟資源壓縮,你會(huì)發(fā)現(xiàn)無(wú)法編譯嫉嘀,Android Studio 會(huì)提示你這倆必須配對(duì)使用炼邀,要開(kāi)啟資源壓縮必須得開(kāi)啟代碼混淆。
4. 資源壓縮會(huì)保留文件名不保留內(nèi)容
我們?cè)僮鰝€(gè)測(cè)試剪侮,在應(yīng)用的資源中放一張png圖片姑且命名為 test.png拭宁,放一個(gè)layout布局文件命名為test.xml,并且確保這2個(gè)資源文件沒(méi)有任何代碼會(huì)引用瓣俯,我們開(kāi)啟代碼混淆和資源壓縮打包生成apk文件杰标。
生成apk文件后,直接將apk包拖到 Android Studio 中降铸,可以查看apk包的相關(guān)信息在旱,細(xì)心一點(diǎn)的話你會(huì)發(fā)現(xiàn)幾個(gè)有趣的現(xiàn)象:
- 在圖片資源文件夾中,仍然可以看到名為 test.png 的圖片推掸,但是你打開(kāi)看到的是一個(gè) 1*1 的圖片桶蝎;
- 在 layout 文件夾中驻仅,仍然可以看到名為 test.xml 的文件,打開(kāi)看到的是一個(gè)空的xml文件登渣,沒(méi)有任何xml節(jié)點(diǎn)信息噪服;
也就是說(shuō),資源壓縮后胜茧,并不是直接刪除了沒(méi)有用到的資源文件粘优,而是生成了對(duì)應(yīng)的占位文件,這些占位文件都是空文件呻顽,相比原文件大小可以忽略不計(jì)雹顺。這樣做的原因是:每個(gè)資源文件都對(duì)應(yīng) R.class 里的一個(gè)資源 id ,資源 id 的映射關(guān)系會(huì)打包在 resources.arsc 文件里廊遍,如果直接刪除了資源文件嬉愧,則可能需要同時(shí)修改 resources.arsc 里的資源映射表,這樣是很繁瑣的過(guò)程喉前,而用占位文件來(lái)替換則避免了這種情況没酣。
5. 使用 resConfigs 去除多余的語(yǔ)言包
目前很多第三方庫(kù)內(nèi)包含了各種語(yǔ)言包,但是大多數(shù)情況下我們的應(yīng)用是不需要國(guó)際化卵迂,僅僅需要中文的就可以了裕便,所以可以 resConfigs 配置來(lái)去掉多余的語(yǔ)言包:
android {
defaultConfig {
...
resConfigs "zh"
}
}
如上所示,打包時(shí)只會(huì)將中文的資源包打進(jìn)去见咒,這樣也可以一定程度上減小 apk 的體積偿衰。
6. ProGuard 中的壓縮優(yōu)化配置
關(guān)于 ProGuard 的配置有很多,具體需要查看文檔才能知道作用是什么论颅。剛開(kāi)始接觸的時(shí)候哎垦,我以為 ProGuard 只是做代碼混淆而用的囱嫩,其實(shí)它的作用不僅僅如此恃疯,有2個(gè)配置我們經(jīng)常會(huì)忽略掉:
- -dontshrink
聲明不進(jìn)行壓縮操作。 - -dontoptimize
不對(duì) class 進(jìn)行優(yōu)化墨闲,默認(rèn)是開(kāi)啟優(yōu)化的今妄。由于優(yōu)化會(huì)進(jìn)行類(lèi)合并、內(nèi)聯(lián)等鸳碧,使用熱修復(fù)的應(yīng)用盾鳞,建議關(guān)閉優(yōu)化。
我發(fā)現(xiàn)很多第三方庫(kù)瞻离,例如友盟統(tǒng)計(jì)SDK腾仅,官方給出的 ProGuard 配置都需要加上該配置,也就是說(shuō)不進(jìn)行代碼優(yōu)化套利、壓縮推励,往往初次接觸者不明所以的照搬了鹤耍。但其實(shí)如果你的應(yīng)用沒(méi)有采用熱更新方案之類(lèi)的,在 ProGuard 里去掉這2個(gè)配置验辞,你會(huì)發(fā)現(xiàn)這對(duì)減小 apk 的大小效果很顯著稿黄。
以我們自己的一個(gè)應(yīng)用為例,ProGuard 里加上這2個(gè)配置打出來(lái)的 apk 包大小約為 25.5M跌造,去掉這2個(gè)配置之后打出的包大小約為 24.1M杆怕。簡(jiǎn)直不敢相信,就這么2個(gè)小小的配置壳贪,居然能讓包大小縮減 1.4M 左右陵珍,效果非常明顯。
但是违施,實(shí)操過(guò)程中撑教,我們發(fā)現(xiàn)有些頁(yè)面的圖標(biāo)丟失變成黑色了,這些因?yàn)?ProGuard 判定某些資源文件沒(méi)有被使用醉拓,將它轉(zhuǎn)換成了一個(gè) 1*1 的占位文件了伟姐。這需要我們手動(dòng)在 res/raw/keep.xml 里配置,明確告訴 ProGuard 哪些資源文件是不需要混淆壓縮的亿卤,以為自己的一個(gè)配置為例:
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:shrinkMode="safe"
tools:keep="@mipmap/emoji_*,@mipmap/jietiao_ic_module_*"
>
</resources>
7. 小結(jié)
采用 ProGuard 是減小 apk 大小非常有效的方法之一愤兵,但是使用過(guò)程中可能附帶很多問(wèn)題:有可能打包不成功、有可能圖片資源問(wèn)題丟失排吴、有可能莫明其妙的閃退秆乳,這些都需要我們對(duì) ProGuard 的配置有個(gè)基本的了解,遇到問(wèn)題才能迎刃而解钻哩,用好了它相信會(huì)有很大的幫助屹堰。
系列文章
Android apk瘦身最佳實(shí)踐(一):去除R.class
Android apk瘦身最佳實(shí)踐(二):代碼混淆和資源壓縮
Android apk瘦身最佳實(shí)踐(三):資源混淆原理
Android apk瘦身最佳實(shí)踐(四):采用AndResGuard進(jìn)行資源混淆
Android apk瘦身最佳實(shí)踐(五):圖片壓縮
Android apk瘦身最佳實(shí)踐(六):采用D8編譯器