Android性能優化-減小APK大小


前言

用戶通常會避免下載比較大的應用,特別是連接到2G和3G網絡,或者按流量收費的設備。這篇文章描述了如何減小apk的大小,幫助你讓更多的用戶下載你的app。

一 理解APK的結構

在討論如何減小apk大小之前,理解apk的結構很有必要。一個APK文件包括一個ZIP 文件,該ZIP包含app的所有文件。包括java 字節碼文件,資源文件和一個包含了編譯后的資源文件。APK包含以下目錄:

  • META-INF/:包含了CERT.SF 和 CERT.RSA 簽名文件, 以及 MANIFEST.MFmanifest 文件.
  • assets/: 包含了app的assets,app可以通過 AssetManager 對象獲取到這些資源
  • res/: 包含了那些沒有被編譯到 resources.arsc的資源
  • lib/: 包含了用於軟件處理器的編譯代碼,該目錄包含一個子目錄,針對不同平台: armeabiarmeabi-v7aarm64-v8ax86x86_64, and mips.

一個APK也包含了下面的文件,但只有 AndroidManifest.xml 是強制性的

  • resources.arsc:

    包含了編譯后的資源。該文件包含了 res/values/文件夾下的所有XML內容。打包工具抽取了XML內容,將它編譯成二進制格式,並且進行了壓縮。該內容包括language strings和styles,以及未直接包含在resources.arsc 文件中的內容路徑。比如layout文件和圖片。

  • classes.dex:

    包含可以被Dalvik/ART 識別,以dex文件格式編譯后的代碼

  • AndroidManifest.xml:

    包含了Android核心mainfest文件。該文件羅列了app名字,版本,訪問權限,和引用的library文件。該文件采用二進制XML格式。

二 減少資源的數量和大小

APK的大小對app的加載速度以及內存的使用和電量消耗都有影響。一種減小APK大小的最簡單方法就是減少APK的資源文件數量和大小。也可以移除那些app不再使用的資源,或者使用可擴展的 Drawable 對象替代圖片文件。這部分討論了這些方法,以及其它幾種減小app資源以便最終達到減小APK總體大小的其它方法。

移除無用資源

使用 lint 工具,AndroidStudio中的一個靜態的代碼分析工具。可以檢測res/ 目錄下那些沒有被引用的資源. 當 lint工具發現了項目中潛在的無用資源,就會打印類似如下的信息:

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

注意: lint 工具不能夠掃描assets/ 目錄, assets 資源是通過反射的方式引用的,或者app中引用的其它library 文件。但lint並不會移除資源,它只會提示它們的存在。

你引入的Libraries有可能引入了無用的資源。Gradle可以通過在 build.gradle 文件中開啟shrinkResources 來幫你自動的移除這些資源:

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 選項把這些信息傳遞給構建系統。構建系統會阻止來自其它不受支持的資源出現在APK中,從而減少APK的大小。更多信息可以參考 Remove unused alternative resources

最小化使用Libraries中的資源

在開發App的時候,通常會使用外部libraries去提升app的可用性和功能擴展。比如,你可能會引用Android Support Library去提升老設備的用戶體驗。或者使用 Google Play Services 為app提供自動翻譯。

如果一個library被設計用於桌面服務,那么就可能包含很多app不需要的對象和方法。為了只保留library中app需要的代碼,如果license許可的話,你需要編輯library文件。你也可以使用一個移動端友好的替代庫。

注意: ProGuard 可以清除一些從library中導入的不需要的代碼。但是不會移除一個 library的內部依賴。

只支持特定的分辨率

Android支持非常大的設備集,包括各種屏幕密度。 在Android 4.4(API級別19)及更高版本中,框架支持各種分辨率:ldpi,mdpi,tvdpi,hdpi,xhdpi,xxhdpi和xxxhdpi。 雖然Android支持所有這些分辨率,但你不需要導出光柵化資源到每種分辨率。

如果你知道只有一小部分用戶使用特定分辨率的設備,請考慮是否需要支持這些分辨率。 如果你不包括特定屏幕密度的資源,Android會自動縮放最初為其他屏幕密度設計的現有資源。

如果您的應用只需要縮放的圖片,您可以通過在drawable-nodpi /中使用圖片的單個版本來節省更多空間。 我們建議每個應用至少包含一個xxhdpi圖片版本。

更多屏幕分辨率的信息,可以參考 Screen Sizes and Densities.

減少動畫幀數

逐幀動畫可能會大幅增加APK的大小。 圖1中展示了一個幀動畫被分成多個PNG文件的情況。 每個圖像是動畫中的一幀。

對於添加到動畫中的每一幀,都會增加APK中存儲的圖片數量。 在圖1中,圖像在應用程序中以30 FPS動畫。 如果圖像僅以15FPS動畫化,則動畫將僅需要所需幀的數目的一半。

Use Drawable Objects

一些圖像不需要靜態圖像資源; 框架可以在運行時動態地繪制圖像。 相反,Drawable對象(XML中的)可能只會占用APK中的一小部分空間。 此外,XML形式的Drawable對象可以生成符合MaterialDesign指南的單色圖像。

減少資源

