APK瘦身指南

用戶一般會不會在應用市場上下載那些看起來很大的App,尤其是當他們使用2G或3G網絡或者是按流量付費的時候。因此這篇文章將講述如何減小APK的大小,從而讓更多的用戶來下載你的應用。

瞭解APK文件的結構

在探討如何減小App大小之前,有必要先弄清楚APK文件的結構。APK實質上是一個ZIP壓縮文件,它包含了構成App的所有文件,如Java類文件,資源文件,以及編譯後的資源文件等。

一個APK包含以下幾個文件目錄:

  • META-INF/:包含CERT.SF及CERT.RSA簽名文件以及MANIFEST.MF。
  • assets/:包含App的資源,這些資源文件可通過AssetManager獲取。
  • res/:包含了不會被編譯到resources.arsc中的資源。
  • lib:包含了特定於處理器軟件層的已編譯的代碼。該文件夾中針對不同處理器平臺架構提供不同子文件夾,如armeabi、armeabi-v7、arm64-v8a、x86、x86_64以及mips。

一個APK還包含了以下文件,其中,只有AndroidManifest.xml是強制性的。

  • resources.arsc:包含了編譯的資源,如res/values/文件夾中的xml文件將會被編譯到這裏。打包工具會將xml文件編譯爲二進制格式,包括strings及styles以及某些資源的路徑信息,如佈局文件以及圖片資源。
  • classes.dex:包含可被Dalvik或ART虛擬機執行的DEX文件。
  • AndroidManifest.xml:包含了Android的核心配置文件,該文件配置了應用的名稱、版本、訪問權限以及引用的類文件等信息。此文件也是被編譯爲二進制格式。

減少資源數量及大小

APK的大小會影響應用的加載速度、內存佔用以及電量消耗。一個簡單的減小APK的方法是減少它所用到的資源數量和大小。尤其是我們可以移除App中不再使用的資源,還可以使用Drawable來替代圖片文件。這一節將討論上述方法及其他幾種方案來減小App中的資源以達到APK瘦身的目的。

移除無用資源

使用Android Studio提供的靜態代碼分析工具——lint,可以檢測到res/文件夾中未被你的代碼引用的資源。一旦lint工具發現了潛在的未使用的資源,就會打印出如下信息:

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

注意:lint工具並不會掃描assets/文件夾、以及通過反射或library引用的資源;另外lint並不會移除資源,只是提醒它們的存在。

App中添加的一些Library可能包含無用的資源,如果我們在build.gradle文件中配置了shrinkResources,那麼Gradle可以幫助我們刪除這些資源文件。

