Damit Ihre App so klein und schnell wie möglich ist, sollten Sie sie optimieren und reduzieren.
Ihren Release-Build mit isMinifyEnabled = true
erstellen.
Dadurch wird die Verkleinerung aktiviert, wodurch nicht verwendeter Code und nicht verwendete Ressourcen entfernt werden. Verschleierung, mit der die Namen der Klassen und Mitglieder Ihrer App gekürzt werden und Optimierung, mit der aggressivere Strategien angewendet werden, um und die Leistung Ihrer App zu verbessern. Auf dieser Seite wird beschrieben, wie R8 diese Aufgaben zur Kompilierungszeit für Ihr Projekt ausführt .
Wenn Sie Ihr Projekt mit Android-Gradle-Plug-in 3.4.0 oder höher, Das Plug-in verwendet ProGuard nicht mehr, um den Code für die Kompilierungszeit zu optimieren. Das Plug-in verwendet stattdessen den R8-Compiler, um Folgendes zu verarbeiten: Kompilierungszeit-Aufgaben:
- Codeverkleinerung (oder Baumschütteln): Erkennt und entfernt ungenutzte Klassen, Felder, Methoden und Attribute aus Ihrer App und ihrer Bibliothek Abhängigkeiten (und ist somit ein wertvolles Tool zur Umgehung des Referenzlimit von 64.000). Wenn Sie beispielsweise nur wenige APIs einer Bibliotheksabhängigkeit vorliegen, kann durch Verkleinern der Bibliothekscode identifiziert werden. dass Ihre App nicht verwendet, und entfernen Sie nur diesen Code aus der App. Bis Weitere Informationen finden Sie im Abschnitt Code verkleinern.
- Ressourcenverkleinerung:Entfernt nicht verwendete Ressourcen aus der gepackten Anwendung. nicht verwendete Ressourcen in die Bibliotheksabhängigkeiten Ihrer App. Funktioniert in zusammen mit der Codekomprimierung, sodass nach Entfernen von nicht verwendetem Code Ressourcen, auf die nicht mehr verwiesen wird, können ebenfalls entfernt werden. Weitere Informationen finden Sie im Abschnitt verringern Sie Ihre Ressourcen.
- Optimierung:Überprüfung und Neuschreibung des Codes zur Verbesserung der Laufzeit
und die Größe der DEX-Dateien Ihrer App weiter reduzieren. Dieses
verbessert die Laufzeitleistung des Codes um bis zu 30 % und verbessert
Start- und Frame-Timings. Wenn R8 beispielsweise erkennt, dass die
else {}
für eine bestimmte if/else-Anweisung nie verwendet wird, entfernt R8 den Code für Zweigelse {}
. Weitere Informationen finden Sie im Abschnitt Code-Optimierung. - Verschleierung (oder Reduzierung von Kennungen): kürzt den Namen von Klassen. und Mitglieder, wodurch sich die Größe der DEX-Dateien verringert. Weitere Informationen findest du unter im Abschnitt zur Verschleierung von Code.
Beim Erstellen der Release-Version Ihrer App kann R8 so konfiguriert werden, dass die oben beschriebenen Aufgaben zur Kompilierungszeit. Sie können auch bestimmte oder das Verhalten von R8 mithilfe von ProGuard-Regeldateien anpassen. R8 funktioniert mit allen Ihren vorhandenen ProGuard-Regeldateien. Wenn Sie das Android-Gradle-Plug-in für R8 aktualisieren, sollten Sie keine Änderung vornehmen müssen Ihre bestehenden Regeln.
Verkleinerung, Verschleierung und Optimierung aktivieren
Wenn Sie Android Studio 3.4 oder das Android-Gradle-Plug-in 3.4.0 und höher verwenden, ist R8 den Standard-Compiler, der den Java-Bytecode Ihres Projekts in den DEX umwandelt das auf der Android-Plattform ausgeführt wird. Wenn Sie jedoch ein neues Projekt Verkleinern, Verschleierung und Codeoptimierung ist standardmäßig aktiviert. Das liegt daran, dass diese Optimierungen bei der Kompilierungszeit die Build-Dauer Ihres Projekts und können zu Fehlern führen, wenn Sie festlegen, welcher Code beibehalten werden soll.
Daher ist es am besten, diese Aufgaben während der Kompilierung zu aktivieren, wenn Sie die endgültige Version die Sie vor der Veröffentlichung testen. Um Verkleinerung, Verschleierung Optimierung: Nehmen Sie Folgendes in Ihr Build-Skript auf Projektebene auf:
Kotlin
android { buildTypes { getByName("release") { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. Make sure to use a build // variant with `isDebuggable=false`. isMinifyEnabled = true // Enables resource shrinking, which is performed by the // Android Gradle plugin. isShrinkResources = true proguardFiles( // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. getDefaultProguardFile("proguard-android-optimize.txt"), // Includes a local, custom Proguard rules file "proguard-rules.pro" ) } } ... }
Cool
android { buildTypes { release { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. Make sure to use a build // variant with `debuggable false`. minifyEnabled true // Enables resource shrinking, which is performed by the // Android Gradle plugin. shrinkResources true // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. proguardFiles getDefaultProguardFile( 'proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... }
R8-Konfigurationsdateien
R8 verwendet ProGuard-Regeldateien, um das Standardverhalten zu ändern die Struktur Ihrer App zu verstehen, z. B. die Klassen, die als Einstiegspunkte dienen in den Code Ihrer App einfügen. Sie können zwar einige dieser Regeldateien ändern, können automatisch von Tools zur Kompilierungszeit wie AAPT2 oder aus den Bibliotheksabhängigkeiten Ihrer App übernommen. In der folgenden Tabelle werden die Quellen von ProGuard-Regeldateien, die R8 verwendet.
Quelle | Standort | Beschreibung |
Android Studio | <module-dir>/proguard-rules.pro
|
Wenn Sie ein neues Modul mit Android Studio erstellen, erstellt die IDE ein
proguard-rules.pro im Stammverzeichnis dieses Moduls.
Standardmäßig werden auf diese Datei keine Regeln angewendet. Fügen Sie also Ihre eigenen ProGuard-Regeln hier an, z. B. Ihre benutzerdefiniert Regeln beibehalten. |
Android-Gradle-Plug-in | Wird vom Android-Gradle-Plug-in bei der Kompilierung generiert. | Das Android-Gradle-Plug-in generiert
proguard-android-optimize.txt mit Regeln, die
ist für die meisten Android-Projekte nützlich und ermöglicht
@Keep*
Anmerkungen.
Wenn Sie mit Android Studio ein neues Modul erstellen, wird die Modulebene Das Build-Skript enthält diese Regeldatei in Ihrem Release-Build für Sie.
Hinweis:Das Android-Gradle-Plug-in enthält zusätzliche vordefinierte ProGuard-Funktionen.
Regeldateien. Es wird jedoch empfohlen,
|
Bibliotheksabhängigkeiten |
In einer automatisch angewendeten Empfehlungen:
In einer JAR-Bibliothek: Zusätzlich zu diesen Speicherorten gibt es auch das Android-Gradle-Plug-in 3.6 oder höher, unterstützt Targeting-Regeln für die Verkleinerung. |
Wenn eine AAR- oder JAR-Bibliothek mit einer eigenen Regeldatei veröffentlicht wird und Sie diese Bibliothek als Kompilierungszeitabhängigkeit, R8 automatisch und wendet diese Regeln bei der Projektzusammenstellung an. Zusätzlich zu den herkömmlichen ProGuard-Regeln 3.6 oder höher unterstützt auch Targeting-Regeln zum Reduzieren der Größe. Dies sind Regeln die auf bestimmte Schrumpfgeräte (R8 oder ProGuard) abzielen, sowie kürzere Versionen. Die Verwendung von Regeldateien, die mit Bibliotheken gepackt sind, ist nützlich, wenn die Regeln erforderlich sind, damit die Bibliothek ordnungsgemäß funktioniert, d. h. die Bibliothek hat der Entwickler die Schritte zur Fehlerbehebung für Sie durchgeführt. Da die Regeln additiv sind, können bestimmte Regeln, die eine Bibliotheksabhängigkeit umfasst, nicht entfernt und kann sich auf die Zusammenstellung anderer Teile Ihrer App auswirken. Wenn zum Beispiel ein Bibliothek eine Regel zum Deaktivieren von Codeoptimierungen enthält. Diese Regel deaktiviert Optimierungen für Ihr gesamtes Projekt. |
Android Asset Package Tool 2 (AAPT2) | Nachdem Sie Ihr Projekt mit minifyEnabled true erstellt haben, gehen Sie so vor:
<module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt
|
AAPT2 erstellt Keep-Regeln basierend auf Verweisen auf Klassen in den Manifest, Layouts und anderen App-Ressourcen. Zum Beispiel enthält AAPT2 für jede Aktivität, die du im Manifest deiner App als Einstiegspunkts hinzufügen. |
Benutzerdefinierte Konfigurationsdateien | Wenn Sie ein neues Modul mit Android Studio erstellen,
erstellt <module-dir>/proguard-rules.pro für Sie, damit Sie Ihre eigenen hinzufügen können
Regeln.
|
Sie können zusätzliche Konfigurationen, und R8 wendet sie zur Kompilierungszeit an. |
Wenn Sie das Attribut minifyEnabled
auf true
setzen, kombiniert R8 Regeln aus allen
den oben aufgeführten verfügbaren Quellen. Das sollten Sie sich merken, wenn Sie
Fehlerbehebung mit R8, da andere Abhängigkeiten bei der Kompilierungszeit
wie Bibliotheksabhängigkeiten, kann zu Änderungen im R8-Verhalten führen,
die Sie noch nicht kennen.
Um einen vollständigen Bericht mit allen Regeln zu erstellen, die R8 beim Erstellen Ihres
Projekt enthalten, fügen Sie Folgendes in die proguard-rules.pro
-Datei Ihres Moduls ein:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
Zielgerichtete Schrumpfregeln
Android-Gradle-Plug-in 3.6 oder höher unterstützt Bibliotheken Regeln für die Ausrichtung (R8 oder ProGuard) sowie spezifische Schrumpfversionen Dieses ermöglicht es Bibliotheksentwicklern, ihre Regeln so anzupassen, dass sie optimal in Projekten arbeiten. die neue reduzierte Versionen verwenden, während bestehende Regeln weiterhin funktionieren, die in Projekten mit älteren verkleinerten Versionen verwendet werden.
Um gezielte Schrumpfregeln festzulegen, müssen Bibliotheksentwickler sie einschließen an bestimmten Stellen innerhalb einer AAR- oder JAR-Bibliothek, wie unten beschrieben.
In an AAR library:
proguard.txt (legacy location)
classes.jar
└── META-INF
└── com.android.tools (targeted shrink rules location)
├── r8-from-<X>-upto-<Y>/<R8-rules-file>
└── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>
In a JAR library:
META-INF
├── proguard/<ProGuard-rules-file> (legacy location)
└── com.android.tools (targeted shrink rules location)
├── r8-from-<X>-upto-<Y>/<R8-rules-file>
└── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>
Das bedeutet, dass die Regeln für die gezielte Verkleinerung im META-INF/com.android.tools
gespeichert werden
Verzeichnis einer JAR-Datei oder im Verzeichnis META-INF/com.android.tools
darin
classes.jar
eines AAE.
Unter diesem Verzeichnis können mehrere Verzeichnisse vorhanden sein, deren Namen folgendes Format haben:
von r8-from-<X>-upto-<Y>
oder proguard-from-<X>-upto-<Y>
, um anzugeben,
Versionen, für die die Regeln in den Verzeichnissen
verkleinert werden.
Beachte, dass die Teile -from-<X>
und -upto-<Y>
optional sind, die Version <Y>
ist exklusiv und die Versionsbereiche müssen fortlaufend sein.
Beispiel: r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
und r8-from-8.2.0
einen gültigen Satz von
Targeting-Regeln für die Verkleinerung. Die Regeln unter
Das Verzeichnis r8-from-8.0.0-upto-8.2.0
wird in R8 von Version 8.0.0 bis zu
aber ohne Version 8.2.0.
Anhand dieser Informationen wählt das Android-Gradle-Plug-in ab Version 3.6
aus den übereinstimmenden R8-Verzeichnissen. Wenn in einer Bibliothek kein Targeting für
werden die Regeln kleiner, werden vom Android-Gradle-Plug-in
Standorte (proguard.txt
für AAE oder
META-INF/proguard/<ProGuard-rules-file>
für eine JAR-Datei).
Bibliotheksentwickler können entweder gezielte Verkleinerungsregeln oder Legacy- ProGuard-Regeln in ihren Bibliotheken oder in beiden Typen, falls die Kompatibilität mit Android-Gradle-Plug-ins, die älter als Version 3.6 sind, oder anderen Tools
Zusätzliche Konfigurationen hinzufügen
Wenn Sie ein neues Projekt oder Modul mit Android Studio erstellen, erstellt die IDE ein
<module-dir>/proguard-rules.pro
-Datei, in die Sie Ihre eigenen Regeln einfügen können. Ich
können auch zusätzliche Regeln aus anderen Dateien enthalten, indem Sie diese
proguardFiles
im Build-Skript des Moduls ein.
So können Sie z. B. Regeln hinzufügen, die für jede Build-Variante spezifisch sind, indem Sie
weitere proguardFiles
-Property im entsprechenden productFlavor
-Block. Die
über die Gradle-Datei, dass flavor2-rules.pro
dem Produkt-Flavor flavor2
hinzugefügt wird.
flavor2
verwendet jetzt alle drei ProGuard-Regeln, weil die von der release
angewendet.
Außerdem können Sie die Eigenschaft testProguardFiles
hinzufügen, die ein
Liste der ProGuard-Dateien, die nur im Test-APK enthalten sind:
Kotlin
android { ... buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). "proguard-rules.pro" ) testProguardFiles( // The proguard files listed here are included in the // test APK only. "test-proguard-rules.pro" ) } } flavorDimensions.add("version") productFlavors { create("flavor1") { ... } create("flavor2") { proguardFile("flavor2-rules.pro") } } }
Cool
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). 'proguard-rules.pro' testProguardFiles // The proguard files listed here are included in the // test APK only. 'test-proguard-rules.pro' } } flavorDimensions "version" productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } }
Code verkleinern
Das Verkleinern von Code mit R8 ist standardmäßig aktiviert, wenn Sie den minifyEnabled
festlegen
zu true
.
Code Shrinking (auch Tree Shaking) ist der Vorgang, bei dem Code entfernt wird. die R8 zur Laufzeit nicht benötigt. Dieser Prozess kann die wenn Ihre App viele Bibliotheksabhängigkeiten enthält, aber und nutzt nur einen kleinen Teil ihrer Funktionalität.
Um den Code Ihrer App zu verkürzen, bestimmt R8 zunächst alle Einstiegspunkte in die basierend auf dem kombinierten Satz von Konfigurationsdateien. Diese Einstiegspunkte umfassen alle Klassen, die die Android-Plattform zum Öffnen von die Aktivitäten oder Dienste Ihrer App. Ausgehend von jedem Einstiegspunkt prüft R8 um eine Grafik mit allen Methoden, Mitgliedsvariablen und anderen Klassen, auf die Ihre App zur Laufzeit zugreifen kann. Code, der nicht mit wird dieses Diagramm als nicht erreichbar angesehen und möglicherweise aus der App entfernt.
Abbildung 1 zeigt eine Anwendung mit einer Laufzeitbibliothekabhängigkeit. Bei der Untersuchung der
App-Code ermittelt R8, dass die Methoden foo()
, faz()
und bar()
ist vom Einstiegspunkt MainActivity.class
aus erreichbar. Die Klasse
OkayApi.class
oder seine Methode baz()
wird von deiner App niemals zur Laufzeit verwendet und
R8 entfernt diesen Code beim Verkleinern Ihrer App.
R8 bestimmt Einstiegspunkte über -keep
-Regeln in der
R8-Konfigurationsdateien. Das heißt, dass Sie Regeln
Klassen, die R8 beim Verkleinern der App nicht verwerfen sollte und die R8 berücksichtigt,
als mögliche Einstiegspunkte in Ihre App. Das Android-Gradle-Plug-in
und AAPT2 generieren automatisch Notizen, die von den meisten Apps
Projekte für Sie, z. B. Aktivitäten, Aufrufe und Dienste Ihrer App. Sie können jedoch
Wenn Sie dieses Standardverhalten mit zusätzlichen Regeln zum Beibehalten anpassen müssen, lesen Sie
finden Sie im Abschnitt Festlegen, welcher Code beibehalten werden soll.
Wenn Sie nur die Ressourcen Ihrer App reduzieren möchten, Fahren Sie mit dem Abschnitt zum Reduzieren von Ressourcen fort.
Wenn ein Bibliotheksprojekt verkleinert ist, wird eine App, die auf dieser Bibliothek basiert, umfasst verkleinerte Bibliotheksklassen. Möglicherweise müssen Sie die Regeln für die Bibliotheksbeibehaltung anpassen, wenn Im Bibliotheks-APK fehlen Klassen. Wenn Sie ein Projekt für eine Bibliothek im AAR-Format haben, sind lokale JAR-Dateien, von denen Ihre Bibliothek abhängig ist, nicht in der AAR-Datei kleiner werden.
Anpassen, welcher Code beibehalten werden soll
In den meisten Fällen wird die Standarddatei für ProGuard-Regeln (proguard-android-optimize.txt
)
R8 reicht aus, nur den nicht verwendeten Code zu entfernen. Sie können jedoch
einige Situationen sind für R8 schwer zu analysieren.
den Ihre App wirklich braucht. Beispiele für Fälle, in denen Google Fotos fälschlicherweise
Code enthalten:
- Wenn Ihre App eine Methode über die Java Native Interface (JNI) aufruft
- Wenn Ihre App zur Laufzeit Code sucht (z. B. bei Reflexion)
Beim Testen deiner App sollten alle Fehler aufgedeckt werden, die durch unangemessene Entfernungen verursacht werden. Sie können aber auch überprüfen, welcher Code einen Bericht über entfernten Code generieren.
Um Fehler zu beheben und R8 zu erzwingen, bestimmten Code beizubehalten, fügen Sie
-keep
in der ProGuard-Regeldatei. Beispiel:
-keep public class MyClass
Alternativ können Sie den
@Keep
-Annotation zum Code hinzufügen,
behalten möchten. Wenn Sie einem Kurs @Keep
hinzufügen, bleibt der gesamte Kurs unverändert.
Wenn Sie es einer Methode oder einem Feld hinzufügen, bleiben auch die Methode bzw. das Feld (und sein Name) erhalten.
da der Klassenname unverändert bleibt. Diese Anmerkung ist nur verfügbar, wenn
die
AndroidX-Anmerkungsbibliothek
Wenn Sie die ProGuard-Regeldatei hinzufügen,
Gradle-Plug-in, wie im Abschnitt zur
Aktivieren Sie die Verkleinerung.
Bei der Verwendung der Option -keep
sollten Sie eine Reihe von Überlegungen berücksichtigen: für
Weitere Informationen zum Anpassen der Regeldatei finden Sie in der
ProGuard-Bedienungsanleitung
Die
Fehlerbehebung
beschreibt andere häufige Probleme, die auftreten können, wenn Ihr Code
entfernt.
Native Bibliotheken entfernen
Standardmäßig werden native Codebibliotheken in Release-Builds Ihrer App entfernt. Bei diesem Entfernen werden die Symboltabelle und Debugging-Informationen entfernt. in nativen Bibliotheken enthalten, die von Ihrer App verwendet werden. Nativen Code entfernen führen zu erheblichen Größeneinsparungen; aber es ist unmöglich, in der Google Play Console aufgrund fehlender Informationen (z. B. Klassen- und Funktionsnamen).
Native Unterstützung für Abstürze
Die Google Play Console meldet native Abstürze unter Android Vitals Mit ein paar können Sie eine native Debugging-Symboldatei für Ihre App generieren und hochladen. Diese Datei aktiviert symbolisch dargestellte native Absturz-Stacktraces (die Klasse und Funktionsnamen) in Android Vitals, damit du Fehler in deiner App in der Produktionsphase beheben kannst. Diese Schritte variieren je nach Version des Android-Gradle-Plug-ins, das in und die Build-Ausgabe Ihres Projekts.
Android-Gradle-Plug-in ab Version 4.1
Wenn Sie für Ihr Projekt ein Android App Bundle erstellen, können Sie das
native Debugging-Symboldatei enthält. Um diese Datei in Release-Builds aufzunehmen, füge den
folgende URL in die Datei build.gradle.kts
Ihrer App ein:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
Wählen Sie die Symbolebene für die Fehlerbehebung aus:
- Mit
SYMBOL_TABLE
kannst du Funktionsnamen in den symbolisch dargestellten Stacktraces der Play Console abrufen. Dieses Level unterstützt Tombstones. - Mit
FULL
kannst du Funktionsnamen, Dateien und Zeilennummern im Play Console- symbolisch dargestellte Stacktraces.
Wenn in deinem Projekt ein APK erstellt wird, verwende die angezeigte Build-Einstellung build.gradle.kts
.
um die Datei mit Symbolen zum Debuggen separat zu generieren. Manuell
Datei mit Symbolen zum Debuggen von nativem Code hochladen
in der Google Play Console. Im Rahmen des Build-Prozesses
Das Plug-in gibt diese Datei am folgenden Projektspeicherort aus:
app/build/outputs/native-debug-symbols/variant-name/native-debug-symbols.zip
Android-Gradle-Plug-in Version 4.0 oder niedriger (und andere Build-Systeme)
Im Rahmen des Build-Prozesses speichert das Android-Gradle-Plug-in eine Kopie der in einem Projektverzeichnis enthalten. Diese Verzeichnisstruktur sieht etwa so aus:
app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── arm64-v8a/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
├── x86/
│ ├── libgameengine.so
│ ├── libothercode.so
│ └── libvideocodec.so
└── x86_64/
├── libgameengine.so
├── libothercode.so
└── libvideocodec.so
Komprimieren Sie den Inhalt dieses Verzeichnisses:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
Manuell laden Sie die Datei
symbols.zip
hoch in der Google Play Console.
Ressourcen verkleinern
Das Verkleinern von Ressourcen funktioniert nur in Verbindung mit der Codeverkleinerung. Nach dem entfernt den gesamten nicht verwendeten Code, Ressourcen, die die App noch verwendet. Dies gilt insbesondere, wenn Sie Code Bibliotheken, die Ressourcen enthalten, müssen Sie nicht verwendeten Bibliothekscode entfernen, damit der Bibliotheksressourcen werden nicht mehr referenziert und können daher von der Ressource entfernt werden. schrumpft.
Wenn Sie das Verkleinern von Ressourcen aktivieren möchten, legen Sie das Attribut shrinkResources
fest
in Ihr Build-Skript true
(neben
minifyEnabled
für das Verkleinern von Code). Beispiel:
Kotlin
android { ... buildTypes { getByName("release") { isShrinkResources = true isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" ) } } }
Cool
android { ... buildTypes { release { shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
Wenn Sie Ihre App noch nicht mit minifyEnabled
für
und versuchen Sie dies, bevor Sie shrinkResources
aktivieren,
da Sie möglicherweise Ihre proguard-rules.pro
-Datei bearbeiten müssen,
die dynamisch erstellten oder aufgerufenen Klassen oder Methoden beibehalten,
beginnen Sie mit dem Entfernen von Ressourcen.
Anpassen, welche Ressourcen beibehalten werden sollen
Wenn Sie bestimmte Ressourcen beibehalten oder verwerfen möchten, erstellen Sie eine XML-Datei
mit einem <resources>
-Tag in Ihrem Projekt erstellen und jedes
Ressource, die im Attribut tools:keep
beibehalten werden soll, und jede Ressource,
im Attribut tools:discard
verwerfen. Beide Attribute akzeptieren einen
kommagetrennte Liste von Ressourcennamen. Sie können das Sternchen als
ein Platzhalterzeichen ist.
Beispiel:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" />
Speichern Sie diese Datei in Ihren Projektressourcen, z. B. unter
res/raw/my.package.keep.xml
Der Build verpackt diese Datei nicht in Ihr
Hinweis:Verwenden Sie für die Datei keep
einen eindeutigen Namen. Wann?
verschiedene Bibliotheken verknüpft werden, deren Regeln für Notizen zu Konflikten führen würden
Andernfalls kann es zu Problemen mit ignorierten Regeln oder unnötigen
Ressourcen.
Die Angabe, welche Ressourcen verworfen werden sollen, mag albern erscheinen,
Löschen Sie sie stattdessen.
Dies kann jedoch nützlich sein, wenn Sie Build-Varianten verwenden. Für
Sie können z. B. alle Ihre Ressourcen
im gemeinsamen Projektverzeichnis ablegen,
Erstellen Sie dann für jeden Parameter eine eigene my.package.build.variant.keep.xml
-Datei
Build-Variante, wenn Sie wissen, dass eine bestimmte Ressource im Code verwendet wird
(und wird daher nicht vom Verkleinerer entfernt).
die für die jeweilige Build-Variante verwendet wird. Es ist auch möglich, dass die Build-Tools
eine Ressource fälschlicherweise als erforderlich identifiziert. Dies ist möglich,
fügt der Compiler die Ressourcen-IDs inline hinzu.
den Unterschied zwischen einer Ressource, auf die eigentlich verwiesen wird, und einem ganzzahligen Wert kennen
die zufällig denselben Wert haben.
Strikte Referenzprüfungen aktivieren
Normalerweise kann mit dem
Ressourcenverkleinerer genau festgestellt werden,
verwendet wird. Wenn Ihr Code jedoch einen Aufruf an
Resources.getIdentifier()
(oder in einer Ihrer Bibliotheken, dem AppCompat
enthält, sucht Ihr Code nach Ressourcennamen,
dynamisch generierten Zeichenfolgen. In diesem Fall verhält sich der Ressourcenschrumpfer
standardmäßig geschützt und kennzeichnet alle Ressourcen mit einem übereinstimmenden Namensformat als
möglicherweise verwendet und kann nicht entfernt werden.
Der folgende Code führt beispielsweise dazu, dass alle Ressourcen mit dem
Das Präfix img_
, das als verwendet markiert werden soll.
Kotlin
val name = String.format("img_%1d", angle + 1) val res = resources.getIdentifier(name, "drawable", packageName)
Java
String name = String.format("img_%1d", angle + 1); res = getResources().getIdentifier(name, "drawable", getPackageName());
Der Ressourcenschrumpfer durchsucht auch alle Stringkonstanten in Ihrem
Code sowie verschiedene res/raw/
-Ressourcen suchen,
URLs in einem ähnlichen Format wie
file:///android_res/drawable//ic_plus_anim_016.png
. Wenn
Zeichenfolgen wie diese oder andere, die aussehen, als könnten sie zum Erstellen von URLs verwendet werden
werden diese nicht entfernt.
Dies sind Beispiele für den sicheren Verkleinerungsmodus, der standardmäßig aktiviert ist.
Du kannst die Option „Besser geschützt als Entschuldigung“ aber auch deaktivieren. Umgang mit Ihren Daten
damit nur Ressourcen
beibehalten werden, die mit Sicherheit verwendet werden. Bis
Setzen Sie dazu shrinkMode
auf strict
in der
keep.xml
:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
Wenn Sie den strikten Verkleinerungsmodus aktivieren und Ihr Code auch
Ressourcen mit dynamisch generierten Strings wie oben gezeigt, müssen Sie
Sie können diese Ressourcen manuell mit dem Attribut tools:keep
behalten.
Nicht verwendete alternative Ressourcen entfernen
Der Gradle-Ressourcenverkleinerer entfernt nur Ressourcen, auf die nicht verwiesen wird
durch Ihren App-Code. Das bedeutet, dass nicht entfernt wird,
alternative Ressourcen für unterschiedliche Gerätekonfigurationen. Bei Bedarf können Sie
können Sie mit dem Attribut resConfigs
des Android-Gradle-Plug-ins
alternative Ressourcendateien entfernen, die Ihre App nicht benötigt.
Wenn Sie z. B. eine Bibliothek mit Sprachressourcen verwenden,
wie AppCompat oder Google Play-Dienste, enthält deine App alle
übersetzte Sprachzeichenfolgen für die Nachrichten in diesen Bibliotheken
der restlichen App in die
gleiche Sprache oder nicht übersetzt wird. Wenn Sie
nur die Sprachen beizubehalten, die deine App offiziell unterstützt, kannst du
diese Sprachen mithilfe des Attributs resConfig
. Beliebige Ressourcen für
Sprachen, die nicht angegeben sind, werden entfernt.
Das folgende Snippet zeigt, wie Sie Ihre Sprachressourcen auf Englisch und Französisch:
Kotlin
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
Cool
android { defaultConfig { ... resConfigs "en", "fr" } }
Wenn Sie eine App im Android App Bundle-Format veröffentlichen, ist standardmäßig nur Sprachen, die auf dem Gerät eines Nutzers konfiguriert sind, werden bei der Installation der App heruntergeladen. Ebenso können nur Ressourcen, die der Bildschirmdichte des Geräts entsprechen, native Bibliotheken, die dem ABI des Geräts entsprechen, sind im Download enthalten. Weitere Informationen finden Sie in den Android-App Bundle-Konfiguration.
Bei älteren Apps, die mit APKs veröffentlicht werden, die vor August 2021 erstellt wurden, können Sie Passen Sie die Bildschirmdichte oder ABI-Ressourcen an, die Sie in Ihr APK aufnehmen möchten, indem Sie Erstellen mehrerer APKs die jeweils auf eine andere Gerätekonfiguration ausgerichtet sind.
Doppelte Ressourcen zusammenführen
Standardmäßig führt Gradle auch Ressourcen mit identischem Namen zusammen, z. B.
Drawables mit demselben Namen, die sich
in verschiedenen Ressourcenordnern befinden können. Dieses
Das Verhalten wird nicht durch das Attribut shrinkResources
gesteuert und
kann nicht deaktiviert werden, da es notwendig ist, Fehler zu vermeiden, wenn mehrere
Ressourcen mit dem Namen übereinstimmen, nach dem Ihr Code sucht.
Ressourcen werden nur zusammengeführt, wenn zwei oder mehr Dateien denselben Ressourcenname, -typ und -qualifizierer. Gradle wählt die Datei aus, die beste Wahl unter den Duplikaten sein (basierend auf der beschriebenen Prioritätsreihenfolge) unten) und übergibt nur diese eine Ressource zur Verteilung in der des finalen Artefakts.
Gradle sucht an den folgenden Speicherorten nach doppelten Ressourcen:
- Die Hauptressourcen, die mit dem Hauptquellensatz verknüpft sind, sind im Allgemeinen
in
src/main/res/
. - Die Varianten-Overlays vom Build-Typ und den Build-Geschmacksrichtungen.
- Die Abhängigkeiten des Bibliotheksprojekts.
Gradle führt doppelte Ressourcen in der folgenden kaskadierenden Prioritätsreihenfolge zusammen:
Abhängigkeiten → Hauptseite → Build-Flavor → Build-Typ
Wenn beispielsweise eine Ressource doppelt in Ihren Hauptressourcen und einen Build-Flavor enthält, wählt Gradle den im Build-Flavor aus.
Wenn identische Ressourcen im selben Quellsatz vorkommen, kann Gradle nicht zusammengeführt werden.
und gibt einen Fehler bei der
Zusammenführung von Ressourcen aus. Dies kann passieren, wenn Sie mehrere
Quell-Sets im Attribut sourceSet
Ihrer
build.gradle.kts
-Datei, z. B. wenn sowohl src/main/res/
als auch
und src/main/res2/
enthalten identische Ressourcen.
Code verschleiern
Der Zweck der Verschleierung besteht darin, die App-Größe zu reduzieren, indem Sie die Namen der die Klassen, Methoden und Felder Ihrer App. Im Folgenden finden Sie ein Beispiel für Verschleierung mit R8:
androidx.appcompat.app.ActionBarDrawerToggle$DelegateProvider -> a.a.a.b:
androidx.appcompat.app.AlertController -> androidx.appcompat.app.AlertController:
android.content.Context mContext -> a
int mListItemLayout -> O
int mViewSpacingRight -> l
android.widget.Button mButtonNeutral -> w
int mMultiChoiceItemLayout -> M
boolean mShowTitle -> P
int mViewSpacingLeft -> j
int mButtonPanelSideLayout -> K
Durch die Verschleierung wird zwar kein Code aus Ihrer App entfernt, es können jedoch erhebliche Größeneinsparungen erzielt werden. ist in Apps mit DEX-Dateien zu sehen, die viele Klassen, Methoden und Felder indexieren. Durch die Verschleierung werden jedoch andere Teile des Codes umbenannt, wie das Prüfen von Stacktraces, sind zusätzliche Tools erforderlich. Um die Leistung Ihrer nach der Verschleierung des Stacktrace finden Sie im Abschnitt einen verschleierten Stacktrace decodieren.
Wenn Ihr Code auf vorhersehbaren Namen für die Methoden Ihrer App basiert, und Klassen. Wenn Sie Reflexion anwenden, sollten Sie diese Signaturen als Einstiegspunkte verwenden und Regeln für die Aufbewahrungsdauer festlegen, wie in den finden Sie im Abschnitt Festlegen, welcher Code beibehalten werden soll. Diese Notizen weisen Sie R8 an, diesen Code nicht nur im endgültigen DEX Ihrer App beizubehalten, die ursprüngliche Bezeichnung.
Verschleierten Stacktrace decodieren
Nach der Verschleierung Ihres Codes mit R8 ist es schwierig, einen Stacktrace zu verstehen weil die Namen von Klassen und Methoden geändert. Um den ursprünglichen Stacktrace zu erhalten, Stacktrace erneut verfolgen.
Codeoptimierung
Um Ihre App noch weiter zu optimieren, untersucht R8 Ihren Code eingehender um nicht verwendeten Code zu entfernen oder Ihren Code nach Möglichkeit so umzuschreiben, weniger ausführlich. Im Folgenden finden Sie einige Beispiele für solche Optimierungen:
- Wenn Ihr Code nie den
else {}
-Zweig für eine bestimmte if/else-Anweisung annimmt, R8 entfernt möglicherweise den Code für den Zweigelse {}
. - Wenn Ihr Code eine Methode nur an wenigen Stellen aufruft, entfernt R8 die Methode möglicherweise und es bei einigen Anruf-Websites inline anzeigen.
- Wenn R8 feststellt, dass eine Klasse nur eine eindeutige Unterklasse hat, und die Klasse wird nicht instanziiert (zum Beispiel eine abstrakte Basisklasse, die nur von einer konkreten Implementierungsklasse), dann kann R8 die beiden Klassen um einen Kurs aus der App zu entfernen.
- Weitere Informationen finden Sie in der Blogpost zur R8-Optimierung von Jake Wharton
Mit R8 können Sie keine diskreten Optimierungen deaktivieren oder aktivieren oder den
einer Optimierung. R8 ignoriert sogar alle ProGuard-Regeln,
Standardoptimierungen wie -optimizations
und
-optimizationpasses
. Diese Einschränkung ist wichtig, da R8
und die Aufrechterhaltung eines Standardverhaltens
Das Studio-Team kann auftretende Probleme problemlos beheben.
Wenn Sie die Optimierung aktivieren, werden die Stacktraces für Ihre . Durch das Inline-Format werden beispielsweise Stapelframes entfernt. Weitere Informationen finden Sie im Abschnitt retracing um, wie Sie die ursprünglichen Stacktraces abrufen können.
Auswirkungen auf die Laufzeitleistung
Wenn die Verkleinerung, Verschleierung und Optimierung aktiviert sind, verbessert sich R8 Laufzeitleistung des Codes (einschließlich Start- und Frame Time im UI-Thread) um bis zu 30%. Wenn Sie eine dieser Optionen deaktivieren, werden die Möglichkeiten zur Optimierung erheblich eingeschränkt. R8 verwendet.
Wenn R8 aktiviert ist, sollten Sie auch Start-up-Profile erstellen für eine noch bessere Start-up-Leistung.
Strengere Optimierungen aktivieren
R8 enthält eine Reihe zusätzlicher Optimierungen (als „Full-Modus“ bezeichnet), die anders als bei ProGuard. Diese Optimierungen werden durch Standard seit Android-Gradle-Plug-in, Version 8.0.0.
Sie können diese zusätzlichen Optimierungen deaktivieren, indem Sie Folgendes in
in die gradle.properties
-Datei Ihres Projekts ein:
android.enableR8.fullMode=false
Da sich R8 durch die zusätzlichen Optimierungen von ProGuard unterscheidet, Möglicherweise müssen Sie zusätzliche ProGuard-Regeln hinzufügen, um Laufzeiten zu vermeiden. wenn Sie Regeln verwenden, die für ProGuard entwickelt wurden. Nehmen wir zum Beispiel an, -Code verweist über die Java Reflection API auf eine Klasse. Wenn das Gerät nicht verwendet wird den Modus "Alle Zugriffe", R8 geht davon aus, dass Sie Objekte von auch wenn Ihr Code dies nicht tut, und es wird automatisch behält die Klasse und ihren statischen Initialisierer bei.
Bei Verwendung des Modus „Alle Zugriffe“ geht R8 jedoch nicht von dieser Annahme aus. Wenn R8 dass Ihr Code die Klasse sonst niemals zur Laufzeit verwendet, werden die aus dem finalen DEX Ihrer App. Das heißt, wenn Sie den Kurs und seine statischer Initialisierer müssen Sie eine Keep-Regel in Ihre Regeldatei einfügen,
Wenn bei der Verwendung des Modus „Vollständiger Modus“ Probleme auftreten, sehen Sie in der R8-FAQ-Seite nach einer möglichen Lösung. Falls Sie das Problem nicht lösen können, Fehler melden
Stacktraces werden zurückgeführt
Von R8 verarbeiteter Code wird auf verschiedene Arten geändert, um Stacktraces zu erstellen sind schwerer zu verstehen, da die Stacktraces nicht genau dem Quellcode entsprechen. Dieses kann bei Änderungen der Zeilennummern der Fall sein, wenn Debugging-Informationen nicht beibehalten werden. Dies kann auf Optimierungen wie Inline- und Outline-Funktionen zurückzuführen sein. Die ist die Verschleierung, bei der sogar die Klassen und Methoden Namen ändern.
Zur Wiederherstellung des ursprünglichen Stacktrace stellt R8 den retrace-Befehlszeilentool. im Paket mit Befehlszeilentools enthalten.
Damit die Stacktraces Ihrer Anwendung zurückgerufen werden können, müssen Sie sicherstellen,
Der Build behält genügend Informationen für das Nachverfolgen bei, indem er Folgendes hinzufügt:
Regeln für die Datei proguard-rules.pro
Ihres Moduls:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
Das Attribut LineNumberTable
behält Positionsinformationen bei.
damit diese Positionen in Stacktraces gedruckt werden. Das Attribut SourceFile
stellt sicher, dass alle potenziellen Laufzeiten
die Positionsinformationen tatsächlich ausgeben.
Die Anweisung -renamesourcefileattribute
legt den Namen der Quelldatei im Stapel fest
nur SourceFile
. Der tatsächliche Name der ursprünglichen Quelldatei ist nicht
erforderlich beim Zurückziehen, da die Zuordnungsdatei die ursprüngliche Quelldatei enthält.
R8 erstellt bei jeder Ausführung eine mapping.txt
-Datei, die
enthält die Informationen, die erforderlich sind, um Stacktraces dem Original zuzuordnen
Stacktraces. Android Studio speichert die Datei im
<module-name>/build/outputs/mapping/<build-type>/
-Verzeichnis.
Wenn du deine App bei Google Play veröffentlichst, kannst du die Datei mapping.txt
hochladen
für jede Version Ihrer App. Bei der Veröffentlichung mit Android App Bundles
-Datei wird automatisch in den Inhalt des App-Bundles aufgenommen. Dann Google
Play verfolgt eingehende Stacktraces auf Grundlage von vom Nutzer gemeldeten Problemen,
können sie sich in der Play Console ansehen. Weitere Informationen findest du in der Hilfe
Artikel darüber, wie Sie
Offenlegung von Absturz-Stacktraces
Fehlerbehebung mit R8
In diesem Abschnitt werden einige Strategien zur Fehlerbehebung bei der Aktivierung von Verkleinerung, Verschleierung und Optimierung mit R8. Wenn Sie keine Lösung finden zu Ihrem Problem weiter unten, lesen Sie auch R8-FAQ-Seite und Anleitung zur Fehlerbehebung von ProGuard.
Bericht zu entferntem (oder beibehaltenem) Code erstellen
Für die Behebung bestimmter R8-Probleme kann es hilfreich sein, einen Bericht
den gesamten Code, den R8 aus Ihrer App entfernt hat. Für jedes Modul, für das Sie
Fügen Sie -printusage <output-dir>/usage.txt
zu Ihrem benutzerdefinierten Bericht hinzu, um diesen Bericht zu erstellen.
Regeldatei. Wenn Sie R8 aktivieren und Ihre App erstellen, gibt R8 einen
Bericht mit dem Pfad und Dateinamen, den Sie angegeben haben. Bericht über entfernten Code
sieht etwa so aus:
androidx.drawerlayout.R$attr
androidx.vectordrawable.R
androidx.appcompat.app.AppCompatDelegateImpl
public void setSupportActionBar(androidx.appcompat.widget.Toolbar)
public boolean hasWindowFeature(int)
public void setHandleNativeActionModesEnabled(boolean)
android.view.ViewGroup getSubDecor()
public void setLocalNightMode(int)
final androidx.appcompat.app.AppCompatDelegateImpl$AutoNightModeManager getAutoNightModeManager()
public final androidx.appcompat.app.ActionBarDrawerToggle$Delegate getDrawerToggleDelegate()
private static final boolean DEBUG
private static final java.lang.String KEY_LOCAL_NIGHT_MODE
static final java.lang.String EXCEPTION_HANDLER_MESSAGE_SUFFIX
...
Wenn Sie stattdessen einen Bericht
zu den Einstiegspunkten sehen möchten, die R8
die Regeln für die Notizen Ihres Projekts einzuhalten , fügen Sie -printseeds <output-dir>/seeds.txt
in Ihr
benutzerdefinierte Regeln. Wenn Sie R8 aktivieren und Ihre App erstellen, gibt R8 aus.
einen Bericht mit dem Pfad und Dateinamen, den Sie angegeben haben. Bericht über einen aufbewahrten Eintrag
sehen in etwa so aus:
com.example.myapplication.MainActivity
androidx.appcompat.R$layout: int abc_action_menu_item_layout
androidx.appcompat.R$attr: int activityChooserViewStyle
androidx.appcompat.R$styleable: int MenuItem_android_id
androidx.appcompat.R$styleable: int[] CoordinatorLayout_Layout
androidx.lifecycle.FullLifecycleObserverAdapter
...
Fehler beim Verkleinern von Ressourcen beheben
Wenn Sie Ressourcen verkleinern, wird der Build zeigt eine Zusammenfassung der Ressourcen, die aus der App entfernt werden. Sie müssen zuerst auf Ansicht umschalten auf der linken Seite des Fensters, um eine detaillierte Textausgabe von Gradle anzuzeigen.) Beispiel:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
Gradle erstellt außerdem eine Diagnosedatei mit dem Namen resources.txt
in
<module-name>/build/outputs/mapping/release/
(gleiche
als Ausgabedateien von ProGuard. Diese Datei enthält Angaben dazu,
Ressourcen auf andere Ressourcen verweisen und welche Ressourcen verwendet werden
entfernt.
Um beispielsweise herauszufinden, warum @drawable/ic_plus_anim_016
noch in der App, öffnen Sie die Datei resources.txt
und suchen Sie danach
Dateinamen. Möglicherweise wird von einer anderen Ressource darauf verwiesen,
folgt:
16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016
Jetzt wissen Sie, warum @drawable/add_schedule_fab_icon_anim
erreichbar ist. Wenn Sie eine höhere Suche durchführen, werden Sie feststellen,
unter „Die erreichbaren Root-Ressourcen sind:“. Es gibt also eine Codereferenz,
an add_schedule_fab_icon_anim
(d. h., seine R.drawable-ID war
Code im erreichbaren Code).
Wenn Sie keine strikte Prüfung verwenden, können Ressourcen-IDs als erreichbar gekennzeichnet werden. ob es Zeichenfolgenkonstanten gibt, die so aussehen, als könnten sie zur Konstruktion Ressourcennamen für dynamisch geladene Ressourcen. Wenn Sie in diesem Fall der Build-Ausgabe für den Ressourcennamen angezeigt wird, könnte eine Meldung wie die folgende angezeigt werden:
10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
used because it format-string matches string pool constant ic_plus_anim_%1$d.
Wenn Sie einen dieser Zeichenfolgen sehen und sicher sind, dass der String nicht
zum dynamischen Laden der angegebenen Ressource verwendet wird, können Sie den
tools:discard
, um das Build-System zu informieren, dass es entfernt werden soll.
enthalten, wie im Abschnitt zur Anpassung der beizubehaltenden Ressourcen beschrieben.