Par défaut, R8 effectue de nombreuses optimisations pour améliorer les performances et la taille, mais elles peuvent ne pas fonctionner immédiatement pour votre application. Si vous activez R8 (ou le mode complet) pour la première fois dans une application volumineuse, essayez d'adopter les optimisations de manière progressive : désactivez temporairement l'obscurcissement et activez R8 pour des parties de code à la fois, plutôt que pour l'ensemble du code de votre application. Nous vous recommandons d'adopter cette approche progressive lors du développement local, mais vous pouvez également l'utiliser lors des tests d'assurance qualité internes ou même en production pour un déploiement progressif. Les étapes exactes à suivre dépendent de la chronologie souhaitée et de votre confiance dans la couverture des tests de version préliminaire.
Limiter les optimisations
R8 effectue de nombreux types d'optimisations, y compris la suppression de code, la réécriture de code et la suppression de ressources. Voici quelques descriptions générales des types d'optimisation :
- Minification de code (ou tree shaking) : supprime le code non référencé
- Obscurcissement (ou minification d'identifiants) : raccourcit les noms des classes et des méthodes
- Optimisation : réécrit le code, par exemple l'intégration
Pour réduire le risque d'erreurs, vous pouvez commencer par n'activer que certaines de ces optimisations.
Activer uniquement le tree shaking
La minification de code, également appelée tree shaking, supprime le code qui semble non référencé. Nous vous recommandons de commencer par le tree shaking, car il s'agit de la méthode la plus simple.
Pour activer uniquement le tree shaking, ajoutez le code suivant à votre fichier proguard-rules.pro afin de désactiver les autres types d'optimisations. Il est essentiel de désactiver l'obscurcissement, car cela facilite grandement la lecture des traces de la pile.
-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization
En fin de compte, vous ne voudrez pas expédier cette configuration, car elle limite considérablement la capacité de R8 à optimiser le code. Toutefois, il s'agit d'un excellent point de départ lorsque vous adoptez R8 pour la première fois dans une base de code volumineuse avec des problèmes à résoudre.
Utiliser le mode compatibilité
Par défaut, R8 s'exécute en mode complet. Le mode complet améliore considérablement les performances et réduit la taille, mais vous pouvez le désactiver temporairement et utiliser le mode compatibilité à la place lorsque vous activez la minification pour la première fois.
Pour utiliser le mode compatibilité, utilisez le paramètre suivant dans votre fichier gradle.properties :
android.enableR8.fullMode = false // Use temporarily to disable full mode
Activer le reste des optimisations
Une fois que vous avez confirmé que le tree shaking fonctionne pour votre application, vous pouvez supprimer les paramètres précédents pour réactiver l'obscurcissement, l'optimisation et le mode complet de R8. Notez que l'obscurcissement peut rendre le débogage plus difficile. C'est pourquoi nous vous recommandons de résoudre d'abord les problèmes de tree shaking.
Pour en savoir plus sur la désobscurcissement des traces de la pile, consultez Récupérer la trace de la pile d'origine.
Limiter le champ d'application de l'optimisation
Une compilation entièrement optimisée optimise tout le code de chaque bibliothèque et package. Il est donc courant de rencontrer des problèmes avec R8 lorsque vous l'activez pour la première fois. Si vous rencontrez un problème d'optimisation dans une partie de l'application, ne désactivez pas complètement R8, sinon vous perdrez les avantages partout ailleurs. Au lieu de cela, désactivez temporairement R8 uniquement dans les parties de votre application qui posent problème.
Utiliser des règles de conservation à l'échelle du package
Nous vous recommandons d'utiliser des règles de conservation à l'échelle du package pour désactiver temporairement R8 dans certaines parties de votre application. Vous devez toujours revenir pour résoudre ces problèmes d'optimisation ultérieurement. Il s'agit généralement d'une solution provisoire pour contourner les zones problématiques.
Par exemple, si une partie de votre application utilise beaucoup Gson et pose des problèmes d'
optimisation, la solution idéale consiste à ajouter des règles de conservation plus
ciblées ou à passer à une solution de génération de code. Toutefois, pour débloquer l'optimisation du reste de l'application, vous pouvez placer le code définissant vos types Gson dans un sous-package dédié et ajouter une règle comme celle-ci à votre fichier proguard-rules.pro :
-keep class com.myapp.json.** { *; }
Si une bibliothèque que vous utilisez comporte une réflexion sur les composants internes, vous pouvez également ajouter une règle de conservation pour l'ensemble de la bibliothèque. Vous devrez inspecter le code ou le fichier JAR/AAR de la bibliothèque pour trouver le package approprié à conserver. Encore une fois, il n'est pas recommandé de conserver cette configuration à long terme, mais elle peut débloquer l'optimisation du reste de l'application :
-keep class com.somelibrary.** { *; }
Supprimer les règles de conservation à l'échelle du package
Une fois que votre application fonctionne correctement avec des règles de conservation à l'échelle du package, vous devez revenir en arrière et ajouter des règles de conservation ciblées, ou supprimer l'utilisation de la réflexion ou la bibliothèque qui nécessite la règle de conservation en premier lieu.
Par exemple, la conservation de toutes les règles qui étendent une certaine classe est extrêmement courante dans AndroidX pour ne conserver que les classes pertinentes. En règle générale, la réflexion ne doit cibler que les classes ou les méthodes qui étendent certaines classes abstraites, implémentent certaines interfaces ou dans des classes avec une annotation d'exécution spécifique. Chacune de ces méthodes est compatible pour définir des règles de conservation afin que vous n'ayez pas besoin de règles de conservation à l'échelle du package dans votre application finale entièrement optimisée.
Si la réflexion est présente dans votre propre base de code, vous pouvez remplacer les règles de conservation à l'échelle du package par Jetpack Keep. Les règles générées sont conditionnelles : R8 conserve la cible d'un appel réflexif uniquement s'il conserve également le code qui effectue l'appel. Pour migrer un package, utilisez les vérifications lint de Jetpack Keep pour trouver et annoter ses appels réflexifs, puis supprimez la règle à l'échelle du package.