主目錄見:Android高級進階知識(這是總目錄索引)
[譯]Reduce APK Size
?個人感覺這篇文章寫得還是比較全的钮热,所以這里就來翻譯一下這篇文章蚁飒,希望大家看了能有所收獲徽曲。這篇是谷歌自己的文章渣淤,應該來說還是比較權威的户誓,APK的體積變小意味著用戶下載時候需要的流量也比較少尚洽,而且下載時間相對縮短乎折,這是一個不錯的用戶體驗绒疗。
一.目標
今天翻譯這篇文章主要是為了大家了解有這么多可以縮小apk包體積的方法,在自己寫代碼的時候可以適當地注意骂澄,所以今天目標如下:
1.了解減小apk體積的若干方法吓蘑;
2.能在實際場景中考慮和使用到里面的方法。
二.譯文
?用戶通常會避免下載大應用坟冲,特別是市場上的設備連接到2G和3G或者按字節(jié)流量付費磨镶。這篇文章重點描述了怎么減少你應用Apk的體積,讓更多的用戶能下載它健提。
1.理解APK結構
?在討論怎么減小Apk體積之前琳猫,理解一個應用的APK結構是非常有幫助的。一個apk文件就是由一個zip壓縮包組成矩桂,這個zip包含了所有組成你應用的文件沸移。這些文件包含了java的字節(jié)碼文件,資源文件和一個包含了編譯后資源的文件侄榴。
?一個apk包含了如下的目錄:
-
META-INF/: 包含了
CERT.SF
和CERT.RSA
簽名文件雹锣,以及MANIFEST.MF
manifest 文件. -
assets/:包含了應用的
assets
,應用可以通過 AssetManager對象來獲取這些資源. -
res/:包含了沒有被編譯成
resources.arsc
的所有資源. -
lib/:包含了用于軟件處理的編譯后的代碼癞蚕,這個目錄還包含了針對不同平臺類型的子目錄
armeabi
,armeabi-v7a
,arm64-v8a
,x86
,x86_64
和mips
.
一個APK還包含了如下的文件蕊爵,但是其中只有AndroidManifest.xml
是必須的。
-
resources.arsc:包含了編譯后的資源桦山。這個文件包含了
res/values/
文件夾下面的所有XML文件內容攒射,打包工具抽取了XML文件內容醋旦,并把它編譯成二進制文件格式,并且進行壓縮会放。該內容包含了language strings(語言相關的字符串)和styles饲齐,并且包括沒有直接放在resources.arsc
文件中的內容路徑,比如layout文件以及圖片文件. - classes.dex:包含了class文件編譯成的dex文件咧最,這是可以被Dalvik/ART虛擬機識別的文件格式捂人。
- AndroidManifest.xml:包含了Android核心manifest文件。這個文件羅列了應用的名字矢沿,版本滥搭,訪問權限和引用的library庫。該文件采用Android的二進制XML格式捣鲸。
2.減小資源數量和體積
?你apk的體積直接影響了你程序的加載速度瑟匆,占用內存大小,消耗的電量栽惶。一個簡單有效的方法是減小apk包含的資源的數量和體積愁溜。特別是,你可以移除一些不再使用的資源媒役,或者你可以使用一些可擴展的 Drawable對象來替代圖片資源祝谚。這部分主要討論這些方法以及另外可以減少資源占用的方法。
移除無用的資源
?使用Lint工具酣衷,這是一個Android Studio中的靜態(tài)代碼分析工具,可以檢測 res/
文件夾中沒有被引用的資源(其實Lint工具不僅僅有這個功能)次泽。當Lint
檢測到工程中潛在的不被使用的資源穿仪,它就會打印出如下消息:
res/layout/preferences.xml: Warning: The resource R.layout.preferences appears to be unused [UnusedResources]
注意:Lint
不會掃描assets/
文件夾,assets資源是通過反射來引用的意荤,或者應用中引用的其他library庫啊片。他只是給你一個警告,并不會幫助你移除這些無用的資源玖像。
同時你添加到代碼中的library庫可能包含無用的資源紫谷,如果你在app里的build.gradle中啟用了shrinkResources
,那么Gradle 會自動幫你移除這些無用的資源捐寥。
android {
// Other settings
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
為了使用shrinkResources
笤昨,你必須開啟 code shrinking。在build階段握恳,ProGuard會移除無用的代碼但是會保留無用的資源瞒窒。然后Gradle過后會移除無用的資源。
更多的關于ProGuard 和使用Android Studio 幫助你減少Apk體積的方法乡洼,參閱Shrink Your Code and Resources.
在Android Gradle Plugin 0.7或者更高的版本崇裁,你可以聲明app支持的所有配置匕坯,Gradle會把resConfig
和resConfigs
flavors 和defaultConfig
等選項信息傳遞給構建系統(tǒng)。構建系統(tǒng)會防止一些不受支持的資源出現在你的apk中拔稳,從而減少你的apk體積葛峻。想要了解更多這方面的特性,參考Remove unused alternative resources巴比。
最小化Library庫中資源使用
?在開發(fā)android應用的時候泞歉,你經常會使用外部的library庫來提升你app的可用性和擴展性。例如匿辩,你會引入Android Support Library來提升用戶在舊機型上面的體驗腰耙,或者你會使用Google Play Services來自動翻譯你app中的文本。
?如果一個library庫被設計為一個服務或者桌面铲球,那么它就會包含很多你應用沒有用到的對象和方法挺庞。為了只包含你工程中用到的部分,你可以修改這個庫文件稼病,如果license許可的話选侨,同時你也可以使用另外的移動端友好的庫來給你的app增加特定的功能。
注意:然走,ProGuard能清除導入庫中一些無用的代碼援制,但是不能清除庫中大的內部依賴。
只支持特定的分辨率
?Android支持了非常多的不同分辨率的設備芍瑞,在Android 4.4 (API level 19)或者更高版本晨仑,框架支持了不同的分辨率:ldpi
, mdpi
, tvdpi
, hdpi
, xhdpi
, xxhdpi
和 xxxhdpi
,雖然Android支持了這些所有的分辨率,但是你并不需要導出所有柵格化的assets到各個分辨率拆檬。
?如果你知道只有一小部分用戶使用特定分辨率的設備洪己,請考慮是否需要支持這些分辨率。如果你沒包含特定屏幕分辨率的資源竟贯,那么Android會自動縮放其他分辨率的資源來支持答捕。
?如果你的app只需要縮放的圖片,那么為了節(jié)省空間你可以使用單個版本在drawable-nodpi/
中的圖片屑那,我們建議拱镐,每個應用都至少有一個xxhdpi
版本的圖片。
想要更多關于屏幕分辨率的信息持际,請參照Screen Sizes and Densities
使用drawable對象
?一些圖片不需要一個靜態(tài)圖片資源:框架能在運行期動態(tài)繪制一張圖片沃琅,Drawable對象(<shape> in XML)只在你的apk中占用非常小的控件。另外选酗,XML Drawable對象能生成符合material design指南的單色圖阵难。
重用資源
?你可能會針對一張圖片的不同變形而提供單獨的資源,比如圖像的著色(tinted),陰影(shaded)或者旋轉(rotated)芒填。我們建議就算這樣呜叫,你可以重用這個資源空繁,在運行期時候根據需要進行自定義。
?Android提供了不同的工具來改變一個asset
的顏色朱庆,比如在Android 5.0 (API level 21) 或者更高版本上面使用android:tint
和tintMode
屬性 盛泡,在低版本平臺上則可以使用 ColorFilter
類。
?你甚至可以忽略掉那些僅僅只是做了一個旋轉變化的資源娱颊,以下的代碼段就提供了一個以圖片中心點為圓心旋轉180度傲诵,將圖片從"朝上"變成"朝下"的例子。
<?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" />
從代碼中渲染
?同時你也可以在程序上渲染你的圖片以減少apk的體積箱硕,程序渲染將會釋放你的很多空間拴竹,因為你的程序中不會存儲一張圖片資源。
處理PNG文件
?在build階段剧罩,aapt
工具能利用無損壓縮來優(yōu)化放在res/drawable/
中的圖片資源栓拜。例如,aapt
工具能利用顏色調色板(color palette)將不需要多于256種顏色的真彩色PNG轉化成一個八位PNG惠昔。這樣做會產生一個質量相同但是占用空間小的圖片幕与。
?但是要記住appt
工具有如下的限制:
-
aapt
工具不會壓縮包含在asset/
中的PNG文件 - 圖片文件需要256個或者更少的顏色來給
aapt
工具優(yōu)化 -
aapt
工具可能會使已經壓縮過的PNG文件變大,為防止這種情況發(fā)生镇防,你可以在Gradle中使用cruncherEnabled
標識來禁用PNG文件的處理啦鸣。
aaptOptions {
cruncherEnabled = false
}
壓縮PNG和JPEG文件
?你能使用工具來減少PNG圖片的體積但是不損失他的質量,例如: pngcrush,pngquant或者zopflipng.這些工具都可以減少PNG的體積但是不損失他的質量来氧。
pngcrush
工具是非常高效地:這個工具會迭代所有的PNG文件過濾器和zlib (Deflate) 參數诫给。利用過濾器和參數的組合來壓縮一張圖片,然后他會選擇產生最小壓縮輸出的配置饲漾。
壓縮JPEG圖片你可以利用 packJPG和guetzli.
使用WebP文件格式
?在Android 3.2 (API level 13)或者更高版本上面蝙搔,你同時可以使用WebP文件格式來替代你的PNG和JPEG文件。WebP格式提供了有損壓縮(如JPEG)和透明度(如PNG)考传,但是他能提供更好的壓縮比。
?你可以用Android Studio來將BMP证鸥,JPG僚楞,PNG 或者靜態(tài)GIF 圖片轉化為WebP格式,想要更多信息枉层,請參考Create WebP Images Using Android Studio
注意:Google Play只接受launcher icons為PNG格式的apk泉褐。
使用矢量圖片
?你可以使用矢量圖片來創(chuàng)建分辨率獨立的圖標或者其他可伸縮媒體。使用這些圖形可以大大減少你的apk體積鸟蜡,矢量圖片可以在 VectorDrawable展示膜赃,使用VectorDrawable對象可以用100字節(jié)的文件就產生一張屏幕大小的文件。
但是不足的是揉忘,他需要大量時間來渲染VectorDrawable對象跳座,如果圖片更大端铛,需要的時間可能會更多。所以在展示小圖片的時候我們可以考慮使用矢量圖片疲眷。
想要了解更多使用VectorDrawable對象的信息禾蚕,請看Working with Drawables
使用矢量圖來替換動畫圖片
?不用使用 AnimationDrawable來創(chuàng)建逐幀動畫,因為這么做需要你為每一幀動畫都包含一張bitmap圖片狂丝,這樣會大大增加你的apk體積换淆。
作為替代,你可以使用 AnimatedVectorDrawableCompat來創(chuàng)建 animated vector drawables
3.減少Native和java的代碼
這里有幾種減少你Native和java代碼庫的方法:
減少不必要的生成的代碼
?確保你能夠理解任何自動生成的代碼的部分几颜。例如倍试,一些protocol buffer
工具能生成一些多余的方法和類,這無疑會是你的app體積變成兩倍三倍蛋哭。
避免使用枚舉
一個獨立的枚舉能增加1.0到1.4KB的大小到你的classes.dex
文件县习,對于一些復雜系統(tǒng)或者共享庫可能增加的會更快。如果可能具壮,你可以使用@IntDef
注解和ProGuard來去掉枚舉并將它們轉化為整型准颓。這種類型轉換保留了枚舉的所有類型安全的好處。
減少本地二進制文件的大小
如果你的程序使用native代碼或者android NDK棺妓,那么你也可以優(yōu)化你的代碼來減少apk體積攘已,兩個有用的方式是刪除debug標記,不提取本地庫怜跑。
1.移除debug標記
如果你的應用在開發(fā)中并且需要調試样勃,那么讓你的debug 標記有意義。使用android NDK中提供的arm-eabi-strip
工具來移除native庫中不需要的debug標記性芬。之后峡眶,再編譯你的release版本。
2.避免抽取native庫
將.so
文件未壓縮存儲于apk中植锉,然后在你app manifest中的<application>設置android:extractNativeLibs
標記為false辫樱,這樣會防止 PackageManager在安裝過程中從apk中拷貝出來.so
文件,而且還會帶來一個好處就是會使你的app差分更新變得更小俊庇。
保持多個精簡版apk
你的apk可能會包含有用戶下載了但是未使用到的內容狮暑,比如區(qū)域或者語言信息。為了給你用戶創(chuàng)建最小化的下載辉饱,你可以將你的app分出多個apk搬男,并且根據屏幕尺寸和GPU紋理支持等因素來細分。
當用戶下載你的應用的時候彭沼,他的設備就會根據設備特征和配置來獲取正確的apk缔逛。這樣,設備不會接收設備沒有的功能的資源。例如褐奴,用戶有hdpi
的設備按脚,他們就不需要為更高分辨率設備準備的xxxhdpi
資源。
想要更多信息的話歉糜,請參考 Configure APK Splits和Maintaining Multiple APKs