Determinar de forma personalizada los recursos que se conservarán

Cuando habilitas la optimización de la app, el comportamiento predeterminado del optimizador es diferente para las distintas versiones de R8.

  • Con el DSL actualizado que está disponible desde AGP 9.3 y versiones posteriores, la reducción de recursos se habilita de forma predeterminada cuando se habilita la optimización. Ten en cuenta que aún se admite el DSL heredado, que requiere que la optimización de código y recursos se habilite de forma independiente.
  • En las versiones anteriores a AGP 9.3, el parámetro de configuración isShrinkResources = true indica al optimizador que quite los recursos que no se usan, lo que ayuda a reducir el tamaño de la app. La reducción de recursos solo funciona en conjunto con la reducción de código, por lo que, si optimizas los recursos, también debes establecer isMinifyEnabled = true.

AGP 9.3 y versiones posteriores (Kotlin)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

AGP 9.3 y versiones posteriores (Groovy)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

DSL heredado (Kotlin)

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

DSL heredado (Groovy)

buildTypes {
    release {
        minifyEnabled = true
        shrinkResources = true
        ...
    }
}

Si deseas conservar o descartar recursos específicos, crea un archivo keep en formato XML en los recursos del proyecto, por ejemplo, res/raw/keep_my_package.xml. El archivo de conservación tiene los siguientes componentes:

  • Etiqueta <resources>: Contiene todos los elementos de recursos secundarios y los atributos de conservación o descarte.
  • Atributo tools:keep: Acepta una lista separada por comas de nombres de recursos que identifican los recursos que se conservarán.
  • Atributo tools:discard: Acepta una lista separada por comas de nombres de recursos que identifican los recursos que se descartarán.

Usa el carácter de asterisco como comodín para hacer referencia a varios recursos en la misma carpeta, por ejemplo:

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

Especificar qué recursos descartar puede parecer superfluo cuando podrías borrarlos, pero descartar recursos puede ser útil cuando se usan variantes de compilación.

Cómo segmentar compilaciones específicas

Para quitar recursos solo en algunas variantes de compilación, coloca todos tus recursos en el directorio común del proyecto y, luego, crea un archivo keep_my_package_build_variant.xml diferente para cada variante de compilación en el directorio de recursos de la variante. En el archivo de conservación, especifica manualmente los recursos que se quitarán cuando un recurso determinado parezca usarse en el código (y, por lo tanto, no lo quite el reductor), pero sabes que, en realidad, no se usará para la variante de compilación determinada.

Cómo quitar recursos alternativos que no se usan

El optimizador solo quita los recursos a los que no se hace referencia en el código de tu app, lo que significa que no quitará los recursos alternativos para diferentes configuraciones de dispositivos.

Usa la propiedad resConfigs de Android Gradle en el archivo build.gradle del módulo de tu app para quitar archivos de recursos alternativos que tu app no necesite.

Por ejemplo, si usas una biblioteca que incluye recursos de idioma (como los Servicios de Google Play), tu app incluye todas las cadenas de idioma traducidas para los mensajes de esas bibliotecas, independientemente de si el resto de la app está traducido a los mismos idiomas. Para conservar solo los idiomas que tu app admite oficialmente, especifícalos con la propiedad resConfigs. Se quitarán los recursos para idiomas que no se especifiquen.

En los siguientes fragmentos, se muestra cómo limitar los recursos de idioma solo a inglés y francés:

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

o

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

Cuando publicas una app con el formato de Android App Bundle (AAB), de forma predeterminada, solo se descargan los idiomas configurados en el dispositivo del usuario cuando este instala la app. Del mismo modo, solo se incluyen en la descarga los recursos que coinciden con la densidad de pantalla del dispositivo y las bibliotecas nativas que coinciden con la ABI del dispositivo. Para obtener más información, consulta Cómo habilitar o inhabilitar tipos de APK de configuración.

En el caso de las apps heredadas que se lanzan con APKs (creadas antes de agosto de 2021), puedes compilar varios APKs que se segmenten para diferentes configuraciones de dispositivos y, así, personalizar los recursos de densidad de pantalla o ABI que se incluirán en tu APK.

Evita conflictos cuando combines recursos

De forma predeterminada, el complemento de Android para Gradle (AGP) combina los recursos con el mismo nombre, como los elementos de diseño con el mismo nombre que se encuentran en diferentes carpetas de recursos. Este comportamiento no está controlado por la propiedad shrinkResources y no se puede inhabilitar porque es necesario para evitar errores cuando varios recursos tienen el nombre al que hace referencia tu código.

La combinación de recursos solo se produce cuando dos o más archivos comparten un nombre, un tipo y un calificador de recursos idénticos. AGP selecciona el archivo que identifica como la mejor opción entre los duplicados (según un orden de prioridad que se describe a continuación) y pasa solo ese recurso a AAPT para su distribución en el artefacto de compilación final.

AGP busca recursos duplicados en las siguientes ubicaciones:

  • Recursos principales, asociados al conjunto principal de orígenes, que suelen ubicarse en src/main/res/
  • Superposiciones de variantes, de los tipos y las variantes de compilación
  • Dependencias del proyecto de biblioteca

AGP combina los recursos duplicados en el siguiente orden de prioridad en cascada:

Dependencias → Principal → Variante de compilación → Tipo de compilación

Por ejemplo, si un recurso duplicado aparece tanto en los recursos principales como en una variante de compilación, Gradle selecciona el recurso en la variante de compilación.

Si aparecen recursos idénticos en el mismo conjunto de orígenes, Gradle no puede combinarlos y emite un error de combinación de recursos. Esto puede suceder si defines varios conjuntos de orígenes en la propiedad sourceSet del archivo build.gradle de tu módulo, por ejemplo, si src/main/res/ y src/main/res2/ contienen recursos idénticos.

Cómo solucionar problemas de reducción de recursos

Cuando reduces los recursos, la ventana Build muestra un resumen de los recursos que se quitaron de la app. (Haz clic en Toggle view en el lado izquierdo de la ventana para mostrar el resultado de texto detallado de Gradle). Por ejemplo:

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

Gradle también crea un archivo de diagnóstico llamado resources.txt en <module-name>/build/outputs/mapping/release/ (la misma carpeta que los archivos de salida de ProGuard). El archivo incluye detalles como qué recursos hacen referencia a otros recursos y qué recursos se usan o se quitan.

Por ejemplo, para saber por qué @drawable/ic_plus_anim_016 sigue en tu app, abre el archivo resources.txt y busca ese nombre de archivo. Es posible que veas que se hace referencia a él desde otro recurso:

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

Ahora debes saber por qué se puede acceder a @drawable/add_schedule_fab_icon_anim. Si buscas hacia arriba, encontrarás el recurso en el encabezado The root reachable resources are: en resources.txt.

Esto significa que hay una referencia de código a add_schedule_fab_icon_anim, es decir, se encontró su ID de R.drawable en el código accesible.

A menos que uses la verificación estricta, los IDs de recursos se pueden marcar como accesibles si hay constantes de cadena que parecen que se podrían usar para construir nombres de recursos para los recursos cargados de forma dinámica. En ese caso, si buscas el nombre del recurso en el resultado de la compilación, es posible que encuentres un mensaje como este:

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.

Si ves una de estas cadenas y tienes la certeza de que no se usa para cargar el recurso determinado de forma dinámica, usa el atributo tools:discard en tu archivo de conservación para informar al sistema de compilación que quite el recurso.