保持するリソースのカスタマイズ

アプリの最適化を有効にすると、isShrinkResources = true 設定により、未使用のリソースを削除するようにオプティマイザーに指示されます。これにより、アプリのサイズを削減できます。リソースの圧縮はコードの圧縮と連動して機能するため、リソースを最適化する場合は isMinifyEnabled = true も設定します。次に例を示します。

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

特定のリソースを保持または破棄する場合は、プロジェクト リソース(res/raw/my.package.keep.xml など)に XML keep ファイルを作成します。keep ファイルには次のコンポーネントがあります。

  • <resources> タグ - すべての子リソース要素と keep/discard 属性が含まれます。
  • 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 ファイルを作成します。keep ファイルで、特定のリソースがコードで使用されているように見える(そのため、圧縮ツールによって削除されない)が、特定のビルド バリアントでは実際に使用されないリソースを手動で指定します。

未使用の代替リソースの削除

オプティマイザーは、アプリのコードで参照されていないリソースのみを削除します。つまり、オプティマイザーは、さまざまなデバイス設定の代替リソースは削除しません。

アプリのモジュール 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 に含める画面密度や ABI リソースをカスタマイズできます。

リソースの統合時に競合を回避する

デフォルトでは、Android Gradle プラグイン(AGP)は、異なるリソース フォルダにある同じ名前のドローアブルなど、同一の名前を持つリソースを結合します。この動作は、shrinkResources プロパティによって制御することも、無効にすることもできません。これは、コードが参照している名前が複数のリソースに存在する場合にエラーを回避するために必要な動作です。

リソースの結合は、2 つ以上のファイルが同一のリソース名、タイプ、修飾子を共有している場合にのみ行われます。AGP は(下記の優先順位に基づいて)重複ファイルのうち最適と判断したファイルを選択し、最終的なビルド アーティファクトでの配布用にそのリソースひとつだけを AAPT に渡します。

AGP は次の場所で重複リソースを検索します。

  • メインリソース。メイン ソースセットと関連付けられていて、通常は src/main/res/ にあります。
  • ビルドタイプとビルド フレーバーからなるバリアント オーバーレイ
  • ライブラリ プロジェクトの依存関係

AGP は、次の優先順位に従って重複リソースを結合します。

依存関係 → メイン → ビルド フレーバー → ビルドタイプ

たとえば、メインリソースとビルド フレーバーの両方に重複リソースがある場合、Gradle はビルド フレーバー内のリソースを選択します。

同じソースセットに同一のリソースがある場合、Gradle はこれらのリソースを結合できないため、リソース結合エラーを出力します。このエラーは、モジュール build.gradle ファイルの sourceSet プロパティで複数のソースセットが定義されている場合に発生する可能性があります(src/main/res/src/main/res2/ の両方に同じリソースが格納されている場合など)。

リソース圧縮のトラブルシューティング

リソースを圧縮すると、アプリから削除されたリソースの概要が [Build] ウィンドウに表示されます(ウィンドウの左側にある [ビューの切り替え] をクリックして、Gradle からの詳細なテキスト出力を表示します)。次に例を示します。

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

また、Gradle は <module-name>/build/outputs/mapping/release/(ProGuard の出力ファイルと同じフォルダ)に resources.txt という名前の診断ファイルを作成します。このファイルには、どのリソースが他のリソースを参照したか、どのリソースが使用または削除されたかなどの詳細情報が記載されます。

たとえば、アプリに @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 属性を使用して、そのリソースを削除するようビルドシステムに指示します。