自訂要保留的資源

當您啟用應用程式最佳化功能時,isShrinkResources = true 設定會指示最佳化工具移除未使用的資源,有助於縮減應用程式大小。資源縮減功能僅適用於程式碼縮減,因此如果您要最佳化資源,請一併設定 isMinifyEnabled = true,例如:

buildTypes {
    release {
        isMinifyEnabled = true
        isShrinkResources = true
        ...
    }
}

如要保留或捨棄特定資源,請在專案資源中建立 XML keep 檔案,例如 res/raw/my.package.keep.xml。keep 檔案包含下列元件:

  • <resources> 標記:包含所有子資源元素和保留/捨棄屬性。
  • tools:keep 屬性:接受以半形逗號分隔的資源名稱清單,用於識別要保留的資源
  • tools:discard 屬性:接受以半形逗號分隔的資源名稱清單,用於識別要捨棄的資源

使用星號字元做為萬用字元,即可參照同一個資料夾中的多個資源,例如:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

指定應捨棄的資源似乎毫無用處,因為您可以進行刪除,但這在建構變化版本中很實用。

指定特定建構變化版本

如要只移除部分建構變化版本中的資源,請將所有資源放入通用專案目錄,然後為每個建構變化版本在變化版本的資源目錄中建立不同的 my.package.build.variant.keep.xml 檔案。在保留檔案中,手動指定資源,以便在程式碼中使用特定資源 (因此不會由縮減器移除),但您知道實際上不會用於特定建構變化版本時移除該資源。

移除未使用的替代資源

最佳化工具只會移除應用程式程式碼未參照的資源,因此不會移除不同裝置設定的替代資源

您可以使用應用程式模組 build.gradle 檔案中的 Android Gradle resConfigs 屬性,移除應用程式不需要的其他資源檔案。

例如,如果您使用的程式庫包含語言資源 (例如 Google Play 服務),則您的應用程式會包含這些程式庫中訊息的所有翻譯語言字串,無論您的應用程序的其餘部分是否被翻譯成相同的語言。如要只保留應用程式官方支援的語言,請使用 resConfigs 屬性指定這些語言。系統會移除任何未指定語言的資源。

下列程式碼片段說明如何將語言資源限制為英文和法文:

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

使用 Android App Bundle (AAB) 格式發布應用程式時,根據預設,使用者安裝應用程式時,系統只會下載使用者裝置上已設定的語言。同樣地,下載內容只會包含與裝置螢幕密度相符的資源,以及與裝置 ABI 相符的原生程式庫。詳情請參閱「重新啟用或停用設定 APK 的類型」。

如果舊版應用程式使用 APK 發布 (2021 年 8 月前建立),您可以建構多個 APK (每個 APK 針對不同的裝置設定),以自訂要包含在 APK 中的螢幕密度或 ABI 資源。

避免合併資源時發生衝突

根據預設,Android Gradle 外掛程式 (AGP) 會合併名稱相同的資源,例如位於不同資源資料夾中的同名可繪項目。這個行為不受 shrinkResources 屬性控管,而且無法停用,因為如果有多個資源符合您的程式碼參照名稱,就必須避免這些錯誤。

只有在兩個以上的檔案共用相同的資源名稱、類型和限定詞時,系統才會合併資源。AGP 會在複本中選出最適合的檔案 (依據下方所述的優先順序),並且只將一項資源傳送給 AAPT,以便在最終版本成果中發布。

AGP 會在下列位置尋找重複的資源:

  • 與主要來源集相關聯的主要資源,通常位於 src/main/res/
  • 子類疊加層,來自建構類型和建構版本
  • 程式庫專案依附元件

AGP 會根據下列優先順序合併重複的資源:

依附元件 → 主要 → 版本版本 → 建構類型

例如,如果主要資源和建構版本出現在重複的資源,Gradle 會選取建構版本中的資源。

如果相同的資源出現在相同的來源集中,Gradle 就無法合併資源,且會提示資源合併錯誤。如果在模組 build.gradle 檔案的 sourceSet 屬性中定義多個來源集,例如 src/main/res/src/main/res2/ 都含有相同的資源,就會發生這種情況。

資源縮減疑難排解

收合資源時,「Build」視窗會顯示從應用程式移除的資源摘要。(按一下視窗左側的「Toggle view」,即可顯示 Gradle 的詳細文字輸出)。例如:

:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

Gradle 也會在 <module-name>/build/outputs/mapping/release/ 中建立名為 resources.txt 的診斷檔案 (與 ProGuard 的輸出檔案位於同一個資料夾)。這個檔案內含哪些資源會參照其他資源,以及如何運用或移除資源。

例如,如要找出 @drawable/ic_plus_anim_016 仍在應用程式中的原因,請開啟 resources.txt 檔案並搜尋檔案名稱。您可能會發現,它從其他資源中進行了參照:

16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016

您現在需要知道 @drawable/add_schedule_fab_icon_anim 可以存取的原因,如果您向上搜尋,就會看到資源列於 resources.txt 中的「The root reachable resources are:」標題下方。

這表示 add_schedule_fab_icon_anim 有程式碼參照,也就是說,可在可連接的程式碼中找到其 R.drawable ID。

除非您使用嚴格檢查,否則如果有字串常數可用來建立動態載入資源的資源名稱,就可以將資源 ID 標示為可連項目。在這種情況下,如果您搜尋資源名稱的建構輸出內容,可能會看到如下的訊息:

10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
    used because its format-string matches string pool constant ic_plus_anim_%1$d.

如果您看到其中一個字串,而且確定該字串並未用於動態載入指定資源,請在 keep 檔案中使用 tools:discard 屬性,通知建構系統移除該資源。