Standardmäßig nimmt R8 viele Optimierungen vor, um die Leistung zu verbessern und die Größe zu reduzieren. Diese Optimierungen funktionieren aber möglicherweise nicht sofort für deine App. Wenn du R8 (oder den vollständigen Modus) zum ersten Mal in einer großen App aktivierst, solltest du die Optimierungen schrittweise einführen: Deaktiviere die Verschleierung vorübergehend und aktiviere R8 für jeweils einen Teil des Codes anstatt für den gesamten Code in deiner App. Wir empfehlen, diesen schrittweisen Ansatz während der lokalen Entwicklung zu verwenden. Du kannst ihn aber auch bei internen Qualitätssicherungstests oder sogar in der Produktion als schrittweise Einführung nutzen. Die genauen Schritte hängen von deinem gewünschten Zeitplan und deinem Vertrauen in die Testabdeckung vor der Veröffentlichung ab.
Optimierungen einschränken
R8 führt viele Arten von Optimierungen durch, darunter das Entfernen von Code, das Umschreiben von Code und das Entfernen von Ressourcen. Hier sind einige allgemeine Beschreibungen der Optimierungstypen:
- Code-Shrinking (oder Tree Shaking): Entfernt nicht referenzierten Code
- Verschleierung (oder Identifier-Minifizierung): Kürzt die Namen von Klassen und Methoden
- Optimierung: Schreibt Code um, z. B. durch Inlining
Um die Wahrscheinlichkeit von Fehlern zu verringern, kannst du zuerst nur einige dieser Optimierungen aktivieren.
Nur Tree Shaking aktivieren
Beim Code-Shrinking, auch Tree Shaking genannt, wird Code entfernt, der nicht referenziert zu sein scheint. Wir empfehlen, mit Tree Shaking zu beginnen, da es am einfachsten ist.
Wenn du nur Tree Shaking aktivieren möchtest, füge der Datei proguard-rules.pro Folgendes hinzu, um die anderen Optimierungstypen zu deaktivieren: Es ist wichtig, die Verschleierung zu deaktivieren, da dadurch Stacktraces viel leichter zu lesen sind.
-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization
Letztendlich solltest du diese Konfiguration nicht verwenden, da sie die Möglichkeiten von R8 zur Codeoptimierung drastisch einschränkt. Sie ist aber ein guter Ausgangspunkt, wenn du R8 zum ersten Mal in einer großen Codebasis mit zu behebenden Problemen einführst.
Kompatibilitätsmodus verwenden
Standardmäßig wird R8 im vollständigen Modus ausgeführt. Der vollständige Modus bietet eine deutlich verbesserte Leistung und eine größere Größenreduzierung. Du kannst ihn aber vorübergehend deaktivieren und stattdessen den Kompatibilitätsmodus verwenden, wenn du die Minifizierung zum ersten Mal aktivierst.
Wenn du den Kompatibilitätsmodus verwenden möchtest, verwende die folgende Einstellung in der Datei gradle.properties:
android.enableR8.fullMode = false // Use temporarily to disable full mode
Restliche Optimierungen aktivieren
Wenn du bestätigt hast, dass Tree Shaking für deine App funktioniert, kannst du die vorherigen Einstellungen entfernen, um die Verschleierung, Optimierung und den vollständigen Modus von R8 wieder zu aktivieren. Beachte, dass die Verschleierung das Debugging erschweren kann. Daher empfehlen wir, zuerst Probleme mit Tree Shaking zu beheben.
Weitere Informationen zum Entschleiern von Stacktraces findest du unter Original-Stacktrace wiederherstellen.
Optimierungsumfang einschränken
Bei einem vollständig optimierten Build wird der gesamte Code in allen Bibliotheken und Paketen optimiert. Daher treten häufig Probleme mit R8 auf, wenn du es zum ersten Mal aktivierst. Wenn du ein Problem mit der Optimierung in einem Teil der App feststellst, deaktiviere R8 nicht vollständig, da du sonst die Vorteile in allen anderen Bereichen verlierst. Deaktiviere R8 stattdessen vorübergehend nur in den Teilen der App, die Probleme verursachen.
Paketweite Keep-Regeln verwenden
Wir empfehlen, paketweite Keep-Regeln zu verwenden, um R8 vorübergehend in Teilen deiner App zu deaktivieren. Du solltest diese Optimierungsprobleme später immer beheben. Dies ist in der Regel eine Übergangslösung, um Problembereiche zu umgehen.
Wenn beispielsweise ein Teil deiner App Gson intensiv nutzt und Probleme mit der
Optimierung verursacht, besteht die ideale Lösung darin, gezieltere
Keep-Regeln hinzuzufügen oder zu einer Codegen-Lösung zu wechseln. Um die Optimierung des restlichen Teils der App zu ermöglichen, kannst du den Code, der deine Gson-Typen definiert, in ein eigenes Unterpaket verschieben und der Datei proguard-rules.pro eine Regel wie diese hinzufügen:
-keep class com.myapp.json.** { *; }
Wenn eine von dir verwendete Bibliothek Reflection in interne Komponenten verwendet, kannst du auf ähnliche Weise eine Keep-Regel für die gesamte Bibliothek hinzufügen. Du musst den Code oder die JAR-/AAR-Datei der Bibliothek prüfen, um das entsprechende Paket zu finden, das beibehalten werden soll. Auch dies wird nicht für die langfristige Wartung empfohlen, kann aber die Optimierung des restlichen Teils der App ermöglichen:
-keep class com.somelibrary.** { *; }
Paketweite Keep-Regeln entfernen
Sobald deine App mit paketweiten Keep-Regeln korrekt funktioniert, solltest du zurückkehren und entweder gezielte Keep-Regeln hinzufügen oder die Reflection-Nutzung oder die Bibliothek entfernen, die die Keep-Regel überhaupt erst erforderlich macht.
Beispielsweise ist es in AndroidX sehr üblich, alle Regeln beizubehalten, die eine bestimmte Klasse erweitern, um nur relevante Klassen beizubehalten. Im Allgemeinen sollte Reflection nur auf Klassen oder Methoden abzielen, die bestimmte abstrakte Klassen erweitern, bestimmte Schnittstellen implementieren oder in Klassen mit einer bestimmten Laufzeitannotation. Jede dieser Methoden wird unterstützt, um Keep-Regeln zu definieren, sodass du in deiner endgültigen, vollständig optimierten App keine paketweiten Keep-Regeln benötigst.
Wenn Reflection in deiner eigenen Codebasis vorhanden ist, kannst du paketweite Keep-Regeln durch Jetpack Keepersetzen. Die generierten Regeln sind bedingt: R8 behält das Ziel eines reflektierenden Aufrufs nur bei, wenn es auch den Code beibehält, der den Aufruf ausführt. Wenn du ein Paket migrieren möchtest, verwende die Jetpack Keep-Lint-Prüfungen, um die reflektierenden Aufrufe zu finden und mit Anmerkungen zu versehen, und entferne dann die paketweite Regel.