Gdy włączysz optymalizację aplikacji z ustawieniami domyślnymi, R8 wykona rozległe optymalizacje, aby zmaksymalizować korzyści pod względem wydajności. R8 wprowadza istotne zmiany w kodzie, w tym zmianę nazwy, przeniesienie i usunięcie pól oraz metod klas. Jeśli powoduje to błędy, musisz określić, które części kodu mają pozostać bez zmian. W tym celu użyj składni keep rules.
R8 może nieprawidłowo usunąć lub zmodyfikować kod w tych sytuacjach:
- Odbicie: kod uzyskiwany za pomocą odbicia, na przykład za pomocą funkcji
Class.forName()
lubMethod.invoke()
. R8 zwykle nie może określić, do których klas lub metod będzie uzyskiwany dostęp w ten sposób. - Serializacja: klasy lub pola potrzebne do serializacji i deserializacji mogą wydawać się nieużywane przez R8 (jest to inna forma odbicia).
- Java Native Interface (JNI): metody Javy wywoływane z kodu natywnego. R8 nie analizuje kodu natywnego, aby sprawdzić, co może wywołać w Javie.
Na tej stronie znajdziesz informacje o tym, jak ograniczyć zakres optymalizacji R8. Aby dowiedzieć się, jak dostosować zasady przechowywania zasobów, przeczytaj artykuł Dodaj reguły przechowywania zasobów.
Gdzie dodać reguły Keep
Reguły należy dodać do pliku proguard-rules.pro
znajdującego się w katalogu głównym modułu (być może plik już tam jest, ale jeśli go nie ma, utwórz go). Aby zastosować reguły w pliku, musisz go zadeklarować w pliku build.gradle.kts
(lub build.gradle
) na poziomie modułu, jak pokazano w tym kodzie:
Kotlin
android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), // File with your custom rules. "proguard-rules.pro" ) ... } } ... }
Groovy
android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile('proguard-android-optimize.txt'), // File with your custom rules. 'proguard-rules.pro' ) } } // ... }
Domyślnie skrypt kompilacji zawiera też plik proguard-android-optimize.txt
. Ten plik zawiera reguły wymagane w większości projektów na Androida, dlatego należy go zachować w skrypcie kompilacji.
Jak pisać reguły w Keep
Podczas kompilowania aplikacji R8 wykrywa, który kod musi pozostać w aplikacji. Robi to, analizując graf wywołań aplikacji, który zaczyna się od wpisów w pliku manifestu (takich jak Twoje aktywności lub usługi), a potem śledzi wszystkie wywołania funkcji aplikacji i bibliotek. R8 usuwa kod, do którego nie odwołuje się bezpośrednio w ten sposób, co może powodować problemy, jeśli wykonany kod nie jest częścią tego grafu, np. kod wywoływany przez odbicie lustrzane. Dzięki napisaniu własnych reguł zachowania możesz poinformować R8 o tym, jaki kod ma pozostać w aplikacji.
Aby dodać regułę przechowywania, dodaj wiersz -keep
w pliku proguard-rules.pro
.
Zachowanie składni reguły
Zasady dotyczące przechowywania mają zwykle taki format:
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
Aby na przykład zachować konkretną klasę i wszystkich jej członków, użyj tych opcji:
-keep class com.myapp.MyClass { *; }
Więcej przykładów znajdziesz w sekcji z przykładami.
Oto, co robią komponenty reguły keep:
<KeepOption>
pozwala określić, które aspekty zajęć mają zostać zachowane:Opcja Zachowaj Opis -keep
Zachowaj zajęcia i użytkowników wymienionych w
[{ OptionalMemberSpecification }]
.-keepclassmembers
Zezwalanie na optymalizację zajęć. Jeśli zajęcia zostaną zachowane, zachowaj użytkowników wymienionych w
[{ OptionalMemberSpecification }]
.-keepnames
Zezwalaj na usuwanie zajęć i ich uczestników, ale nie ukrywaj ani nie modyfikuj ich w inny sposób.
-keepclassmembernames
Zezwalaj na usuwanie zajęć i uczestników, ale nie ukrywaj ani nie modyfikuj uczestników w inny sposób.
-keepclasseswithmembers
Brak usuwania lub zaciemniania klas, jeśli ich członkowie pasują do określonego wzorca.
Zalecamy głównie używanie opcji
-keepclassmembers
, ponieważ umożliwia ona najwięcej optymalizacji, a w razie potrzeby-keepnames
.-keep
nie pozwala na żadne optymalizacje, więc staraj się używać go oszczędnie.[OptionalModifier],...]
pozwala podać dowolną liczbę modyfikatorów języka Java klasy, np.public
lubfinal
.<ClassSpecification>
umożliwia określenie klasy (lub nadrzędnej klasy lub zaimplementowanego interfejsu), której ma dotyczyć reguła keep. W najprostszym przypadku jest to jedna w pełni kwalifikowana klasa.[{ OptionalMemberSpecification }]
umożliwia filtrowanie zachowania keep do tylko tych klas i metod, które pasują do określonych wzorców. Zazwyczaj zalecamy to w przypadku większości reguł przechowywania, aby zapobiec przechowywaniu większej liczby elementów, niż jest to zamierzone.
Przykłady reguł do zachowania
Oto kilka przykładów dobrze zaprojektowanych reguł Keep.
Tworzenie podklasy
Ta reguła przechowywania jest zapakowana w androidx.room:room-runtime
, aby zachować konstruktory bazy danych utworzone przez mechanizm odbicia.
-keep class * extends androidx.room.RoomDatabase { void <init>(); }
Odbicie z Android Framework ObjectAnimator
Ta reguła keep jest zapakowana w androidx.vectordrawable:vectordrawable-animated
, aby umożliwić ObjectAnimator
wywoływanie metod getter i setter z użyciem kodu natywnego za pomocą JNI. Pamiętaj, że nowsze systemy animacji w Compose nie wymagają takich reguł keep, to tylko przykładowa struktura reguł.
-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
void set*(***);
*** get*();
}
Rejestracja JNI
Ta reguła jest zapakowana w androidx.graphics:graphics-path
i służy do zachowywania metod natywnych. Może być to konieczne, jeśli Twoja biblioteka ręcznie rejestruje metody natywne za pomocą env->RegisterNatives()
.
-keepclasseswithmembers class androidx.graphics.path.** {
native <methods>;
}