減少Android APK大小

[SDK官網原文鏈接](https://developer.android.com/topic/performance/reduce-apk-size.html#multiple-apks
用戶經常避免下載看起來很大的APP,尤其是你的設備連接參差不齊的2G、3G網絡或者使用按數據流量支付的業務。本文將介紹如何減少APK 尺寸,使得更多的用戶可以接受下載你的APP。

一、理解APK文件結構

理解Android APK的文件結構,對如何減少你的app尺寸是有意義的。一個APK文件包含一個ZIP歸檔文件,它包含組成你的APP的所有文件,這些文件包括java類文件,資源文件,以及包含編譯資源的文件。
一個APK包含下面幾個目錄:
(1)META-INF/:包括簽名文件CERT.SF and CERT.RSA,以及MANIFEST.MF文件。
(2)assets/:包括app的assets文件,APP能用AssetManager對象來獲得。
(3)res/:包括哪些沒有被編譯進resources.arsc的資源。
(4)lib/:包含編譯後的代碼,是特定於處理器的軟件層。這個目錄包含子目錄爲每個平臺類型,像armeabi armeabi-v7a,arm64-v8a,x86,x86_64和mips。
一個APK文件還包括以下文件。在這些文件中,只有AndroidManifest.xml是強制必須有的。
(1)resources.arsc:包含編譯資源。這個文件包含res/values/文件下的所有配置的XML內容,打包工具提取XML內容,將其編譯成二進制形式,並且歸檔該內容。這些內容包括
語言字符串、樣式、以及那些沒有被直接包含在resources.arsc文件中的內容的路徑,比如:佈局文件和圖片。
(2)classes.dex: 包括編譯在Dalvik/ART虛擬機認可的DEX格式文件的所有類。
(3)AndroidManifest.xml: 包括核心的Android清單文件,這個文件列出了名稱,版本,訪問權限,app所引用的庫文件。這個文件用Android二進制XML格式。

二、減少資源數量和大小

APK的大小會影響APP加載的快慢,它使用多少內存,以及消耗多少電量。一個讓你的APK較小簡單辦法是減少它所包含的資源的數量和大小。特別是,你可以移除你的APP不再使用的資源,並且用可拉伸的Drawable對象代替圖片資源。本節將討論這些方法以及其他一些可以減少你的應用程序資源從而減少APK總體大小的方法。

(1)移除未使用的資源

Android Studio包含了一個靜態代碼分析工具,Lint工具,它可以檢測在res/文件下你的代碼未引用的資源。當Lint工具發現你的工程裏潛在的未使用的資源,它就打印如下信息:

res/layout/preferences.xml: Warning: The resource R.layout.preferences
appears to be unused [UnusedResources]

注意:Lint工具不掃描assets/文件夾,assets文件是通過反射被引用,也不會掃描你的APP鏈接的庫文件。同時,它不會刪除資源;它只提醒你它們的存在。
你的引用的庫也有可能包含不可用的資源。如果你在build.gradle文件中開啓了shrinkResources,Gradle能夠代表你自動移除資源。

  android {
    // Other settings

    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}  

爲了使用shrinkResources,你必須首先開啓代碼shrink。在構建過程中,首先混淆器會移除無用的代碼但會保留無用的代碼,然後由Gradle移除無用的資源文件。

(2)最小化庫的資源使用

在開發應用程序時,你通常會使用外部庫來提高你的應用程序的可用性和多功能性。例如:你可以引用Android支持庫去提升用戶在舊設備的上的體驗,或者你可以使用谷歌播放服務來檢索自動翻譯在你的應用程序文本。如果你所要引用的庫是基於服務端或者桌面設計的,那可能包含很多你的APP用不上的對象和方法。爲了使你所引用的庫只包含你需要的那部分功能,那就需要你修改庫文件,當然要求你有可以修改庫的許可。你也可以選擇替代的,傾向於終端使用的庫來向你的APP添加特定的功能。
注意:ProGuard可以清理一些外部庫不必要的代碼,但不能移除庫本身內部的龐大依賴。

(3)只支持特定的密度

Android 支持很大一系列的設備,包括各種各樣的屏幕密度。在Android 4.4 (API 19)及以上,框架支持各種屏幕密度:ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi and xxxhdpi。儘管Android 支持所有這些屏幕密度,但是爲每一種屏幕密度都配置相應資源文件是沒有必要的。
如果你知道僅有很少一部分的用戶擁有特定密度的設備,考慮是否需要將這些屏幕密度的資源放入你的項目中,如果你不包含某一特定屏幕密度的資源,Android 會自動伸縮現存的未其他屏幕密度設計的資源。
如果你的APP僅需要伸縮的圖片,你甚至可以省去drawable-nodpi/的圖片,我們建議每個APP至少有一個drawable-xxhdpi/的圖片.
(4)減少動畫的幀

逐幀動畫會大大增加你的APK的大小,圖1顯示了一個逐幀動畫分解出來在一個文件夾下的多個PNG文件,每一個圖片就是動畫中的一幀。你加入動畫的每一幀,都會增加存儲在你的APK中的圖片數量,圖1是30FPS的動畫,假設你的動畫以15FPS,動畫只需一半幀的數量。
這裏寫圖片描述

(5)使用Drawable對象

一些圖片不需要靜態圖片資源,框架可以在運行時動態繪製圖像。Drawable對象(XML中定義的Shape)只佔用極少量APK的空間,另外,XML Drawable對象定義的單色圖像,也是符合物料設計指南的。

(6)重用資源

你可以包含一個圖像變化的一系列的資源,比如:這個圖像的顏色漸變,陰影,或者旋轉。然而,我們建議你只用一個圖像資源,然而在運行的時候定製它們。
Android提供了一些工具來改變資源的顏色,在Android 5.0或更高的版本上,可以使用android:tint 和 tintMode屬性,低版本的平臺,使用ColorFilter類。
你也可以省去通過旋轉可以得到的資源,下面的代碼片段提供了一個例子,將原始圖像伸展的箭頭,轉變成摺疊的箭頭。

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_arrow_expand"
    android:fromDegrees="180"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="180" />

(7)通過代碼渲染

你也可以通過有序的渲染你的圖像來減小APK的大小,有序的渲染可以節省空間,因爲你將不必在APK裏存儲圖像文件。

(8)緊縮PNG 文件

aapt工具可以在構建過程中無損壓縮res/drawable/目錄的圖像資源。舉個例子,aapt工具可以將不需要256種顏色的真彩色PNG轉換成一個有調色板的8位PNG,這樣做就可以使同等品質的圖像佔用更小的內存空間。
注意,appt工具有以下限制:
1.appt工具不能緊縮asset/目錄下的PNG文件
2.圖像文件需要256顏色或更少,纔可以使用appt工具優化
3.aapt工具可能膨脹已經壓縮的PNG文件。爲了防止這一點,你可以設置Gradle裏cruncherEnabled標誌來禁用對PNG文件的處理。

aaptOptions {
    cruncherEnabled = false
}

(9)壓縮PNG和JPEG文件

你可以工具像pngcrush pngquant或zopflipng,在不損失圖像質量情況下減少PNG文件的大小。這些工具都可以在減少PNG文件大小的同時,也保留圖像質量。pngcrush工具是尤其有效的,這個工具遍歷PNG過濾器和zlib(壓縮)參數,用對應的過濾器和參數來壓縮圖像,然後選擇可以產生最小壓縮輸出的配置。
對於JPEG文件,你可以選擇類似packJPG 工具,來將JPEG文件壓縮成更緊湊的形式。

(10)使用WebP文件格式

代替使用PNG或JPEG文件格式,你也可以爲圖像使用WebP的文件格式。WebP格式提供了有損壓縮(JPEG)以及透明度(如PNG)但是它可以提供比JPEG和PNG更好的壓縮比。使用WebP文件格式有一些明顯的缺點,首先,低於Android 3.2(API級別13)是不支持WebP的,其次,對於WebP和PNG文件的系統解碼來說,它是比較耗時的。
注意:Google Play 只接受只能包含PNG格式icon的APK,如果你想在Google Play發佈應用,那麼你將不能使用JPEG或WebP格式的文件作爲應用的icon。

(11)使用矢量圖片

你可以使用矢量圖形來創建分辨率無關圖標和其他可伸縮的媒體。使用這些圖形可以大大減少你的APK的大小,矢量圖形在Android中用VectorDrawable對象表示,用VectorDrawable對象,100個字節的文件就可以生成有形的屏幕尺寸的圖像。
然而,那需要花費系統大量的時間去渲染每一個VectorDrawable對象,對於較大的圖片可能需要更長的時間才能渲染到屏幕上,因此,當只有當顯示較小的圖像時,可以考慮用這些矢量圖形。

(12)減少native和Java代碼

有以下幾種方法可以用來減少APP的Java和native代碼庫。
1.移除不必要的生成代碼
一定要確認明確自動生成的代碼的存在的必要性。例如,許多協議緩衝工具生成過多的方法和類,它可以導致應用程序大小增至兩倍或三倍。
2.移除枚舉
一個枚舉會導致你的APP的classes.dex文件增加大約1.0到1.4 KB。對於複雜的系統或者共享庫而言,這些添加可以迅速累積起來。如果可能的話,可以考慮用@IntDef 註釋和ProGuard將枚舉轉換爲整數。這種類型轉換保留了枚舉的所有類型安全好處。
3.減少native二進制的大小
如果應用程序使用了native代碼和Android NDK,你也可以通過優化你的代碼減少你的應用程序的大小。兩個有用技術是移除調試標識和不提取native庫。
1)移除調試標識
如果你的應用程序在開發階段或者仍需要調試,那麼使用debug標識是有意義的。使用Android NDK提供的arm-eabi-strip工具,移除native庫中不必要的debug標識,之後, 你就可以編譯發佈構建。
2)避免提取native庫
存儲未壓縮的.so文件,以及在app manifest文件標籤裏設置android:extractNativeLibs標識爲false。這將避免PackageManager在安裝期間從APK拷貝.so文件到文件系統,並且將有使增量APP更新變小的額外好處。

(13)維護多個瘦身APK

你的apk會包含用戶下載但從來未使用的內容,比如區域或語言。爲用戶創建一個最小的下載,你可以通過考量屏幕尺寸或GPU紋理的支持等因素,來將你的APP分拆成幾個APK.
當一個用戶下載你的APP時,他的設備應該接收到和這個設備的特性和設置相匹配的正確的APK,用這種方式,設備不會接收到該設備不具有特性的資源,舉個例子,如果用戶有個hdpi設備,那麼該設備將不必需要包含更高顯示密度的xxxhdpi資源。
更多的APK瘦身方法請看Configure APK SplitsMaintaining Multiple APKs

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章