Als Bibliotheksautor sollten Sie dafür sorgen, dass App-Entwickler Ihre Bibliothek ganz einfach in ihre App einbinden können und dabei die Qualität der Nutzererfahrung erhalten bleibt. Sie sollten dafür sorgen, dass Ihre Bibliothek ohne zusätzliche Einrichtung mit der Android-Optimierung kompatibel ist, oder dokumentieren, dass die Bibliothek möglicherweise nicht für die Verwendung auf Android-Geräten geeignet ist.
Diese Dokumentation richtet sich an Entwickler veröffentlichter Bibliotheken, kann aber auch für Entwickler interner Bibliotheksmodule in einer großen, modularen App nützlich sein.
Wenn Sie App-Entwickler sind und mehr über die Optimierung Ihrer Android-App erfahren möchten, lesen Sie den Hilfeartikel App-Optimierung aktivieren. Informationen dazu, welche Bibliotheken geeignet sind, finden Sie unter Bibliotheken mit Bedacht auswählen.
codegen anstelle von reflection verwenden
Verwenden Sie nach Möglichkeit die Codegenerierung (codegen) anstelle der Reflection. Codegen und Reflection sind gängige Ansätze, um bei der Programmierung Boilerplate-Code zu vermeiden. Codegen ist jedoch mit einem App-Optimierer wie R8 besser kompatibel:
- Mit codegen wird Code während des Build-Prozesses analysiert und geändert. Da nach der Kompilierungszeit keine größeren Änderungen mehr vorgenommen werden, weiß der Optimierer, welcher Code letztendlich benötigt wird und was sicher entfernt werden kann.
- Bei der Reflection wird Code zur Laufzeit analysiert und manipuliert. Da der Code erst bei der Ausführung endgültig festgelegt wird, weiß der Optimierer nicht, welcher Code sicher entfernt werden kann. Es wird wahrscheinlich Code entfernt, der während der Laufzeit dynamisch durch Reflection verwendet wird und zu App-Abstürzen führt.
Viele moderne Bibliotheken verwenden Codegen statt Reflection. KSP ist ein gängiger Einstiegspunkt, der unter anderem von Room und Dagger2 verwendet wird.
Wann ist Nachdenken in Ordnung?
Wenn Sie Reflexionen verwenden müssen, sollten Sie nur eine der folgenden Optionen verwenden:
- Bestimmte ausgerichtete Typen (bestimmte Schnittstellenimplementierer oder Unterklassen)
- Code mit einer bestimmten Laufzeitanmerkung
Durch die Verwendung der Reflection auf diese Weise werden die Laufzeitkosten begrenzt und es ist möglich, zielgerichtete Regeln für die Aufbewahrung von Daten zu schreiben.
Diese spezifische und gezielte Form der Reflexion ist ein Muster, das sowohl im Android-Framework (z. B. beim Aufblähen von Aktivitäten, Ansichten und Drawables) als auch in AndroidX-Bibliotheken (z. B. beim Erstellen von WorkManager-ListenableWorkers oder RoomDatabases) zu sehen ist. Im Gegensatz dazu ist die offene Reflexion von Gson nicht für die Verwendung in Android-Apps geeignet.
Regeln für die Aufbewahrung von Inhalten für den Nutzer schreiben
Bibliotheken sollten „Verbraucher“-Aufbewahrungsregeln enthalten, die dasselbe Format wie App-Aufbewahrungsregeln verwenden. Diese Regeln werden in Bibliotheksartefakten (AARs oder JARs) gebündelt und bei der Optimierung von Android-Apps automatisch verwendet, wenn die Bibliothek verwendet wird.
AAR-Bibliotheken
Wenn Sie Verbraucherregeln für eine AAR-Bibliothek hinzufügen möchten, verwenden Sie die Option consumerProguardFiles
im Build-Script des Android-Bibliotheksmoduls. Weitere Informationen finden Sie in unserer Anleitung zum Erstellen von Bibliotheksmodulen.
Kotlin
android { defaultConfig { consumerProguardFiles("consumer-proguard-rules.pro") } ... }
Groovy
android { defaultConfig { consumerProguardFiles 'consumer-proguard-rules.pro' } ... }
JAR-Bibliotheken
Wenn Sie Regeln mit Ihrer Kotlin-/Java-Bibliothek bündeln möchten, die als JAR-Datei bereitgestellt wird, legen Sie die Regelndatei mit einem beliebigen Dateinamen im Verzeichnis META-INF/proguard/
der endgültigen JAR-Datei ab.
Wenn sich Ihr Code beispielsweise in <libraryroot>/src/main/kotlin
befindet, legen Sie eine Datei mit Verbraucherregeln unter <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro
ab. Die Regeln werden dann am richtigen Speicherort in der Ausgabe-JAR-Datei verpackt.
Prüfen Sie, ob das finale JAR-Archiv die Regeln korrekt bündelt. Dazu müssen sich die Regeln im Verzeichnis META-INF/proguard
befinden.
AAR-Bibliothek-Build optimieren (erweitert)
Im Allgemeinen sollten Sie einen Bibliotheksbau nicht direkt optimieren, da die möglichen Optimierungen beim Erstellen der Bibliothek sehr begrenzt sind. Erst während des App-Builds, wenn eine Bibliothek als Teil einer App eingebunden ist, kann R8 erkennen, wie alle Methoden der Bibliothek verwendet werden und welche Parameter übergeben werden. Als Bibliotheksentwickler müssen Sie mehrere Optimierungsphasen berücksichtigen und das Verhalten sowohl beim Erstellen der Bibliothek als auch der App im Auge behalten, bevor Sie die Bibliothek optimieren.
Wenn Sie Ihre Bibliothek trotzdem zum Zeitpunkt des Builds optimieren möchten, wird dies vom Android Gradle-Plug-in unterstützt.
Kotlin
android { buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } configureEach { consumerProguardFiles("consumer-rules.pro") } } }
Groovy
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } configureEach { consumerProguardFiles "consumer-rules.pro" } } }
Das Verhalten von proguardFiles
unterscheidet sich stark von dem von consumerProguardFiles
:
proguardFiles
werden zum Zeitpunkt des Builds verwendet, oft zusammen mitgetDefaultProguardFile("proguard-android-optimize.txt")
, um festzulegen, welcher Teil der Bibliothek beim Erstellen der Bibliothek beibehalten werden soll. Das ist mindestens Ihre öffentliche API.consumerProguardFiles
werden dagegen in der Bibliothek verpackt, um spätere Optimierungen beim Erstellen einer App zu beeinflussen, die Ihre Bibliothek nutzt.
Wenn Ihre Bibliothek beispielsweise Reflection zum Erstellen interner Klassen verwendet, müssen Sie die Regeln zum Beibehalten möglicherweise sowohl in proguardFiles
als auch in consumerProguardFiles
definieren.
Wenn Sie -repackageclasses
im Build Ihrer Bibliothek verwenden, verpacken Sie die Klassen in ein Unterpaket innerhalb des Pakets Ihrer Bibliothek neu. Verwenden Sie z. B. -repackageclasses 'com.example.mylibrary.internal'
statt -repackageclasses 'internal'
.
Unterstützung verschiedener R8-Versionen (erweitert)
Sie können Regeln auf bestimmte Versionen von R8 ausrichten. So kann Ihre Bibliothek optimal in Projekten mit neueren R8-Versionen verwendet werden, während vorhandene Regeln weiterhin in Projekten mit älteren R8-Versionen verwendet werden können.
Wenn Sie gezielte R8-Regeln angeben möchten, müssen Sie sie im Verzeichnis META-INF/com.android.tools
in classes.jar
einer AAR oder im Verzeichnis META-INF/com.android.tools
einer JAR-Datei einfügen.
In an AAR library:
proguard.txt (legacy location, the file name must be "proguard.txt")
classes.jar
└── META-INF
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
In a JAR library:
META-INF
├── proguard/<ProGuard-rule-files> (legacy location)
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
Im Verzeichnis META-INF/com.android.tools
können mehrere Unterverzeichnisse mit Namen im Format r8-from-<X>-upto-<Y>
vorhanden sein, um anzugeben, für welche R8-Versionen die Regeln geschrieben sind. Jedes Unterverzeichnis kann eine oder mehrere Dateien mit den R8-Regeln enthalten, die beliebige Dateinamen und ‑erweiterungen haben können.
Die Teile -from-<X>
und -upto-<Y>
sind optional. Die Version <Y>
ist exklusiv. Die Versionsbereiche sind in der Regel fortlaufend, können sich aber auch überschneiden.
Beispielsweise sind r8
, r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
und r8-from-8.2.0
Verzeichnisnamen, die eine Reihe von R8-Regeln mit Ausrichtung darstellen.
Die Regeln im Verzeichnis r8
können von allen R8-Versionen verwendet werden. Die Regeln im Verzeichnis r8-from-8.0.0-upto-8.2.0
können von R8 ab Version 8.0.0 bis einschließlich Version 8.2.0 (nicht einschließlich) verwendet werden.
Das Android Gradle-Plug-in verwendet diese Informationen, um alle Regeln auszuwählen, die von der aktuellen R8-Version verwendet werden können. Wenn für eine Bibliothek keine R8-Regeln für bestimmte Ziele angegeben sind, wählt das Android Gradle-Plug-in die Regeln aus den bisherigen Speicherorten aus (proguard.txt
für eine AAR oder META-INF/proguard/<ProGuard-rule-files>
für eine JAR).