Domyślnie R8 wprowadza wiele optymalizacji, aby poprawić wydajność i zmniejszyć rozmiar aplikacji, ale optymalizacje mogą nie działać od razu. Jeśli po raz pierwszy włączasz R8 (lub włączasz tryb pełny) w dużej aplikacji, spróbuj wprowadzać optymalizacje stopniowo: tymczasowo wyłącz zaciemnianie kodu i włącz R8 dla części kodu, a nie dla całego kodu w swojej aplikacji. Zalecamy stosowanie tego podejścia podczas lokalnego programowania, ale możesz też używać go podczas wewnętrznych testów jakości lub nawet w środowisku produkcyjnym jako stopniowe wdrażanie. Dokładne kroki zależą od pożądanego harmonogramu i pewności co do zakresu testów przedpremierowych.
Ogranicz optymalizacje
R8 wprowadza wiele rodzajów optymalizacji, w tym usuwanie kodu, przepisywanie kodu i usuwanie zasobów. Oto ogólne opisy typów optymalizacji:
- Zmniejszanie rozmiaru kodu (lub usuwanie nieużywanego kodu): usuwa kod, do którego nie ma odwołań.
- Zaciemnianie kodu (lub minimalizacja identyfikatorów): skraca nazwy klas i metod.
- Optymalizacja: przepisuje kod, np. wstawiając metody.
Aby zmniejszyć ryzyko wystąpienia błędów, możesz zacząć od włączenia tylko niektórych z tych optymalizacji.
Włącz tylko usuwanie nieużywanego kodu
Zmniejszanie rozmiaru kodu, znane też jako usuwanie nieużywanego kodu, usuwa kod, do którego nie ma odwołań. Zalecamy rozpoczęcie od usuwania nieużywanego kodu, ponieważ jest to najprostsze rozwiązanie.
Aby włączyć tylko usuwanie nieużywanego kodu, dodaj do pliku proguard-rules.pro te ustawienia, aby wyłączyć inne typy optymalizacji. Wyłączenie zaciemniania kodu jest kluczowe, ponieważ znacznie ułatwia odczytywanie zrzutów stosu.
-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization
Nie zalecamy stosowania tej konfiguracji w ostatecznej wersji aplikacji, ponieważ drastycznie ogranicza ona możliwość optymalizacji kodu przez R8, ale jest to dobry punkt wyjścia, gdy po raz pierwszy wdrażasz R8 w dużej bazie kodu z problemami do rozwiązania.
Użyj trybu zgodności
Domyślnie R8 działa w trybie pełnym. Tryb pełny zapewnia znacznie lepszą wydajność i oszczędność miejsca, ale możesz go tymczasowo wyłączyć i zamiast niego użyć trybu zgodności , gdy po raz pierwszy włączasz minimalizację.
Aby użyć trybu zgodności, zastosuj to ustawienie w pliku gradle.properties:
android.enableR8.fullMode = false // Use temporarily to disable full mode
Włącz pozostałe optymalizacje
Gdy potwierdzisz, że usuwanie nieużywanego kodu działa w Twojej aplikacji, możesz usunąć poprzednie ustawienia, aby ponownie włączyć zaciemnianie kodu, optymalizację i tryb pełny R8. Pamiętaj, że zaciemnianie kodu może utrudniać debugowanie, dlatego zalecamy najpierw rozwiązanie problemów z usuwaniem nieużywanego kodu.
Więcej informacji o usuwaniu zaciemnienia kodu ze zrzutów stosu znajdziesz w artykule Przywracanie oryginalnego zrzutu stosu.
Ogranicz zakres optymalizacji
W pełni zoptymalizowana kompilacja optymalizuje cały kod we wszystkich bibliotekach i pakietach, dlatego po pierwszym włączeniu R8 często występują problemy. Jeśli znajdziesz problem z optymalizacją w jednej części aplikacji, nie wyłączaj R8 całkowicie, ponieważ stracisz korzyści w pozostałych częściach. Zamiast tego tymczasowo wyłącz R8 tylko w tych częściach aplikacji, które powodują problemy.
Użyj reguł zachowywania dla całego pakietu
Zalecamy używanie reguł zachowywania dla całego pakietu jako sposobu na tymczasowe wyłączenie R8 w częściach aplikacji. Później należy wrócić do tych problemów z optymalizacją i je rozwiązać. Jest to zwykle rozwiązanie tymczasowe, które pozwala obejść problematyczne obszary.
Jeśli np. część aplikacji intensywnie korzysta z Gson i powoduje problemy z
optymalizacją, idealnym rozwiązaniem jest dodanie bardziej
ukierunkowanych reguł zachowywania lub przejście na rozwiązanie do generowania kodu. Aby jednak odblokować optymalizację pozostałej części aplikacji, możesz umieścić kod definiujący typy Gson w dedykowanym podpakiecie i dodać do pliku proguard-rules.pro regułę taką jak ta:
-keep class com.myapp.json.** { *; }
Jeśli używana biblioteka korzysta z refleksji w komponentach wewnętrznych, możesz podobnie dodać regułę zachowywania dla całej biblioteki. Aby znaleźć odpowiedni pakiet do zachowania, musisz sprawdzić kod biblioteki lub plik JAR/AAR. Ponownie, nie zalecamy tego rozwiązania na dłuższą metę, ale może ono odblokować optymalizację pozostałej części aplikacji:
-keep class com.somelibrary.** { *; }
Usuń reguły zachowywania dla całego pakietu
Gdy aplikacja będzie działać prawidłowo z regułami zachowywania dla całego pakietu, wróć do niej i dodaj ukierunkowane reguły zachowywania lub usuń użycie refleksji albo bibliotekę, która wymaga reguły zachowywania.
Na przykład w AndroidX bardzo często zachowuje się wszystkie reguły, które rozszerzają określoną klasę, aby zachować tylko odpowiednie klasy. Zwykle refleksja powinna być kierowana tylko na klasy lub metody, które rozszerzają określone klasy abstrakcyjne, implementują określone interfejsy lub na klasy z określoną adnotacją czasu wykonywania. Każdy z tych sposobów umożliwia zdefiniowanie reguł zachowywania, dzięki czemu w ostatecznej, w pełni zoptymalizowanej aplikacji nie musisz używać reguł zachowywania dla całego pakietu.
Jeśli refleksja występuje w Twojej bazie kodu, możesz zastąpić reguły zachowywania dla całego pakietu regułami Jetpack Keep. Wygenerowane reguły są warunkowe: R8 zachowuje cel wywołania refleksyjnego tylko wtedy, gdy zachowuje też kod, który wywołuje. Aby przeprowadzić migrację pakietu, użyj kontroli lintera Jetpack Keep, aby znaleźć i dodać adnotacje do wywołań refleksyjnych, a następnie usuń regułę dla całego pakietu.