Personnaliser les ressources à conserver

Lorsque vous activez l'optimisation de l'application, le paramètre isShrinkResources = true demande à l'optimiseur de supprimer les ressources inutilisées, ce qui permet de réduire la taille de votre application. La réduction des ressources ne fonctionne que parallèlement à la réduction du code. Par conséquent, si vous optimisez les ressources, définissez également isMinifyEnabled = true, par exemple:

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

Si vous souhaitez conserver ou supprimer des ressources spécifiques, créez un fichier XML keep dans les ressources de votre projet, par exemple res/raw/my.package.keep.xml. Le fichier keep contient les composants suivants:

  • Balise <resources> : contient tous les éléments de ressources enfants et les attributs de conservation/suppression.
  • Attribut tools:keep : accepte une liste de noms de ressources séparés par une virgule qui identifient les ressources à conserver.
  • Attribut tools:discard : accepte une liste de noms de ressources séparés par une virgule qui identifient les ressources à supprimer.

Utilisez le caractère astérisque comme caractère générique pour faire référence à plusieurs ressources dans le même dossier, par exemple:

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

Spécifier les ressources à supprimer peut sembler superflu, alors que vous pourriez les supprimer, mais supprimer des ressources peut s'avérer utile lorsque vous utilisez des variantes de compilation.

Cibler des variantes de compilation spécifiques

Pour supprimer des ressources dans certaines variantes de compilation uniquement, placez toutes vos ressources dans le répertoire de projet commun, puis créez un fichier my.package.build.variant.keep.xml différent pour chaque variante de compilation dans le répertoire de ressources de la variante. Dans le fichier keep, spécifiez manuellement les ressources à supprimer lorsqu'une ressource donnée semble être utilisée dans le code (et donc n'est pas supprimée par le réducteur), mais que vous savez qu'elle ne sera pas utilisée pour la variante de compilation donnée.

Supprimer les autres ressources non utilisées

L'optimiseur ne supprime que les ressources qui ne sont pas référencées par le code de votre application. Cela signifie qu'il ne supprime pas les autres ressources correspondant à des configurations d'appareil différentes.

Utilisez la propriété Android Gradle resConfigs dans le fichier build.gradle du module de votre application pour supprimer les fichiers de ressources dont votre application n'a pas besoin.

Par exemple, si vous utilisez une bibliothèque qui contient des ressources linguistiques (comme les services Google Play), votre application inclut toutes les chaînes traduites pour les messages de ces bibliothèques, et ce, que le reste de votre application soit traduite ou non dans les langues de ces ressources. Pour conserver uniquement les langues officiellement prises en charge par votre application, spécifiez-les à l'aide de la propriété resConfigs. Toutes les ressources pour les langues non spécifiées seront supprimées.

Les extraits suivants montrent comment limiter vos ressources linguistiques à l'anglais et au français:

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

ou

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

Lorsque vous publiez une application au format Android App Bundle (AAB), seules les langues configurées sur l'appareil de l'utilisateur sont téléchargées par défaut lorsque l'utilisateur installe l'application. De même, seules les ressources correspondant à la densité d'écran de l'appareil et les bibliothèques natives correspondant à l'ABI de l'appareil sont incluses dans le téléchargement. Pour en savoir plus, consultez la section Réactiver ou désactiver des types de fichiers APK de configuration.

Pour les anciennes applications publiées avec des APK (créés avant août 2021), vous pouvez personnaliser la densité d'écran ou les ressources ABI à inclure dans votre APK en compilant plusieurs APK ciblant différentes configurations d'appareil.

Éviter les conflits lors de la fusion de ressources

Par défaut, le plug-in Android Gradle (AGP) fusionne les ressources portant un nom identique, telles que les drawables du même nom qui se trouvent dans des dossiers de ressources différents. Ce comportement n'est pas contrôlé par la propriété shrinkResources et ne peut pas être désactivé, car il est nécessaire pour éviter les erreurs lorsque plusieurs ressources portent le nom référencé par votre code.

La fusion de ressources ne se produit que lorsque plusieurs fichiers partagent les mêmes nom de ressource, type et qualificatif. AGP sélectionne le fichier qu'il identifie comme le meilleur candidat parmi les doublons (en fonction d'un ordre de priorité décrit ci-dessous) et transmet uniquement cette ressource à AAPT en vue d'une distribution dans l'artefact de compilation final.

AGP recherche les ressources en double aux emplacements suivants:

  • Ressources principales, associées à l'ensemble de sources principal, généralement situées dans src/main/res/
  • Superpositions de variantes, à partir du type et des versions de compilation
  • Dépendances du projet de bibliothèque

AGP fusionne les ressources en double dans l'ordre de priorité en cascade suivant:

Dépendances → Principales → Version de compilation → Type de compilation

Par exemple, si une ressource en double apparaît à la fois dans vos ressources principales et dans une version de compilation, Gradle sélectionne la ressource dans la version de compilation.

Si des ressources identiques apparaissent dans le même ensemble de sources, Gradle ne peut pas les fusionner et génère une erreur de fusion des ressources. Cela peut se produire si vous définissez plusieurs ensembles de sources dans la propriété sourceSet de votre fichier build.gradle de module, par exemple si src/main/res/ et src/main/res2/ contiennent des ressources identiques.

Résoudre les problèmes de réduction de ressources

Lorsque vous réduisez des ressources, la fenêtre Compiler affiche un récapitulatif des ressources supprimées de l'application. Cliquez sur Changer d'affichage sur le côté gauche de la fenêtre pour afficher la sortie texte détaillée à partir de Gradle. Exemple :

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

Gradle crée également un fichier de diagnostic nommé resources.txt dans <module-name>/build/outputs/mapping/release/ (il s'agit du même dossier que celui des fichiers de sortie de ProGuard). Les informations contenues dans ce fichier permettent de savoir quelles ressources en référencent d'autres, et lesquelles sont utilisées ou supprimées.

Par exemple, pour savoir pourquoi @drawable/ic_plus_anim_016 se trouve toujours dans votre application, ouvrez le fichier resources.txt et recherchez ce nom de fichier. Vous apprendrez peut-être qu'il est référencé à partir d'une autre ressource:

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

Vous devez maintenant comprendre pourquoi @drawable/add_schedule_fab_icon_anim est accessible. Si vous effectuez une recherche vers le haut, vous verrez que cette ressource est répertoriée sous l'en-tête The root reachable resources are: (Les ressources accessibles à la racine sont les suivantes :) dans resources.txt.

Cela signifie qu'il existe une référence à add_schedule_fab_icon_anim, c'est-à-dire que son ID R.drawable a été trouvé dans le code accessible.

Sauf si vous utilisez une vérification stricte, les ID de ressource peuvent être marqués comme accessibles s'il existe des constantes de chaîne susceptibles d'être utilisées pour créer des noms pour des ressources chargées dynamiquement. Dans ce cas, si vous recherchez le nom de la ressource dans le résultat de la compilation, un message semblable à celui-ci peut s'afficher:

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 vous voyez l'une de ces chaînes et que vous êtes sûr qu'elle n'est pas utilisée pour charger dynamiquement la ressource donnée, utilisez l'attribut tools:discard dans votre fichier keep pour demander au système de compilation de supprimer la ressource.