Damit die App optimiert werden kann, müssen Sie Bibliotheken verwenden, die mit der Android-Optimierung kompatibel sind. Wenn eine Bibliothek nicht für die Android-Optimierung konfiguriert ist, z. B. wenn sie Reflection ohne zugehörige Keep-Regeln verwendet, ist sie möglicherweise nicht gut für eine Android-App geeignet. Auf dieser Seite wird erläutert, warum einige Bibliotheken besser für die App-Optimierung geeignet sind, und es werden allgemeine Tipps zur Auswahl gegeben.
Allgemeine Tipps zur Auswahl von Bibliotheken
Mit diesen Tipps können Sie dafür sorgen, dass Ihre Bibliotheken mit der App-Optimierung kompatibel sind.
Codegenerierung gegenüber Reflexion bevorzugen
Wählen Sie Bibliotheken aus, die Codegenerierung (codegen) anstelle von Reflection verwenden. Durch die Codegenerierung kann der Optimierer leichter ermitteln, welcher Code zur Laufzeit tatsächlich verwendet wird und welcher Code entfernt werden kann. Es kann schwierig sein, festzustellen, ob eine Bibliothek Codegenerierung oder Reflexion verwendet. Es gibt jedoch einige Anzeichen. Tipps können dabei helfen.
Weitere Informationen zu Codegenerierung im Vergleich zu Reflexion finden Sie unter Optimierung für Bibliotheksautoren.
Verwendung von Reflection prüfen (erweitert)
Ob eine Bibliothek Reflection verwendet, können Sie anhand des Codes erkennen. Wenn die Bibliothek Reflection verwendet, prüfen Sie, ob zugehörige Keep-Regeln vorhanden sind. Eine Bibliothek verwendet wahrscheinlich Reflection, wenn sie Folgendes tut:
- Verwendet Klassen oder Methoden aus den Paketen
kotlin.reflectoderjava.lang.reflect. - Verwendet die Funktionen
Class.forNameoderclassLoader.getClass. - Liest Anmerkungen zur Laufzeit, z. B. wenn ein Anmerkungswert mit
val value = myClass.getAnnotation()oderval value = myMethod.getAnnotation()gespeichert und dann mitvalueetwas unternommen wird. Ruft Methoden auf, indem der Methodenname als String angegeben wird, wie im folgenden Beispiel:
// Calls the private `processData` API with reflection myObject.javaClass.getMethod("processData", DataType::class.java) ?.invoke(myObject, data)
Auf Optimierungsprobleme prüfen
Wenn Sie eine neue Bibliothek in Betracht ziehen, sollten Sie im Issue Tracker der Bibliothek und in Online-Diskussionen nachsehen, ob es Probleme im Zusammenhang mit der Minimierung oder der Konfiguration der App-Optimierung gibt. Wenn das der Fall ist, sollten Sie nach Alternativen für diese Bibliothek suchen. Beachten Sie Folgendes:
- Die AndroidX-Bibliotheken und Bibliotheken wie Hilt eignen sich gut für die App-Optimierung, da sie größtenteils Codegenerierung anstelle von Reflection verwenden. Wenn sie Reflection verwenden, stellen sie minimale Keep-Regeln bereit, um nur den benötigten Code beizubehalten.
- Serialisierungsbibliotheken verwenden häufig Reflection, um Boilerplate-Code beim Instanziieren oder Serialisieren von Objekten zu vermeiden. Anstelle von reflexionsbasierten Ansätzen (z. B. Gson für JSON) sollten Sie nach Bibliotheken suchen, die Codegenerierung verwenden, um diese Probleme zu vermeiden, z. B. Kotlin Serialization oder Moshi mit Codegenerierung.
- Vermeiden Sie nach Möglichkeit Bibliotheken, die paketweite Keep-Regeln enthalten. Mit package-weiten Keep-Regeln lassen sich Fehler beheben. Allgemeine Keep-Regeln sollten jedoch letztendlich so angepasst werden, dass nur der benötigte Code beibehalten wird. Weitere Informationen finden Sie unter Optimierungen inkrementell übernehmen.
- Für Bibliotheken sollten keine Keep-Regeln aus der Dokumentation in eine Datei in Ihrem Projekt kopiert und eingefügt werden müssen, insbesondere keine paketweiten Keep-Regeln. Diese Regeln stellen langfristig eine Belastung für den App-Entwickler dar und sind im Laufe der Zeit schwer zu optimieren und zu ändern.
Optimierung nach dem Hinzufügen einer neuen Bibliothek aktivieren
Wenn Sie eine neue Bibliothek hinzufügen, aktivieren Sie die Optimierung anschließend und prüfen Sie, ob Fehler auftreten. Wenn Fehler auftreten, suchen Sie nach Alternativen zu dieser Bibliothek oder schreiben Sie Keep-Regeln. Wenn eine Bibliothek nicht mit der Optimierung kompatibel ist, melden Sie einen Fehler für diese Bibliothek.
Unerwünschte Aufbewahrungsregeln herausfiltern (erweitert)
Aufbewahrungsregeln werden miteinander kombiniert. Das bedeutet, dass bestimmte Regeln, die in einer Bibliotheksabhängigkeit enthalten sind, nicht entfernt werden können und sich auf die Kompilierung anderer Teile Ihrer App auswirken können. Wenn eine Bibliothek beispielsweise eine Regel zum Deaktivieren der Codeoptimierung enthält, wird die Optimierung für Ihr gesamtes Projekt deaktiviert.
Sie sollten Bibliotheken mit Keep-Regeln vermeiden, die Code beibehalten, der eigentlich entfernt werden sollte. Wenn Sie sie jedoch verwenden müssen, können Sie die Regeln herausfiltern, wie im folgenden Code gezeigt:
// If you're using AGP 8.4 and higher
buildTypes {
release {
optimization.keepRules {
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
}
// If you're using AGP 7.3-8.3
buildTypes {
release {
optimization.keepRules {
it.ignoreExternalDependencies("com.somelibrary:somelibrary")
}
}
}
Fallstudie: Warum Gson bei Optimierungen nicht funktioniert
Gson ist eine Serialisierungsbibliothek, die häufig Probleme bei der App-Optimierung verursacht, da sie stark auf Reflection basiert. Das folgende Code-Snippet zeigt, wie Gson normalerweise verwendet wird. Das kann leicht zu Laufzeitabstürzen führen. Wenn Sie mit Gson eine Liste von User-Objekten abrufen, rufen Sie den Konstruktor nicht auf und übergeben auch keine Factory an die Funktion fromJson(). Wenn Sie von der App definierte Klassen ohne eine der folgenden Optionen erstellen oder verwenden, ist das ein Zeichen dafür, dass eine Bibliothek möglicherweise offene Reflektion verwendet:
- App-Klasse, die eine Bibliothek oder Standardschnittstelle oder -klasse implementiert
- Plug-in zur Codegenerierung wie KSP
class User(val name: String)
class UserList(val users: List<User>)
// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()
Informationen zur Funktionsweise von R8 für Gson finden Sie unter Gson-Consumer-Regeln. Wenn R8 diesen Code analysiert und UserList oder User nirgends instanziiert sieht, kann es Felder umbenennen oder Konstruktoren entfernen, die scheinbar nicht verwendet werden, was zum Absturz Ihrer App führt. Wenn Sie andere Bibliotheken auf ähnliche Weise verwenden, sollten Sie prüfen, ob sie die App-Optimierung beeinträchtigen. Falls dies der Fall ist, sollten Sie sie nicht verwenden.
Verwenden Sie das folgende Snippet als Referenz, um die Klassen in einer Weise zu definieren, die mit den Consumer-Regeln von Gson kompatibel ist:
class User(@com.google.gson.annotations.SerializedName("name") val name: String)
class UserList(@com.google.gson.annotations.SerializedName("users") val users: List<User>)
Room, Hilt und Moshi mit Codegenerierung erstellen von der App definierte Typen, verwenden aber die Codegenerierung, um die Notwendigkeit von Reflection zu vermeiden.