使用者通常會避免下載看似過大的應用程式,這種現象在新興市場尤為明顯,在這些地方,使用者的裝置通常是連接狀態不穩定的 2G 和 3G 網路,或使用按流量計費的方案。本頁說明如何縮減應用程式的下載大小,讓更多使用者下載您的應用程式。
使用 Android App Bundle 上傳應用程式
將應用程式上傳為 Android App Bundle,即可在發布至 Google Play 時立即縮減應用程式大小。Android App Bundle 是一種上傳格式,包含應用程式所有已編譯的程式碼和資源,但是需要較長的處理時間,才能產生及簽署 APK,發布到 Google Play 上。
上傳完畢後,Google Play 的應用程式提供模型就會使用應用程式套件,根據各個使用者的裝置設定產生並提供經過最佳化的 APK,讓使用者只下載執行應用程式所需的程式碼和資源。您不必建構、簽署及管理多個 APK 來支援不同的裝置,而且使用者下載的內容不但檔案較小,還會經過最佳化處理。
對於使用應用程式套件發布的應用程式,Google Play 會強制執行壓縮下載大小限制 (200 MB)。您可以使用 Play Feature Delivery 和 Play Asset Delivery 提供較大的應用程式,但增加應用程式大小可能會影響安裝成功率並增加解除安裝次數,因此建議您依循本頁所述規範,盡可能減少應用程式的下載大小。
瞭解 APK 結構
縮減應用程式大小之前,建議您先瞭解應用程式的 APK 結構。APK 檔案包含 ZIP 封存檔,內含應用程式的所有檔案,包括 Java 類別檔案、資源檔案,以及含有已編譯資源的檔案。
一個 APK 包含下列目錄:
META-INF/
:包含CERT.SF
和CERT.RSA
簽名檔案,以及MANIFEST.MF
資訊清單檔案。assets/
:包含應用程式的資源,應用程式可以透過AssetManager
物件擷取該資源。res/
:包含未編譯至resources.arsc
中的資源。lib/
:包含專屬於處理器軟體層的編譯程式碼。這個目錄包含每個平台類型的子目錄,例如armeabi
、armeabi-v7a
、arm64-v8a
、x86
、x86_64
和mips
。
APK 也包含下列檔案,只有 AndroidManifest.xml
是必要項目:
resources.arsc
:包含已編譯的資源。此檔案包含res/values/
資料夾所有設定中的 XML 內容。包裝工具會擷取此 XML 內容,將其以二進位格式編譯並封存。此內容包含語言字串和樣式,以及沒有直接納入resources.arsc
檔案的內容路徑 (例如:版面配置檔案和圖片)。classes.dex
:包含以 DEX 檔案格式編譯、且 Dalvik 或 ART 虛擬機器瞭解的類別。AndroidManifest.xml
:包含核心的 Android 資訊清單檔案。此檔案採用 Android 的二進位 XML 格式,列出應用程式的名稱、版本、存取權和參照程式庫檔案。
縮減資源數量和大小
APK 大小會影響應用程式載入的速度、記憶體用量,以及應用程式的耗電量。您可以減少 APK 所含的資源數量和大小,藉此縮減其大小。具體來說,您可以移除應用程式不再使用的資源,也能使用可延展的 Drawable
物件取代圖片檔。本節會說明這些方法,以及其他可以減少應用程式資源,縮減 APK 大小的方法。
移除未使用的資源
lint
工具是 Android Studio 中的靜態程式碼分析工具,可偵測 res/
資料夾中未由程式碼參照的資源。當 lint
工具在專案中發現可能未使用的資源,就會輸出訊息,可能如下所示:
res/layout/preferences.xml: Warning: The resource R.layout.preferences appears to be unused [UnusedResources]
您在程式碼中加入的程式庫可能包含未使用的資源。如果在應用程式的 build.gradle.kts
檔案中啟用 shrinkResources
,Gradle 就會自動為您移除資源。
Kotlin
android { // Other settings. buildTypes { getByName("release") { minifyEnabled = true shrinkResources = true proguardFiles(getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro") } } }
Groovy
android { // Other settings. buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
如要使用 shrinkResources
,請啟用程式碼縮減功能。在建構過程中,R8 會先移除未使用的程式碼。接著,Android Gradle 外掛程式會移除未使用的資源。
如要進一步瞭解程式碼和資源縮減功能,以及其他 Android Studio 縮減 APK 大小的方式,請參閱「縮減、模糊化及最佳化應用程式」一文。
在 Android Gradle 外掛程式 7.0 以上版本中,您可以宣告應用程式支援的設定。Gradle 會使用 resourceConfigurations
變種版本和 defaultConfig
選項,將這些資訊傳遞至建構系統。接著,建構系統會禁止來自其他不支援設定的資源顯示在 APK 中,進而縮減 APK 大小。如要進一步瞭解這項功能,請參閱「移除未使用的額外資源」。
將程式庫資源用量降至最低
開發 Android 應用程式時,您通常會使用外部程式庫提高應用程式的可用性和多功能性。舉例來說,您可以參照 AndroidX 來改善舊裝置的使用者體驗,也可以使用 Google Play 服務擷取應用程式中自動翻譯的文字內容。
如果程式庫是專為伺服器或電腦而設計,其中可能包含許多應用程式不需要的物件和方法。如果只要包含應用程式所需的程式庫部分,若授權允許您修改程式庫,您可以編輯程式庫的檔案。另外,您也可以使用適合行動裝置的程式庫,為應用程式新增特定功能。
原生動畫圖片解碼
在 Android 12 (API 級別 31) 中,NDK ImageDecoder
API 已擴展功能,可從 GIF 動畫和動態 WebP 檔案格式的圖片解碼所有影格和時間資料。
請使用 ImageDecoder
而非第三方程式庫,進一步減少 APK 大小,且方便進行日後的安全性和效能相關更新。
如要進一步瞭解 ImageDecoder
API,請參閱 API reference
和 GitHub 範例。
僅支援特定密度
Android 支援不同的螢幕密度,例如:
ldpi
mdpi
tvdpi
hdpi
xhdpi
xxhdpi
xxxhdpi
雖然 Android 支援這些密度,但您不需要將光柵化資源匯出至各個密度。
如果您確定只有一小部分使用者具備有特定密度的裝置,請考慮是否需要將這些密度納入應用程式。如果您沒有加入特定螢幕密度的資源,Android 會自動調整原先專為其他螢幕密度設計的現有資源。
如果您的應用程式只需要經過調整的圖片,您可以在 drawable-nodpi/
中使用單一圖片變化版本,藉此節省更多空間。建議您在應用程式中至少加入一個 xxhdpi
圖片變化版本。
如要進一步瞭解螢幕密度,請參閱「螢幕大小和密度」一文。
使用可繪項目物件
部分圖片不需要使用靜態圖片資源,架構可以在執行階段動態繪製圖片。在 APK 中,不管是 XML 中的 Drawable
或 <shape>
物件,佔用的空間都不大。除此之外,XML Drawable
物件還可產生符合 Material Design 指南的單色圖片。
重複使用資源
您可以針對圖片的變化版本加入個別資源,例如調整過色調、濃淡或旋轉的圖片版本。不過,我們建議您重複使用相同的資源組合,並在執行階段視需求自訂組合。
Android 提供多種公用程式,可使用 android:tint
和 tintMode
屬性變更資源的顏色。
如果某項資源只等同於另一個資源旋轉後的樣子,您也可以將其省略。以下程式碼片段示範如何在圖片中間以旋轉 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 大小。算繪處理作業可釋放空間,因為您不再將圖片檔儲存在 APK 中。
壓縮 PNG 檔案
aapt
工具可以在建構過程中,以無損壓縮的方式對 res/drawable/
中的圖片資源進行最佳化調整。舉例來說,aapt
工具可以透過調色盤,將不需要超過 256 種顏色的真實色彩 PNG 圖片轉換為 8 位元 PNG 圖片。這種方式產生的圖片品質相同,但記憶體用量較低。
aapt
具有下列限制:
aapt
工具不會壓縮asset/
資料夾中包含的 PNG 檔案。- 圖片檔的顏色必須在 256 色以下,
aapt
工具才能對其最佳化。 aapt
工具可能會加載已壓縮的 PNG 檔案。如要避免這種情況,可以使用isCrunchPngs
標記停用 PNG 檔案的程序:
Kotlin
buildTypes.all { isCrunchPngs = false }
Groovy
buildTypes.all { isCrunchPngs = false }
壓縮 PNG 和 JPEG 檔案
您可以使用 pngcrush、pngquant 或 zopflipng 等工具,在不犧牲圖片品質的情況下縮減 PNG 檔案大小。這些工具都能縮減 PNG 檔案的大小,同時維持良好的圖片品質。
pngcrush
工具特別有效率。這項工具會反覆疊代 PNG 篩選器和 zlib (Deflate) 參數,並運用各個篩選器和參數組合壓縮圖片,接著選用可產生最小壓縮輸出圖片的設定。
如要壓縮 JPEG 檔案,可以使用 packJPG 和 guetzli 等工具。
使用 WebP 檔案格式
除了使用 PNG 或 JPEG 檔案之外,您也可以使用 WebP 檔案格式的圖片。WebP 格式會有損壓縮和透明度 (例如 JPG 和 PNG),但壓縮效果比 JPEG 或 PNG 更好。
您可以使用 Android Studio,將現成的 BMP、JPG、PNG 或靜態 GIF 圖片轉換為 WebP 格式。詳情請參閱「建立 WebP 圖片」。
使用向量圖形
您可以使用向量圖形,建立與解析度無關的圖示和其他可延展的媒體。這類圖形可大幅減少 APK 大小。Android 系統中的向量圖片會以 VectorDrawable
物件形式呈現。使用 VectorDrawable
物件,100 位元組的檔案可以產生與螢幕大小相同的清晰圖片。
不過,系統算繪每個 VectorDrawable
物件所需的時間會大幅增加,而較大的圖片需要較長時間才會在螢幕畫面中顯示。因此,建議您只在要顯示小型圖片時才使用這些向量圖形。
如要進一步瞭解如何使用 VectorDrawable
物件,請參閱「可繪項目」。
針對動畫圖片使用向量圖形
請勿使用 AnimationDrawable
建立逐個影格的動畫,因為您必須為每個影格加入個別的點陣圖檔案,導致 APK 大小大幅增加。
請改用 AnimatedVectorDrawableCompat
建立動畫向量可繪項目。
減少原生和 Java 程式碼
您可以使用下列方法減少應用程式中的 Java 和原生程式碼集大小。
移除系統產生的多餘程式碼
請務必瞭解所有自動產生程式碼的足跡。舉例來說,許多通訊協定緩衝區工具會產生過多的方法和類別,可能導致應用程式大小增加一或二倍。
避免使用列舉項目
單一列舉項目會使應用程式的 classes.dex
檔案大小增加約 1.0 至 1.4 KB。如果是複雜的系統或共用程式庫,這些新增項目可能會快速累積檔案大小。如果可以,建議您使用 @IntDef
註解和程式碼縮減功能去除列舉項目,並將其轉換為整數。這種類型轉換可保留列舉項目的所有安全優勢。
縮減原生二進位檔的大小
如果應用程式使用原生程式碼和 Android NDK,您也可以對程式碼進行最佳化,藉此縮減應用程式版本的大小。移除偵錯符號及不擷取原生資料庫,是縮減大小的兩項實用技巧。
移除偵錯符號
如果應用程式處於開發階段,且且需進行偵錯,那麼就很適合使用偵錯符號。請使用 Android NDK 中提供的 arm-eabi-strip
工具,從原生資料庫移除不必要的偵錯符號。之後,您就可以編譯發布子版本。
避免擷取原生資料庫
建構應用程式的發布版本時,請在應用程式的 build.gradle.kts
檔案中將 useLegacyPackaging
設為 false
,封裝 APK 中未壓縮的 .so
檔案。停用此標記可防止 PackageManager
在安裝期間,從 APK 將 .so
檔案複製到檔案系統,進而縮減應用程式更新的大小。
維護多個精簡 APK
您的 APK 可能含有使用者下載但從未使用的內容,例如其他語言或個別螢幕密度的資源。如要盡可能減少使用者下載的項目,請使用 Android App Bundle 將應用程式上傳至 Google Play。上傳應用程式套件後,Google Play 會根據各使用者的裝置設定,產生並提供經過最佳化的 APK,讓使用者只下載執行應用程式所需的程式碼和資源。您不再需要為不同裝置建構、簽署及管理多個 APK,而且使用者下載的內容不但檔案較小,還經過最佳化處理。
如果未將應用程式發布至 Google Play,您可以將應用程式區隔成多個 APK,並依照螢幕大小或 GPU 材質支援等因素加以區別。
使用者下載應用程式後,裝置就會根據裝置的功能和設定接收正確的 APK。這樣一來,裝置就不會收到裝置沒有的功能相關資產。舉例來說,如果使用者使用的是 hdpi
裝置,就不需要加入適合高密度螢幕裝置使用的 xxxhdpi
資源。