Optimierungen schrittweise einführen

Standardmäßig führt R8 viele Optimierungen durch, um Leistung und Größe zu verbessern. Die Optimierungen funktionieren jedoch möglicherweise nicht sofort für Ihre App. Wenn Sie R8 (oder den Vollmodus) in einer großen App zum ersten Mal aktivieren, sollten Sie die Optimierungen schrittweise einführen: Deaktivieren Sie vorübergehend die Verschleierung und aktivieren Sie R8 für Teile des Codes, nicht für den gesamten Code in Ihrer App. Wir empfehlen diesen schrittweisen Ansatz bei der lokalen Entwicklung, Sie können ihn aber auch bei internen QA-Tests oder sogar in der Produktion als schrittweises Roll-out verwenden. Die genauen Schritte, die Sie ausführen, hängen von Ihrem gewünschten Zeitplan und Ihrem Vertrauen in die Abdeckung Ihrer Pre-Release-Tests 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:

  • Codekomprimierung (oder Tree Shaking): Entfernt Code, auf den nicht verwiesen wird
  • Verschleierung (oder Minimierung von IDs): Kürzung der Namen von Klassen und Methoden
  • Optimierung: Code wird umgeschrieben, z. B. durch Inline-Einfügen

Um die Wahrscheinlichkeit von Fehlern zu verringern, können Sie zuerst nur einige dieser Optimierungen aktivieren.

Nur Baumschütteln aktivieren

Bei der Codekomprimierung, auch Tree Shaking genannt, wird Code entfernt, auf den anscheinend keine Verweise vorhanden sind. Wir empfehlen, mit dem Tree Shaking zu beginnen, da dies am einfachsten ist.

Wenn Sie nur das Entfernen von Untergeordneten aktivieren möchten, fügen Sie der Datei proguard-rules.pro Folgendes hinzu, um die anderen Optimierungstypen zu deaktivieren: Die Verschleierung muss deaktiviert werden, da Stack-Traces dadurch viel leichter zu lesen sind.

-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization

Diese Konfiguration sollte nicht für die Produktion verwendet werden, da sie die Möglichkeiten von R8 zur Codeoptimierung drastisch einschränkt. Sie ist jedoch ein guter Ausgangspunkt, wenn Sie R8 zum ersten Mal in einer großen Codebasis mit Problemen zur Fehlerbehebung verwenden.

Kompatibilitätsmodus verwenden

Standardmäßig wird R8 im Vollmodus ausgeführt. Der Vollmodus bietet eine deutlich bessere Leistung und eine geringere Größe. Sie können ihn jedoch vorübergehend deaktivieren und stattdessen den Kompatibilitätsmodus verwenden, wenn Sie die Minimierung zum ersten Mal aktivieren.

Wenn Sie den Kompatibilitätsmodus verwenden möchten, verwenden Sie in der Datei gradle.properties die folgende Einstellung:

android.enableR8.fullMode = false // Use temporarily to disable full mode

Restliche Optimierungen aktivieren

Wenn Sie bestätigt haben, dass das Tree Shaking für Ihre App funktioniert, können Sie die vorherigen Einstellungen entfernen, um Obfuscation, Optimierung und den R8-Vollmodus wieder zu aktivieren. Beachten Sie, dass Obfuscierung die Fehlerbehebung erschweren kann. Daher empfehlen wir, zuerst Probleme mit dem Tree Shaking anzugehen.

Weitere Informationen zum Entfernen von Verschleierungen aus Stacktraces finden Sie unter „Ursprünglichen Stacktrace wiederherstellen“.

Umfang der Optimierung begrenzen

Bei einem vollständig optimierten Build wird der gesamte Code in allen Bibliotheken und Paketen optimiert. Daher treten beim ersten Aktivieren von R8 häufig Probleme auf. Wenn Sie in einem Teil der App ein Problem mit der Optimierung feststellen, sollten Sie R8 nicht vollständig deaktivieren, da Sie sonst überall sonst die Vorteile verpassen. Deaktivieren Sie R8 stattdessen nur vorübergehend in den Teilen Ihrer App, die Probleme verursachen.

Paketweite Aufbewahrungsregeln verwenden

Wir empfehlen, paketweite Beibehaltungsregeln zu verwenden, um R8 vorübergehend in Teilen Ihrer App zu deaktivieren. Sie sollten diese Optimierungsprobleme später immer beheben. Dies ist in der Regel eine Notlösung, um Problembereiche zu umgehen.

Wenn beispielsweise ein Teil Ihrer App Gson intensiv verwendet und Probleme bei der Optimierung verursacht, ist es am besten, weitere zielgerichtete Regeln für das Behalten hinzuzufügen oder zu einer codegen-Lösung zu wechseln. Wenn Sie jedoch die Optimierung des Rests der App nicht blockieren möchten, können Sie den Code, der Ihre Gson-Typen definiert, in ein eigenes Unterpaket einfügen und Ihrer proguard-rules.pro-Datei eine Regel wie diese hinzufügen:

-keep class com.myapp.json.** { *; }

Wenn eine von Ihnen verwendete Bibliothek Reflexionen in interne Komponenten hat, können Sie auch hier eine Beibehaltungsregel für die gesamte Bibliothek hinzufügen. Sie müssen den Code oder JAR/AAR der Bibliothek prüfen, um das entsprechende Paket zu finden, das Sie behalten möchten. Auch diese Lösung wird nicht langfristig empfohlen, kann aber die Optimierung der restlichen App ermöglichen:

-keep class com.somelibrary.** { *; }

Paketweite Beibehaltungsregeln entfernen

Sobald Ihre App mit paketweiten Regeln für die Beibehaltung ordnungsgemäß funktioniert, sollten Sie entweder zielgerichtete Regeln für die Beibehaltung hinzufügen oder die Reflexionsnutzung oder ‑bibliothek entfernen, die die Regel für die Beibehaltung überhaupt erforderlich macht.

In AndroidX ist es beispielsweise sehr üblich, alle Regeln beizubehalten, die eine bestimmte Klasse erweitern, um nur relevante Klassen zu behalten. Im Allgemeinen sollte die Reflection nur auf Klassen oder Methoden ausgerichtet sein, die entweder bestimmte abstrakte Klassen erweitern, bestimmte Schnittstellen implementieren oder Klassen mit einer bestimmten Laufzeitanmerkung sind. Jede dieser Methoden wird unterstützt, um Speicheraufbewahrungsregeln zu definieren, sodass Sie in Ihrer endgültigen, vollständig optimierten App keine paketweiten Speicheraufbewahrungsregeln benötigen.