本篇文章已授權(quán)微信公眾號guolin_blog(郭霖)獨家發(fā)布
轉(zhuǎn)載請注明出處:http://www.reibang.com/p/7b623fed6302
APK的大小對于app載入速度、占用內(nèi)存大小以及耗電量有著很大的影響蚜点。一般而言,用戶并不太喜歡下載APK體積太大的app厂镇。尤其是對于流量、手機內(nèi)存有限的用戶來講残黑,太大的APK往往會讓他們望而卻步。那么如何讓APK的體積降下來呢?
了解APK結(jié)構(gòu)
想要對APK進行瘦身雏亚,你必須得先了解APK的組成結(jié)構(gòu)胖笛,只有了解APK由哪些部分組成,你才能有所針對性的進行APK瘦身辟汰。
APK主要由以下幾部分組成:
-
META-INF/ :包含了簽名文件
CERT.SF
凑术、CERT.RSA
鹿鳖,以及 manifest 文件MANIFEST.MF
命满。 - assets/ : 存放資源文件杂抽,這些資源不會被編譯成二進制赡矢。
- lib/ :包含了一些引用的第三方庫。
-
resources.arsc :包含res/values/中所有資源界轩,例如
strings
,styles
报辱,以及其他未被包含在resources.arsc
中的資源路徑信息,例如layout 文件慢睡、圖片等。 -
res/ :包含res中沒有被存放到
resources.arsc
的資源袒啼。 - classes.dex :經(jīng)過dx編譯能被android虛擬機理解的Java源碼文件。
- AndroidManifest.xml :這個不用解釋
我們可以通過android studio --> build --> Analyze APK 來查看一下上述各個部分文件大小情況
從上圖來看,占用空間的主要是代碼蚓再、res 和 lib 滑肉,因為我的assets中沒有放文件,所以看起來并沒有占用什么空間摘仅,其實assets中文件放的多靶庙,一樣會占用很大空間。所以APK瘦身時实檀,主要就從
代碼
惶洲、res
、 lib
和assets
這幾個方面考慮膳犹。
減少資源文件數(shù)量和大小
APK瘦身的一個很簡單的辦法就是減少資源文件的數(shù)量和大小恬吕,本節(jié)就來討論一些常用的方法。
去除無用資源
- 使用
lint
工具來檢測res/
中是否有沒有使用到的資源 - 然而對于一些第三方庫來說须床,使用lint可能無法檢測到铐料,我們可以使用
shrinkResources
來刪除庫文件中無用的資源,配合proguard壓縮代碼使用
android {
// Other settings
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
- 移除未使用的備用資源豺旬。例如對于一些第三庫來說钠惩,因為國際化的問題,它們可能會支持了幾十種語言族阅,但我們的應(yīng)用可能只需要支持中文就行了篓跛,這時候我們就可以使用
resConfig
或resConfigs
來解決。
下面這段代碼展示了如何將語言資源限定為僅支持中文:
android {
defaultConfig {
...
resConfigs "zh"
}
}
使用最小化資源的庫
我們開發(fā)項目的時候坦刀,經(jīng)常會用到許多第三方庫愧沟,但第三方庫往往可能會很大,那怎么來進行壓縮呢鲤遥?
- 使用ProGuard壓縮代碼沐寺,然后配合
shrinkResources
使用,方法見上面shrinkResources
的使用盖奈。 - 然而ProGuard只能壓縮庫本身的一些沒有用到的代碼混坞,但庫內(nèi)部本身可能仍依賴了其他的第三方庫,對于這些庫ProGuard卻無法進行有效去除钢坦。
很多第三方庫會提供多種版本究孕,例如完整版、精簡版爹凹、針對某個功能的特殊版蚊俺,你只需要選擇能包含你需要功能的體積最小版本庫。當然如果你能獲得源碼逛万,自己提煉出你所需要的功能就更好了泳猬。
只支持特定屏幕密度
Android支持多種屏幕密度設(shè)備批钠,Android 4.4以上版本支持包括:ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi and xxxhdpi。盡管Android支持了這么多屏幕密度得封,但你并不需要全部支持埋心,你可以根據(jù)你的需求來選擇支持。
使用drawable 對象
對于一些簡單的images可以不使用圖片忙上,使用Drawable XML
來進行繪制拷呆。
復用資源
對于相似的一些Image可以復用同一張圖片。
- 形狀一樣疫粥,但顏色茬斧、陰影有區(qū)別的Image;在 Android 5.0 (API level 21)以及以上版本梗逮,可以使用
android:tint
,tintMode
等屬性去調(diào)整项秉,在Android 5.0以下可以使用ColorFilter
來調(diào)整。 - 形狀顏色一樣慷彤,但角度不一樣的Image娄蔼;可以使用
rotate
等來調(diào)整角度達到復用效果。例如:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_thumb_up"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="180" />
代碼渲染
你也可以通過代碼渲染來代替使用圖片底哗,例如使用自定義View繪制岁诉。圖片減少了,APK自然瘦身了跋选。
緊縮PNG文件
AAPT工具會在構(gòu)建期間自動對res/drawable/文件夾下的PNG圖片資源做無損壓縮涕癣。例如,一張true-color的PNG圖片前标,如果它實際需要的顏色不大于256種坠韩,那么就有可能會被轉(zhuǎn)換成一張8位的調(diào)色板圖片(PNG8)。轉(zhuǎn)換之后的圖片質(zhì)量未減卻只占用更小的內(nèi)存候生。
壓縮PNG和JPG
你可以使用pngcrush, pngquant 或 zopflipng來壓縮PNG圖片。
使用packJPG 或 guetzli 來壓縮JPG圖片绽昼。
使用WebP
你可以使用 WebP 來代替JPG和PNG圖片唯鸭。WebP 保留了JPG和PNG優(yōu)點的同時,能提供更好的壓縮硅确,達到更小的體積目溉。
你可以將已經(jīng)有的JPG、PNG菱农、GIF等直接轉(zhuǎn)為WebP圖片缭付,方法請參考:Create WebP Images Using Android Studio.
注意:啟動圖標最好不要用WebP,因為谷歌商店只接受啟動圖片格式為PNG的APK循未。
使用矢量圖形
你可以使用矢量圖形來繪制分辨率無關(guān)圖標及其他可伸縮媒體文件陷猫。整個屏幕那么大的清晰圖片,如果使用矢量圖可能只需要100-byte大小。
然而使用矢量圖形會讓系統(tǒng)花更多的時間來進行繪制绣檬,所以最好只在比較小的images上使用矢量圖足陨。
將矢量圖形用于動畫圖像
不要使用AnimationDrawable
來創(chuàng)建幀動畫,否則每一幀就用一張圖片會占用大量的空間娇未。這個時候你應(yīng)該使用AnimatedVectorDrawableCompat
墨缘。
減少本地代碼和Java代碼
這兒有幾種方法來減小Java代碼和本地代碼庫的大小。
刪除不必要的生成代碼
要確保能夠了解自動生成的代碼用途零抬,例如有很多的protocol buffer tools會自動生成大量你可能用不到的代碼镊讼。
避免使用枚舉
一個單獨的枚舉可以將apk增加1.0 到1.4 KB大小,對于復雜的系統(tǒng)或者共享庫來說平夜,累積下來可能會增加相當大的APK體積蝶棋。
如果可能的話,可以考慮使用@IntDef
注解和ProGuard
來剝離枚舉并將它們轉(zhuǎn)換為整數(shù)褥芒。這種類型轉(zhuǎn)換保留了枚舉的類型安全優(yōu)勢嚼松。
減少本地二進制文件的大小
如果你的APP使用native code 和 Android NDK,那么可以通過兩種方法優(yōu)化代碼锰扶,達到減小APK大小的效果献酗。
- 刪除Debug符號
使用Android NDK中提供的arm-eabi-strip
工具來移除Native庫中不必要的Debug符號。 - 避免提取本地庫
在 Android 6.0 之前坷牛, so 文件會壓縮到 apk 中罕偎,系統(tǒng)在安裝應(yīng)用的時候,會把 so文件解壓到 data 分區(qū)京闰,這樣同一個 so 文件會有兩份存在颜及,一個在 apk 中一個在 data 區(qū)中, 導致多占用了一倍空間蹂楣。 從 Android 6.0 開始俏站,你可以在 AndroidManifest.xml 中使用一個新的屬性:
<application
android:extractNativeLibs=”false”
...
>
該屬性告訴系統(tǒng),不要把 so 文件從 apk 中解壓出來了痊土,并且修改 System.loadLibrary 調(diào)用直接從 apk 中打開 so 文件肄扎。
維護多個精簡版APK
你的APP中可能會包含許多用戶根本不會使用的內(nèi)容,例如區(qū)域和語言信息赁酝。你可以根據(jù)屏幕尺寸或GPU紋理支持等因素針對性提供不同版本的APK犯祠。當用戶下載APK的時候,會根據(jù)手機的特性和設(shè)置有針對性的下載特定版本APK酌呆,這樣的話用戶就不會下載到他根本不需要的內(nèi)容衡载。
上面的話是從官網(wǎng)翻譯過來的,看不太懂沒關(guān)系隙袁,其實就是按需提供資源支持痰娱,根據(jù)手機的不同提供不同版本的APK弃榨,我們直接來看例子
android {
...
splits {
//根據(jù)屏幕像素密度來創(chuàng)建多個APK
density {
enable true
//根據(jù)屏幕密度創(chuàng)建兩個版本APK,"mdpi", "hdpi"
reset()
include "mdpi", "hdpi"
}
//根據(jù)手機cpu指令集分類創(chuàng)建多個APK
abi {
enable true
//創(chuàng)建 "x86", "x86_64"兩個版本APK
reset()
include "x86", "x86_64"
}
}
}
我們來編譯一下APK看下結(jié)果
我們可以看到生成了6個APK猜揪,為什么是6個呢惭墓?
首先屏幕密度有三個版本(
mdpi
, x86_64
,gralde還會生成一個包含所有屏幕密度資源的默認版本),ABI指令集有兩個版本(gralde默認編譯不會添加包含所有ABI指令集版本的APK而姐,如果你想添加腊凶,需要在abi代碼塊中加上universalApk true
),它們兩兩組合為6種拴念。每個APK里只會包含它對應(yīng)的資源钧萍,例如app-hdpiX86-debug.apk
中只會存在屏幕密度為hdpi
的資源以及X86
的庫文件。如果你的手機cpu指令集是x86政鼠,屏幕密度為hdpi风瘦,那么你會下載到
app-hdpiX86-debug.apk
。
你可以通過Configure APK Splits 和 Maintaining Multiple APKs來進一步了解相關(guān)內(nèi)容公般。
參考資料
https://developer.android.google.cn/topic/performance/reduce-apk-size
https://developer.android.google.cn/studio/build/shrink-code
https://developer.android.google.cn/studio/write/lint
http://www.reibang.com/p/0eae3f13dcd6
http://blog.chengyunfeng.com/?p=895