Actualités des produits
Configurer et résoudre les problèmes liés aux règles Keep R8
Temps de lecture : 7 min
Dans le développement Android moderne, la livraison d'une application petite, rapide et sécurisée est une attente fondamentale des utilisateurs. L'outil principal du système de compilation Android pour y parvenir est l'optimiseur R8 , le compilateur qui gère la suppression du code mort et des ressources pour la minification, le renommage du code ou la minification, et l'optimisation de l'application.
L'activation de R8 est une étape essentielle pour préparer une application à la publication, mais elle nécessite que les développeurs fournissent des instructions sous la forme de "règles de conservation".
Après avoir lu cet article, regardez la vidéo Performance Spotlight Week sur l'activation, le débogage et la résolution des problèmes de l'optimiseur R8 sur YouTube.
Pourquoi les règles de conservation sont-elles nécessaires ?
La nécessité d'écrire des règles Keep découle d'un conflit fondamental : R8 est un outil d'analyse statique, mais les applications Android s'appuient souvent sur des modèles d'exécution dynamique tels que la réflexion ou les appels dans et hors du code natif à l'aide de la JNI (Java Native Interface).
R8 crée un graphique du code utilisé en analysant les appels directs. Lorsque le code est accédé de manière dynamique, l'analyse statique de R8 ne peut pas le prédire. Il identifie ce code comme inutilisé et le supprime, ce qui entraîne des plantages au moment de l'exécution.
Une règle keep est une instruction explicite adressée au compilateur R8, qui indique : "Cette classe, cette méthode ou ce champ spécifiques sont un point d'entrée auquel on accède de manière dynamique au moment de l'exécution. Vous devez le conserver, même si vous ne trouvez pas de référence directe à celui-ci."
Pour en savoir plus sur les règles de conservation, consultez le guide officiel.
Où écrire les règles de conservation ?
Les règles Keep personnalisées pour une application sont écrites dans un fichier texte. Par convention, ce fichier est nommé proguard-rules.pro et se trouve à la racine du module d'application ou de bibliothèque. Ce fichier est ensuite spécifié dans le type de compilation release du fichier build.gradle.kts de votre module.
release {
isShrinkResources = true
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
Utiliser le bon fichier par défaut
La méthode getDefaultProguardFile importe un ensemble de règles par défaut fournies par le SDK Android. Si vous utilisez le mauvais fichier, il est possible que votre application ne soit pas optimisée. Veillez à utiliser proguard-android-optimize.txt. Ce fichier fournit les règles de conservation par défaut pour les composants Android standards et active les optimisations de code de R8. L'ancien proguard-android.txt ne fournit que les règles de conservation, mais n'active pas les optimisations de R8.
Comme il s'agit d'un problème de performances grave, nous commençons à avertir les développeurs qu'ils utilisent le mauvais fichier, à partir de la version Android Studio Narwhal 3 Feature Drop. À partir de la version 9.0 du plug-in Android Gradle, nous ne prenons plus en charge le fichier proguard-android.txt obsolète. Veillez donc à passer à la version optimisée.
Rédiger des règles Keep
Une règle de conservation se compose de trois parties principales :
-
Une option , comme
-keepou-keepclassmembers -
Modificateurs facultatifs, comme
allowshrinking - Spécification de classe qui définit le code à mettre en correspondance
Pour obtenir la syntaxe complète et des exemples, consultez les instructions pour ajouter des règles Keep.
Antimodèles des règles Keep
Il est important de connaître les bonnes pratiques, mais aussi les antipatrons. Ces anti-modèles découlent souvent de malentendus ou de raccourcis de dépannage, et peuvent avoir des conséquences désastreuses sur les performances d'une version de production.
Options globales
Ces indicateurs sont des options globales qui ne doivent jamais être utilisées dans un build de version. Elles ne sont destinées qu'au débogage temporaire pour isoler un problème.
L'utilisation de -dontotptimize désactive efficacement les optimisations de performances de R8, ce qui ralentit l'application.
Lorsque vous utilisez -dontobfuscate, vous désactivez toutes les opérations de changement de nom. Lorsque vous utilisez -dontshrink, vous désactivez la suppression du code mort. Ces deux règles globales augmentent la taille de l'application.
Dans la mesure du possible, évitez d'utiliser ces indicateurs globaux dans un environnement de production pour offrir une expérience utilisateur plus performante dans votre application.
Règles de conservation trop générales
Le moyen le plus simple d'annuler les avantages de R8 est d'écrire des règles de conservation trop générales. Les règles de conservation comme celle ci-dessous indiquent à l'optimiseur R8 de ne pas réduire, obscurcir ni optimiser aucune classe de ce package ni aucun de ses sous-packages. Cela supprime complètement les avantages de R8 pour l'ensemble du package. Essayez plutôt de rédiger des règles Keep précises et spécifiques.
-keep class com.example.package.** { *;} // WIDE KEEP RULES CAUSE PROBLEMS
L'opérateur d'inversion (!)
L'opérateur d'inversion (!) semble être un moyen efficace d'exclure un package d'une règle. Mais ce n'est pas si simple. Prenons un exemple :
-keep class !com.example.my_package.** { *; } // USE WITH CAUTION
Vous pourriez penser que cette règle signifie "ne pas conserver les classes danscom.example.package". Mais en réalité, elle signifie "conserver chaque classe, méthode et propriété de l'ensemble de l'application qui ne se trouve pas danscom.example.package". Si cela vous surprend, vérifiez s'il y a des négations dans votre configuration R8.
Règles redondantes pour les composants Android
Une autre erreur courante consiste à ajouter manuellement des règles Keep pour les Activities, Services ou BroadcastReceivers de votre application. Cette étape est inutile. Le fichier proguard-android-optimize.txt par défaut inclut déjà les règles pertinentes pour que ces composants Android standards fonctionnent immédiatement.
De plus, de nombreuses bibliothèques apportent leurs propres règles Keep. Vous ne devriez donc pas avoir à écrire vos propres règles pour ceux-ci. En cas de problème avec les règles de conservation d'une bibliothèque que vous utilisez, il est préférable de contacter l'auteur de la bibliothèque pour connaître la nature du problème.
Bonnes pratiques concernant les règles Keep
Maintenant que vous savez ce qu'il ne faut pas faire, parlons des bonnes pratiques.
Rédiger des règles Keep précises
Les règles de conservation efficaces doivent être aussi précises et spécifiques que possible. Ils ne doivent conserver que ce qui est nécessaire, ce qui permet à R8 d'optimiser tout le reste.
| Règle | Qualité |
|---|---|
| Faible : conserve un package entier et ses sous-packages |
| Faible : conserve une classe entière, qui est probablement encore trop large. |
| Élevé : seules les méthodes et propriétés pertinentes d'une classe spécifique sont conservées. |
Utiliser des ancêtres communs
Au lieu d'écrire des règles Keep distinctes pour plusieurs modèles de données différents, écrivez une règle qui cible une classe de base ou une interface communes. La règle ci-dessous indique à R8 de conserver tous les membres des classes qui implémentent cette interface. Elle est très évolutive.
# Keep all fields of any class that implements SerializableModel
-keepclassmembers class * implements com.example.models.SerializableModel {
<fields>;
}
Utiliser des annotations pour cibler plusieurs classes
Créez une annotation personnalisée (par exemple, @Serialize) et utilisez-la pour "taguer" les classes dont les champs doivent être conservés. Il s'agit d'un autre modèle propre, déclaratif et très évolutif. Vous pouvez également créer des règles Keep pour les annotations existantes provenant des frameworks que vous utilisez.
# Keep all fields of any class annotated with @Serialize
-keepclassmembers class * {
@com.example.annotations.Serialize <fields>;
}
Choisir la bonne option Keep
L'option "Conserver" est la partie la plus importante de la règle. Si vous choisissez le mauvais, vous risquez de désactiver l'optimisation inutilement.
| Option "Conserver" | Fonctionnement |
-keep | Empêche la suppression ou le renommage de la classe et des membres mentionnés dans la déclaration . |
-keepclassmembers | Empêche la suppression ou le renommage des membres spécifiés, mais autorise la suppression de la classe elle-même, à condition qu'elle ne soit pas déjà supprimée. |
-keepclasseswithmembers | Une combinaison : conserve la classe et ses membres, uniquement si tous les membres spécifiés sont présents. |
Pour en savoir plus sur l'option "Conserver", consultez notre documentation sur les options de conservation.
Autoriser l'optimisation avec les modificateurs
Les modificateurs tels que allowshrinking et allowobfuscation assouplissent une règle -keep générale, ce qui redonne à R8 le pouvoir d'optimisation. Par exemple, si une ancienne bibliothèque vous oblige à utiliser -keep sur une classe entière, vous pourrez peut-être récupérer une partie de l'optimisation en autorisant la réduction et l'obscurcissement :
# Keep this class, but allow R8 to remove it if it's unused and allow R8 to rename it. -keep,allowshrinking,allowobfuscation class com.example.LegacyClass
Ajouter des options globales pour une optimisation supplémentaire
En plus des règles Keep, vous pouvez ajouter des indicateurs globaux à votre fichier de configuration R8 pour encourager une optimisation encore plus poussée.
-repackageclasses est une option puissante qui indique à R8 de déplacer toutes les classes obscurcies dans un seul package. Cela permet de gagner beaucoup d'espace dans le fichier DEX en supprimant les chaînes de noms de packages redondantes.
-allowaccessmodification permet à R8 d'élargir l'accès (par exemple, de private à public) pour permettre un inlining plus agressif. Cette fonctionnalité est désormais activée par défaut lorsque vous utilisez proguard-android-optimize.txt.
Avertissement : Les auteurs de bibliothèques ne doivent jamais ajouter ces indicateurs d'optimisation globale à leurs règles de consommateur, car ils seraient appliqués de force à l'ensemble de l'application.
Pour être encore plus clair, dans la version 9.0 du plug-in Android Gradle, nous allons commencer à ignorer complètement les indicateurs d'optimisation globale des bibliothèques.
Bonnes pratiques pour les bibliothèques
Toutes les applications Android reposent sur des bibliothèques, d'une manière ou d'une autre. Parlons donc des bonnes pratiques pour les bibliothèques.
Pour les développeurs de bibliothèques
Si votre bibliothèque utilise la réflexion ou JNI, il vous incombe de fournir les règles de conservation nécessaires à ses consommateurs. Ces règles sont placées dans un fichier consumer-rules.pro, qui est ensuite automatiquement regroupé dans le fichier AAR de la bibliothèque.
android {
defaultConfig {
consumerProguardFiles("consumer-rules.pro")
}
...
}
Pour les consommateurs de la bibliothèque
Filtrer les règles Keep problématiques
Si vous devez utiliser une bibliothèque qui inclut des règles de conservation problématiques, vous pouvez les filtrer dans votre fichier build.gradle.kts à partir d'AGP 9.0. Cela indique à R8 d'ignorer les règles provenant d'une dépendance spécifique.
release {
optimization.keepRules {
// Ignore all consumer rules from this specific library
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
La meilleure règle de conservation est l'absence de règle de conservation
La stratégie de configuration R8 ultime consiste à supprimer complètement la nécessité d'écrire des règles Keep. Pour de nombreuses applications, cela peut être réalisé en choisissant des bibliothèques modernes qui privilégient la génération de code plutôt que la réflexion. Grâce à la génération de code, l'optimiseur peut plus facilement déterminer quel code est réellement utilisé au moment de l'exécution et quel code peut être supprimé. De plus, l'absence de réflexion dynamique signifie qu'il n'y a pas de points d'entrée "cachés". Par conséquent, aucune règle Keep n'est nécessaire. Lorsque vous choisissez une nouvelle bibliothèque, privilégiez toujours une solution qui utilise la génération de code plutôt que la réflexion.
Pour savoir comment choisir des bibliothèques, consultez Choisir judicieusement les bibliothèques.
Déboguer et dépanner votre configuration R8
Lorsque R8 supprime du code qu'il aurait dû conserver ou que votre APK est plus volumineux que prévu, utilisez ces outils pour diagnostiquer le problème.
Rechercher les règles Keep en double et globales
Étant donné que R8 fusionne les règles de dizaines de sources, il peut être difficile de connaître l'ensemble de règles "final". L'ajout de cet indicateur à votre fichier proguard-rules.pro génère un rapport complet :
# Outputs the final, merged set of rules to the specified file -printconfiguration build/outputs/logs/configuration.txt
Vous pouvez effectuer une recherche dans ce fichier pour trouver les règles redondantes ou remonter à la bibliothèque spécifique qui inclut une règle problématique (comme -dontoptimize).
Demande à R8 : Pourquoi gardes-tu ça ?
Si une classe que vous pensiez avoir supprimée est toujours présente dans votre application, R8 peut vous en indiquer la raison. Il vous suffit d'ajouter cette règle :
# Asks R8 to explain why it's keeping a specific class class com.example.MyUnusedClass -whyareyoukeeping
Lors de la compilation, R8 affichera la chaîne exacte de références qui l'ont amené à conserver cette classe. Vous pourrez ainsi suivre la référence et ajuster vos règles.
Pour obtenir un guide complet, consultez la section Dépanner R8.
Étapes suivantes
R8 est un outil puissant permettant d'améliorer les performances des applications Android. Son efficacité dépend d'une bonne compréhension de son fonctionnement en tant que moteur d'analyse statique.
En rédigeant des règles spécifiques au niveau des membres, en tirant parti des ancêtres et des annotations, et en choisissant soigneusement les bonnes options de conservation, vous pouvez conserver exactement ce qui est nécessaire. La pratique la plus avancée consiste à éliminer complètement le besoin de règles en choisissant des bibliothèques modernes basées sur la génération de code plutôt que leurs prédécesseurs basés sur la réflexion.
Pendant la semaine consacrée aux performances, n'oubliez pas de regarder la vidéo du jour sur YouTube et de continuer notre défi R8. Utilisez #optimizationEnabled pour toute question sur l'activation ou le dépannage de R8. Nous sommes là pour vous aider.
Il est temps de découvrir les avantages par vous-même.
Nous vous invitons à activer le mode complet R8 pour votre application dès aujourd'hui.
- Pour commencer, suivez nos guides du développeur : Activer l'optimisation des applications.
-
Vérifiez si vous utilisez encore
proguard-android.txtet remplacez-le parproguard-android-optimize.txt. - Ensuite, mesurez l'impact. Ne vous contentez pas de sentir la différence, vérifiez-la. Mesurez vos gains de performances en adaptant le code de notre exemple d'application Macrobenchmark sur GitHub pour mesurer vos temps de démarrage avant et après.
Nous sommes certains que vous constaterez une amélioration significative des performances de votre application.
Profitez-en pour poser vos questions avec le tag #AskAndroid sur les réseaux sociaux. Tout au long de la semaine, nos experts surveillent les questions et y répondent.
Rendez-vous demain pour en savoir plus sur l'optimisation guidée par profil avec les profils de référence et de démarrage, découvrir comment les performances de rendu de Compose se sont améliorées au fil des versions et connaître les considérations de performances pour le travail en arrière-plan.
Lire la suite
-
Actualités des produits
Android Studio Panda 4 est désormais stable et prêt à être utilisé en production. Cette version inclut le mode Planification, la prédiction de la prochaine modification et bien d'autres fonctionnalités qui vous permettent de créer des applications Android de haute qualité plus facilement que jamais.
Matt Dyor • Temps de lecture : 5 min
-
Actualités des produits
Si vous êtes un développeur Android et que vous souhaitez implémenter des fonctionnalités d'IA innovantes dans votre application, nous avons récemment lancé de nouvelles mises à jour puissantes.
Thomas Ezan • Temps de lecture : 3 min
-
Actualités des produits
Android 17 est disponible en version bêta 4, la dernière version bêta prévue pour ce cycle de publication. Il s'agit d'une étape cruciale pour la compatibilité des applications et la stabilité de la plate-forme.
Daniel Galpin • Temps de lecture : 4 min
Restez informé
Recevez chaque semaine les dernières informations sur le développement Android directement dans votre boîte de réception.