android {
    // Other settings

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

爲了使用shrinkResources,需要允許代碼壓縮,在應用的構建過程中,首先ProGuard會移除無用代碼,但會保留未使用的資源,然後Gradle再移除未使用的資源。

更多關於ProGuard及其他Android Studio提供的APK壓縮方法,可參考Shrink Your Code and Resources

減小第三方庫的大小

開發一個Android應用時,會經常用到第三方庫來實現各種各樣的功能,例如,可能會使用Android Support Library來兼容老的設備以提升用戶體驗,或者可能使用Google Play Service實現App的文本自動翻譯功能。

如果一個庫是爲服務端或桌面應用設計的,它可能包含了很多App中用不到的對象和方法。爲了只引入App所用到的部分,如果該庫的許可允許修改,那麼我們可以修改精簡該庫;或者使用其他專門針對移動端的可替代庫來實現App功能。

注意:ProGuard可以移除library中的一些無用代碼,但無法刪除library中大的內部依賴。

僅支持特定屏幕密度

Android支持一系列設備,包括各種不同的屏幕分辨率。Android 4.4及更高的版本,支持衆多屏幕密度,如ldpi、mdpi、tvdpi、hdpi、xhdpi、xxhdpi、xxxhdpi。儘管Android支持上述所有屏幕密度,但我們不需要爲所有密度提供圖片資源。

如果你知道某個分辨率的設備使用者佔比很小,則可以考慮是否還要爲其提供針對性的資源。如果我們不提供某個分辨率的圖片資源,Android系統會自動將已存在的資源縮放以適配該屏幕密度。

如果應用僅需要可縮放的圖片,可以使用drawable-nodpi/以節省更多空間,同時推薦爲每個App至少配置一個xxhdpi圖片文件夾。

減少動畫的幀數

幀動畫會顯著增加APK的大小,因爲幀動畫一般會被分離成多張圖片,每張圖片代表動畫的一幀。

動畫中每添加一幀,意味着APK將增加一張圖片數量。

使用Drawable

一些圖片不需要靜態圖片資源,系統可以在運行時動態繪製。Drawable在APK中只佔用很小的空間,另外用XML表示的Drawable對象可以生成兼容Material Design指南的單色圖。

資源重用

對於着色、陰影、旋轉等效果,可以只使用一張獨立的圖片即可。這裏建議重用同一套資源,在需要的時候再進行自定義處理。

Android提供了一些列的實用工具來改變資源的顏色,如使用android:tint或tintMode屬性(API level 21+),對於低於Android 5.0的版本,則可以使用ColorFilter類。

對於圖片旋轉的需求,下面代碼片段提供了一個示例:簡單地將原始圖片選裝180度,從而將一個箭頭icon從“展開”狀態變爲“收起”狀態:

<?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" />

使用代碼渲染

可以使用程序代碼來渲染圖片以減小APK大小,因爲如果用代碼來實現的話,就不需要在APK中存儲圖片了。

Crunch PNG Files

在構建過程中,aapt工具可以對res/drawable/中的圖片進行無損優化,如aapt可使用調色板將小於256色的真彩色PNG圖片轉換爲8-bit的PNG。這樣做可以在不影響圖片質量的情況下減小內存佔用。

需要注意aapt有以下侷限性:

  • aapt工具不能壓縮assets/文件夾中的PNG文件

  • aapt工具只能優化那些不超過256色的圖片文件

  • aapt工具可能inflate被壓縮過的PNG文件,爲了禁止此功能,可以在Gradle中使用cruncherEnabled標誌:

    aaptOptions {
      cruncherEnabled = false
    }

壓縮PNG與JPEG文件

可以在不影響圖片質量的情況下對PNG文件進行壓縮,常用工具有 pngcrushpngquant,或者zopflipng。這些工具都可以減少PNG文件大小,同時保持圖像質量。

pngcrush是特別有效的工具,它會遍歷PNG過濾器和zlib(緊縮)參數,使用每個過濾器及參數的組合來壓縮圖像,然後選擇能夠產生最小壓縮輸出的配置。

對於JPEG文件,可以使用類似 packJPG的工具來將JPEG壓縮到更緊湊的形式。

使用WebP文件格式

除了使用PNG及JPEG文件外,還可以使用 WebP圖片格式來作爲替代。WebP擁有JPEG的無損壓縮以及PNG的透明度特性,同時可以提供更優於JPEG及PNG的壓縮效果。

使用WebP文件格式有幾個值得注意的缺陷,第一,低於Android3.2(API level 13)的系統不支持WebP,第二,使用WebP將花費比PNG文件更多的解碼時間。

注意:Google Play只接受應用圖標爲PNG格式的應用,不能使用其他文件格式,如果打算通過Google Play來分發應用,則不可使用JPEG或WebP格式的應用圖標。

使用矢量圖

可以使用矢量圖來創建分辨率無關的icon或者可縮放的多媒體,使用矢量圖可以極大地減小APK的大小。矢量圖在Android中表現爲VectorDrawable對象,使用VectorDrawable,100字節的大小就可以創建一個清晰的屏幕大小的圖片。

然而,使用VectorDrawable,系統需要更多的時間來渲染,如果圖片較大,則需要更長的時間才能顯示到屏幕上。因此,最好是在展示小圖片時考慮使用矢量圖。

減小Native與Java代碼的大小

可以使用以下幾種方法來減小Java代碼與Native代碼的大小。

移除不必要的生成代碼

請務必瞭解自動生成的代碼會佔用多大空間,例如,許多協議緩衝工具會產生過多的方法和類,它可以佔用雙倍或三倍於App的大小。

移除枚舉

單個枚舉可以使App的classes.dex文件增加1到1.4KB的大小,由於系統的複雜性及共享庫的使用,這種增加累計起來將會很可觀。如果可能,考慮使用@IntDef註解或者使用ProGuard將註解轉換爲整型,這種類型轉換可以保持枚舉類型的安全性。

減少本地二進制文件的大小

如果應用使用到本地代碼及Android NDK,我們可以通過優化代碼來減小應用的大小。兩種有用的技術可以刪除調試符號而不是提取本地庫。

刪除調試符號

在應用的開發與調試階段,使用調試符號是有意義。可以使用Android NDK提供的arm-eabi-strip工具來移除本地庫中不必要的調試符號。移除之後,我們可以編譯應用的release版本。

避免提取本地庫

將未壓縮的.so文件添加到APK中,在manifest配置文件的中將android:extractNativeLibs設爲false。做了上述配置後,在應用安裝時,PackageManager將不會把.so文件從APK中拷貝到文件系統,這樣做也有額外的好處,可以使App的增量更新變得更小。

維護多個專用APK

用戶下載了你的App,但很可能有些內容用戶不會用到,如地區及語言信息。爲了讓用戶得到最小化的下載,我們可以根據一些因素,如屏幕尺寸或對GPU的支持來將我們的App分化成多個App。

當用戶下載App時,可以根據用戶的設備信息與配置下載對應的APK,因此,該設備將不會收到與此設備本身支持的特性不匹配的資源要素。例如,用戶設備只支持hdpi,所以這些設備不需要爲高密度設備所準備的xxxhdpi資源。

官方原文:Reduce APK Size

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