When you [enable app optimization](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization), the `isShrinkResources = true` setting
instructs the optimizer to remove resources that are unused, which helps reduce
the size of your app. Resource shrinking works only in conjunction with code
shrinking, so if you're optimizing resources, also set `isMinifyEnabled = true`,
for example:  

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

If you want to keep or discard specific resources, create an XML *keep* file in
your project resources, for example `res/raw/my.package.keep.xml`. The keep file
has the following components:

- `<resources>` tag --- Contains all child resource elements and keep/discard attributes.
- `tools:keep` attribute --- Accepts a comma-separated list of resource names that identify resources to keep
- `tools:discard` attribute --- Accepts a comma-separated list of resource names that identify resources to discard

Use the asterisk character as a wildcard to reference multiple resources in the
same folder, for example:  

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

| **Note:**
|
| - Keep files have global scope. Give your keep files unique filenames that include the file's package name. Unique filenames ensure keep files from different libraries won't conflict, causing potential issues with ignored rules or unneeded kept resources, when different libraries are linked together.
| - The build doesn't package the keep file into your app.
| - You should rarely need to keep resources. The use of [`getIdentifier()`](https://developer.android.com/reference/android/content/res/Resources#getIdentifier(java.lang.String,%20java.lang.String,%20java.lang.String)) is an exception; however, retrieving resources by identifier is more efficient than retrieving them by name with `getIdentifier()`.

Specifying which resources to discard might seem superfluous when you could
instead delete them, but discarding resources can be useful when using build
variants.

## Target specific build variants

To remove resources in only some build variants, put all your resources into the
common project directory, then create a different
`my.package.build.variant.keep.xml` file for each build variant in the variant's
resource directory. In the keep file, manually specify resources to remove when
a given resource appears to be used in code (and therefore not removed by the
shrinker), but you know it actually won't be used for the given build variant.

## Remove unused alternative resources

The optimizer only removes resources that aren't referenced by your app code,
which means the optimizer won't remove [alternative resources](https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources) for different
device configurations.

Use the Android Gradle `resConfigs` property in your app's module `build.gradle`
file to remove alternative resource files that your app does not need.

For example, if you are using a library that includes language resources (such
as Google Play Services), then your app includes all translated language strings
for the messages in those libraries whether the rest of your app is translated
to the same languages or not. To keep only the languages that your app
officially supports, specify those languages using the `resConfigs` property.
Any resources for languages not specified are removed.

The following snippets show how to limit your language resources to just English
and French:  

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

or  

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

When you publish an app using the Android App Bundle (AAB) format, by default
only languages configured on a user's device are downloaded when the user
installs the app. Similarly, only resources matching the device's screen density
and native libraries matching the device's ABI are included in the download. For
more information, see [Re-enable or disable types of configuration APKs](https://developer.android.com/guide/app-bundle/configure-base#disable_config_apks).

For legacy apps releasing with APKs (created before August 2021), you can
customize the screen density or ABI resources to include in your APK by
[building multiple APKs](https://developer.android.com/studio/build/configure-apk-splits) that target different device configurations.

## Avoid conflicts when merging resources

By default, the Android Gradle plugin (AGP) merges identically named resources,
such as drawables with the same name that are in different resource folders.
This behavior is not controlled by the `shrinkResources` property and cannot be
disabled because the behavior is necessary to avoid errors when multiple
resources have the name your code is referencing.

Resource merging occurs only when two or more files share an identical resource
name, type, and qualifier. AGP selects the file it identifies to be the best
choice among the duplicates (based on a priority order described below) and
passes only that one resource to AAPT for distribution in the final build
artifact.

AGP looks for duplicate resources in the following locations:

- Main resources, associated with the main source set, generally located in `src/main/res/`
- Variant overlays, from the build type and build flavors
- Library project dependencies

AGP merges duplicate resources in the following cascading priority order:  
Dependencies → Main → Build flavor → Build type

For example, if a duplicate resource appears in both your main resources and a
build flavor, Gradle selects the resource in the build flavor.

If identical resources appear in the same source set, Gradle cannot merge them
and emits a resource merge error. This can happen if you define multiple source
sets in the `sourceSet` property of your module `build.gradle` file, for
example, if both `src/main/res/` and `src/main/res2/` contain identical
resources.

## Troubleshoot resource shrinking

When you shrink resources, the **Build** window shows a summary of the resources
removed from the app. (Click **Toggle view** on the left side of the window to
display detailed text output from Gradle.) For example:  

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

Gradle also creates a diagnostic file named `resources.txt` in
`<module-name>/build/outputs/mapping/release/` (the same folder as ProGuard's
output files). The file includes details such as which resources reference other
resources and which resources are used or removed.

For example, to find out why `@drawable/ic_plus_anim_016` is still in your app,
open the `resources.txt` file and search for that filename. You might find that
it's referenced from another resource:  

    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

You now need to know why `@drawable/add_schedule_fab_icon_anim` is reachable;
and if you search upwards, you'll find the resource listed under the heading
*The root reachable resources are:* in `resources.txt`.

This means there's a code reference to `add_schedule_fab_icon_anim`, that is,
its `R.drawable` ID was found in the reachable code.

Unless you're using strict checking, resource IDs can be marked as reachable if
there are string constants that look like they might be used to construct
resource names for dynamically loaded resources. In that case, if you search the
build output for the resource name, you might find a message like this:  

    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.

If you see one of these strings and you are certain that the string is not being
used to load the given resource dynamically, use the `tools:discard` attribute
in your keep file to inform the build system to remove the resource.