Gdy włączysz optymalizację aplikacji z ustawieniami domyślnymi, R8 przeprowadzi optymalizację na dużą skalę, aby zmaksymalizować korzyści z wydajności. R8 wprowadza znaczące modyfikacje w kodzie, w tym zmianę nazw, przenoszenie i usuwanie klas, pól i metod. Jeśli zauważysz, że te modyfikacje powodują błędy, musisz określić, których części kodu R8 nie powinien modyfikować, deklarując je w regułach zachowywania.
Typowe scenariusze wymagające reguł zachowywania
R8 identyfikuje i zachowuje wszystkie bezpośrednie wywołania w kodzie. Nie widzi jednak pośrednich zastosowań kodu, co może spowodować usunięcie kodu potrzebnego aplikacji i doprowadzić do awarii. Użyj reguł zachowywania, aby poinformować R8, że ma zachować taki pośrednio używany kod. Oto kilka typowych sytuacji, w których prawdopodobnie będziesz potrzebować reguł zachowywania:
- Kod, do którego uzyskuje się dostęp za pomocą odbicia: R8 nie może określić, kiedy klasy, pola lub metody są dostępne za pomocą odbicia. Na przykład R8 nie może zidentyfikować metody wyszukiwanej według nazwy za pomocą
Class.getDeclaredMethod()ani adnotacji pobranej za pomocąClass.getAnnotation(). W takich przypadkach R8 może zmienić nazwy tych metod i adnotacji lub całkowicie je usunąć, co spowoduje wystąpienie w czasie działania wyjątkuClassNotFoundExceptionlubNoSuchMethodException. - Kod wywoływany z interfejsu Java Native Interface (JNI): gdy kod natywny (C lub C++) wywołuje metodę Java lub Kotlin albo gdy kod Java lub Kotlin wywołuje kod C++ za pomocą JNI, wywołanie jest oparte na dynamicznym wyszukiwaniu nazwy metody. R8 nie widzi wywołania metody opartego na dynamicznym ciągu znaków, dlatego jego optymalizacje mogą spowodować uszkodzenie kodu.
To nie jest wyczerpująca lista scenariuszy, które wymagają reguł zachowywania, ale obejmuje ona większość przypadków, w których mogą być one potrzebne.
Jak dodać reguły zachowywania do aplikacji
Konfiguracja reguł zachowywania zależy od używanej wersji AGP.
Większe aplikacje zwykle mają kod w wielu modułach biblioteki. W takich przypadkach często lepiej jest umieścić reguły zachowywania obok kodu, do którego się odnoszą, w konkretnym module biblioteki. Kluczowa różnica w utrzymywaniu reguł zachowywania w przypadku
bibliotek polega na tym, jak deklarujesz te reguły w pliku modułu biblioteki
build.gradle.kts (lub build.gradle). Więcej informacji znajdziesz w artykule Optymalizacja dla autorów bibliotek.
W przypadku AGP w wersji 9.3 lub nowszej
Dodaj reguły do pliku z sufiksem .keep w katalogu
src/<variant>/keepRules. Na przykład src/main/keepRules/custom-rules.keep. Pamiętaj, że używanie zaktualizowanego DSL w przypadku AGP w wersji 9.3 lub nowszej umożliwia optymalizację kodu i zasobów oraz nie wymaga jawnego zdefiniowania domyślnego pliku reguł zachowywania Androida (proguard-android-optimize.txt), ponieważ jest on domyślnie uwzględniany, chyba że zostanie wyraźnie pominięty.
Kotlin
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
}
Dynamiczny
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
}
Pomijanie domyślnych reguł zachowywania platformy Android (zaawansowane)
AGP udostępnia zestaw domyślnych reguł platformy Android. Aby pominąć te reguły w konfiguracji projektu i samodzielnie zarządzać wszystkimi regułami zachowywania, ustaw optimization.keepRules.includeDefault na false.
Kotlin
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
keepRules {
includeDefault = false // The file with optimization
// rules for the Android platform is included by
// default. To omit this file, set this option to false.
}
}
}
}
}
Dynamiczny
android {
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
keepRules {
includeDefault = false // The file with optimization
// rules for the Android platform is included by
// default. To omit this file, set this option to false.
}
}
}
}
}
Starszy DSL w przypadku AGP w wersji starszej niż 9.3
Dodaj reguły do pliku proguard-rules.pro znajdującego się w katalogu głównym modułu aplikacji. Plik może już tam być, ale jeśli go nie ma, utwórz go. Aby zastosować
reguły w pliku, musisz zadeklarować go w pliku na poziomie modułu
build.gradle.kts (lub build.gradle).
Domyślnie plik 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 pozostawić w pliku kompilacji. Ten plik jest oparty na pliku proguard-common.txt i zawiera
te same treści.
Starszy DSL (Kotlin)
android {
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
// Default file with default optimization rules.
getDefaultProguardFile("proguard-android-optimize.txt"),
...
)
}
}
}
Starszy DSL (Dynamiczny)
android {
buildTypes {
release {
minifyEnabled = true
shrinkResources = true
// Default file with default optimization rules.
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
...
}
}
}
Dodawanie reguły zachowywania
Gdy dodajesz reguły zachowywania, możesz uwzględnić opcje globalne oraz zdefiniować własne reguły zachowywania.
Opcje globalne: opcje globalne to ogólne dyrektywy, które wpływają na sposób działania R8 w całej bazie kodu. Więcej informacji znajdziesz w artykule Opcje globalne.
Reguły zachowywania: reguły zachowywania muszą być starannie zaprojektowane, aby zapewnić odpowiednią równowagę między maksymalizacją optymalizacji kodu a unikaniem przypadkowego uszkodzenia aplikacji. Aby dowiedzieć się, jak pisać reguły zachowywania, przeczytaj artykuł Dodawanie reguł zachowywania.
Reguły zachowywania dla autorów bibliotek
Po zapoznaniu się z opcjami globalnymi i składnią reguł zachowywania przeczytaj artykuł Optymalizacja dla autorów bibliotek, aby uzyskać więcej informacji.