Cuando habilitas la optimización de apps, la configuración de isShrinkResources = true
le 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 junto con la reducción de código, por lo que, si optimizas recursos, también debes configurar isMinifyEnabled = true
, por ejemplo:
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
...
}
}
Si deseas conservar o descartar recursos específicos, crea un archivo XML de conservación en los recursos de tu proyecto, por ejemplo, res/raw/my.package.keep.xml
. El archivo keep 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 de nombres de recursos separados por comas que identifican los recursos que se conservarán. - Atributo
tools:discard
: Acepta una lista de nombres de recursos separados por comas 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 los recursos que deben descartarse puede parecer superfluo, ya que puedes borrarlos, pero descartar recursos puede ser útil cuando usas variantes de compilación.
Cómo segmentar anuncios para variantes de compilación específicas
Para quitar recursos de solo algunas variantes de compilación, coloca todos tus recursos en el directorio del proyecto común y, luego, crea un archivo my.package.build.variant.keep.xml
diferente para cada variante de compilación en el directorio de recursos de la variante. En el archivo keep, especifica manualmente los recursos que se quitarán cuando un recurso determinado parezca usarse en el código (y, por lo tanto, el reductor no lo quite), 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 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 las diferentes opciones de configuración del dispositivo.
Usa la propiedad resConfigs
de Android para 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 en esas bibliotecas, sin importar si el resto de tu app está traducida a los mismos idiomas o no. Para mantener solo los idiomas que tu app admite oficialmente, especifícalos a través de la propiedad resConfigs
.
Los recursos para idiomas que no se especifiquen se eliminarán.
En los siguientes fragmentos, se muestra cómo limitar tus recursos de idioma a inglés y francés únicamente:
android {
defaultConfig {
...
resourceConfigurations.addAll(listOf("en", "fr"))
}
}
o
android {
defaultConfig {
...
resConfigs "en", "fr"
}
}
Cuando publicas una app con el formato 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 APK (que se crearon antes de agosto de 2021), puedes personalizar los recursos de ABI o las densidades de pantalla que quieras incluir en tu APK mediante la compilación de varios APK, cada uno orientado a una configuración del dispositivo diferente.
Evita conflictos cuando combines recursos
De forma predeterminada, el complemento de Android Gradle (AGP) fusiona los recursos con nombres idénticos, como los elementos de diseño con el mismo nombre que se encuentran en diferentes carpetas de recursos.
Este comportamiento no es controlado por la propiedad shrinkResources
y no puede inhabilitarse, ya que es necesario evitar errores cuando varios recursos tienen el nombre al que hace referencia tu código.
La fusión de recursos se produce cuando dos o más archivos comparten un nombre, un tipo y un calificador de recurso idénticos. AGP selecciona el archivo que identifica como la mejor opción entre los duplicados (en función del 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:
- Los recursos principales, asociados con el conjunto principal de orígenes, que generalmente se ubican en
src/main/res/
- Superposiciones de variantes, del tipo de compilación y de las variantes de compilación
- Dependencias del proyecto de biblioteca
AGP fusiona recursos duplicados en el siguiente orden de prioridad en cascada:
Por ejemplo, si un recurso duplicado aparece tanto en tus recursos principales como en un tipo de compilación, Gradle seleccionará el recurso en el tipo de compilación.
Si aparecen recursos idénticos en el mismo conjunto de orígenes, Gradle no podrá fusionarlos y emitirá un error de fusión de recursos. Esto puede suceder si defines varios conjuntos de orígenes en la propiedad sourceSet
de tu archivo build.gradle
del módulo, por ejemplo, si tanto src/main/res/
como src/main/res2/
contienen recursos idénticos.
Cómo solucionar problemas de reducción de recursos
Cuando reduces recursos, en la ventana Build, se 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 la salida de texto detallada de Gradle). Por ejemplo:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
Gradle crea, además, un archivo de diagnóstico llamado resources.txt
en <module-name>/build/outputs/mapping/release/
(la misma carpeta de los archivos de salida de ProGuard). El archivo incluye detalles como qué recursos hacen referencia a otros recursos y cuáles de estos se usan o se quitan.
Por ejemplo, para determinar la razón por la que @drawable/ic_plus_anim_016
aún está en tu app, abre el archivo resources.txt
y busca ese nombre de archivo. Es posible que descubras que se hace referencia a este 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
y, si buscas de manera ascendente, encontrarás que el recurso se enumera 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 alcanzable.
A menos que uses una comprobación estricta, los IDs de recursos pueden marcarse como accesibles si hay constantes de cadenas que parezcan que se usan para crear los nombres de los recursos cargados de forma dinámica. En ese caso, si buscas la salida de la compilación del nombre de recurso, es posible que encuentres un mensaje como el siguiente:
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 estás seguro de que no se usa para subir el recurso especificado de manera dinámica, usa el atributo tools:discard
en tu archivo de retención para informar al sistema de compilación que quite el recurso.