你可能為同一種圖像的不同形式都提供了獨立的資源,例如同一圖像的有色,陰影或旋轉版本。 但是,我們建議你重復使用相同的資源,在運行時根據需要進行自定義。

Android提供了幾個工具來更改資源的顏色,可以在Android 5.0(API級別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_arrow_expand"
    android:fromDegrees="180"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="180" />

從代碼中渲染

You can also reduce your APK size by procedurally rendering your images. Procedural rendering frees up space because you no longer store an image file in your APK.

你也可以通過程序對圖像渲染來減少APK大小。 通過程序渲染可以節約空間是因為不需要在APK中存儲圖像文件。

壓縮PNG文件

aapt工具可以在構建過程期間優化放置在res / drawable /中的圖像資源,以及無損壓縮。 例如,aapt工具可以將不需要多於256種顏色的真彩色PNG轉換為具有調色板的8位PNG。 這樣做會產生質量相同但占用內存較小的映像。

但請記得aapt有以下限制:

  • aapt工具不會收縮asset/文件夾中包含的PNG文件。
  • 圖像文件需要使用256個或更少的顏色的aapt工具來優化它們。
  • aapt工具可能會填充已壓縮的PNG文件。 為了防止這種情況,您可以在Gradle中使用cruncherEnabled標志為PNG文件禁用此過程:
aaptOptions {
    cruncherEnabled = false
}

壓縮PNG和JPG文件

你可以使用像 pngcrushpngquant, 或zopflipng等工具來減少PNG文件大小,而不會損失圖像質量。 所有這些工具都可以減少PNG文件大小,同時保持圖像質量。

pngcrush工具特別有效:此工具在PNG過濾器和zlib(Deflate)參數上迭代,使用每個過濾器和參數的組合來壓縮圖像。 然后選擇產生最小壓縮輸出的配置。

對於JPEG文件,您可以使用 packJPG 等工具將JPEG文件壓縮為更緊湊的形式。

使用WebP 文件格式

除了使用PNG或JPEG文件,你還可以使用WebP的圖像文件。 WebP格式提供有損壓縮(如JPEG)和透明度(如PNG),但可以提供比JPEG或PNG更好的壓縮。

但是,使用WebP文件格式有一些顯着的缺點。 首先,在低於Android 3.2(API級別13)的平台版本中不支持WebP。 第二,系統解碼WebP比PNG文件需要更長的時間。

注意:Google Play只接受使用PNG格式的圖標。 如果你打算通過Google Play發布應用,圖標就不能使用其他文件格式(如JPEG或WebP)。

使用矢量圖形

你可以使用矢量圖形創建分辨率獨立的圖標和其他可伸縮媒體。 使用這些圖形可以大大減少APK體積。 矢量圖像在Android中表示為VectorDrawable對象。 使用VectorDrawable對象,100字節的文件可以生成屏幕大小的清晰圖像。

然而,系統渲染每個VectorDrawable對象需要大量的時間,較大的圖像則需要更長的時間才能出現在屏幕上。 因此,只有在顯示小圖像時才考慮使用這些矢量圖形。

有關使用VectorDrawable對象的更多信息,請參考 Working with Drawables.

三 減少Native和Java代碼

刪除不必要的生成代碼

確保你能夠理解那些任何自動生成的代碼部分。 例如,許多協議緩沖工具生成過多的方法和類,可以使應用程序的大小增加一倍或兩倍。

刪除枚舉

單個枚舉可能為應用程序的classes.dex文件添加大小為1.0到1.4 KB的大小。 對於復雜的系統或者共享庫,這種增加可能比較快迅速。 如果可能,請考慮使用@IntDef注解和ProGuard 來除去枚舉並將它們轉換為整數。 這種類型轉換保留了枚舉的所有類型安全的好處。

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

如果你的應用使用本地代碼和Android NDK,你還可以通過優化這些代碼來減小應用的大小。 兩個有用的方式是刪除debug標記,不提取本地庫。

刪除Debug符號

如果你的應用程序正在開發中並仍需要調試,那么使用debug標記很有意義。 使用Android NDK中提供的 arm-eabi-strip 工具從本地庫中刪除不必要的調試標記。 之后,再編譯release版本。

避免提取本地庫

將.so文件存儲在APK中未壓縮的文件中,並在應用清單的``元素中將android:extractNativeLibs標記設置為false。 這將防止PackageManager在安裝過程中將.so文件從APK復制到文件系統,並且有一個額外的好處,會讓app的差分更新變得更小。

四 維護多個精簡版APK

你的APK可能包含用戶下載但從不使用的內容,例如區域或語言信息。 為了讓用戶提供最小化的下載,你可以將應用細分為多個APK,並根據屏幕尺寸或GPU紋理支持等因素進行區分。

當用戶下載您的應用時,其設備會根據設備的功能和設置接收正確的APK。 這樣,設備不會接收設備沒有的功能的資源。 例如,如果用戶擁有的是hdpi設備,那么他們不需要你為更高分辨率設備提供的xxxhdpi資源。

更多信息請參考Configure APK Splits and Maintaining Multiple APKs.

 

來源:http://www.lightskystreet.com/2016/10/17/android-optimize-apk/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM