Włączanie optymalizacji aplikacji za pomocą R8

Aby zapewnić użytkownikom jak najlepsze wrażenia, zoptymalizuj aplikację, aby była jak najmniejsza i jak najszybsza. Nasz optymalizator aplikacji, R8, usprawnia aplikację, usuwając nieużywany kod i zasoby, przepisując kod w celu optymalizacji wydajności środowiska wykonawczego i nie tylko. Dla użytkowników oznacza to:

  • szybsze uruchamianie aplikacji,
  • ograniczenie wykorzystania pamięci,
  • lepsze renderowanie i wydajność środowiska wykonawczego,
  • mniej błędów ANR.

Omówienie optymalizacji R8

R8 używa procesu wieloetapowego, aby zoptymalizować aplikację pod kątem rozmiaru i szybkości. Najważniejsze operacje:

  • Zmniejszanie kodu (nazywane też tree shaking): R8 identyfikuje i usuwa nieosiągalny kod z aplikacji i jej zależności bibliotecznych. Analizując punkty wejścia aplikacji (takie jak Activities czy Services zdefiniowane w manifeście), R8 tworzy graf odwołań do kodu i usuwa wszystko, do czego nie ma odwołań.

  • Optymalizacje logiczne: R8 przepisuje kod, aby zwiększyć wydajność wykonywania i zmniejszyć obciążenie. Najważniejsze techniki:

    • Wstawianie metod: R8 zastępuje miejsce wywołania metody rzeczywistą treścią wywoływanej metody. Eliminuje to obciążenie związane z wywołaniem funkcji i umożliwia R8 przeprowadzanie dalszych optymalizacji.

    • Scalanie klas: R8 łączy zestawy klas i interfejsów w jedną klasę. Zmniejsza to liczbę klas w aplikacji, co zmniejsza obciążenie pamięci i zwiększa szybkość uruchamiania.

  • Zaciemnianie kodu (nazywane też minifikacją): aby zmniejszyć rozmiar pliku DEX , R8 skraca nazwy klas, pól i metod (np. com.example.MyActivity może stać się a.b.a).

Od wersji 8.12.0 wtyczki Androida do obsługi Gradle (AGP) R8 optymalizuje też zasoby w ramach etapów optymalizacji. Więcej informacji znajdziesz w artykule Zoptymalizowane zmniejszanie zasobów.

Włączanie optymalizacji

Aby włączyć optymalizację aplikacji, użyj odpowiedniego DSL na podstawie wersji AGP projektu. Zalecamy włączanie optymalizacji aplikacji tylko w ostatecznej wersji aplikacji, którą testujesz przed opublikowaniem – zwykle w kompilacji do publikacji – ponieważ optymalizacje zwiększają czas kompilacji projektu i mogą utrudniać debugowanie ze względu na sposób modyfikowania kodu.

W przypadku AGP w wersji 9.3 lub nowszej

Aby włączyć optymalizację aplikacji w AGP w wersji 9.3 lub nowszej:

  • Ustaw enable = true w bloku optimization w skrypcie kompilacji na poziomie aplikacji w kompilacji do publikacji.
  • Dodaj reguły zachowywania do pliku z sufiksem .keep w src/<variant>/keepRules zestawie źródeł. Na przykład src/main/keepRules/custom-rules.keep.

Kotlin

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
            }
        }
    }
}

Dynamiczny

android {
    buildTypes {
        release {
            optimization {
                enable = true // Enables code and resource optimizations.
            }
        }
    }
}

Starszy DSL w przypadku AGP w wersji starszej niż 9.3

Aby włączyć optymalizację aplikacji, ustaw isMinifyEnabled = true (w przypadku optymalizacji kodu) i isShrinkResources = true (w przypadku optymalizacji zasobów) w skrypcie kompilacji na poziomie aplikacji w kompilacji do publikacji build's. Zalecamy, aby zawsze włączać oba ustawienia.

Starszy DSL (Kotlin)

android {
    buildTypes {
        release {

            // Enables code optimizations.
            isMinifyEnabled = true

            // Enables resource shrinking.
            isShrinkResources = true

            proguardFiles(
                // Default file with automatically generated optimization rules.
                getDefaultProguardFile("proguard-android-optimize.txt"),

                ...
            )
            ...
        }
    }
    ...
}

Starszy DSL (Groovy)

android {
    buildTypes {
        release {

            // Enables code optimizations.
            minifyEnabled = true

            // Enables resource shrinking.
            shrinkResources = true

            // Default file with automatically generated optimization rules.
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')

            ...
        }
    }
}

Ulepszanie optymalizacji R8

Korzyści z wydajności R8 są bezpośrednio związane z tym, jak dużą część bazy kodu R8 może zoptymalizować. Aby w pełni wykorzystać możliwości R8, stosuj te sprawdzone metody:

Aby doprecyzować reguły zachowywania, użyj analizatora konfiguracji R8.

Analizator konfiguracji R8 umożliwia:

  • śledzenie i poprawianie ogólnej jakości konfiguracji R8 przez monitorowanie danych podanych w raporcie analizatora konfiguracji R8;
  • znajdowanie najszerszych reguł zachowywania, które uniemożliwiają największą optymalizację;
  • poznawanie, jakiej optymalizacji zapobiegają, aby je doprecyzować.

Analizator konfiguracji R8 jest dostępny w AGP w wersji 9.3.0-alpha05 lub w R8 w wersji 9.3.7-dev. Więcej informacji znajdziesz w artykule Analizowanie konfiguracji R8.

Optymalizowanie zmniejszania zasobów, aby aplikacje były jeszcze mniejsze

Wersja 8.12.0 AGP wprowadza zoptymalizowane zmniejszanie zasobów, które ma na celu zintegrowanie optymalizacji zasobów i kodu, aby tworzyć jeszcze mniejsze i szybsze aplikacje. Przed zoptymalizowanym zmniejszaniem zasobów narzędzie Android Asset Packaging Tool (AAPT2) generowało reguły zachowywania, które skutecznie traktowały zmniejszanie zasobów oddzielnie od kodu, często zachowując niedostępny kod lub zasoby, które się wzajemnie odwoływały.

W przypadku zoptymalizowanego zmniejszania zasobów zasoby są traktowane jako część kodu programu, tworząc graf odwołań. Gdy do zbioru kodu lub zasobów nie ma odwołań, nie jest on chroniony przez regułę zachowywania i można go usunąć.

Włączanie zoptymalizowanego zmniejszania zasobów

Aby włączyć nowy potok zoptymalizowanego zmniejszania zasobów w AGP w wersji 8.12 lub 8.13, dodaj do pliku gradle.properties projektu te informacje:

android.r8.optimizedResourceShrinking=true

Jeśli używasz AGP w wersji 9.0.0 lub nowszej, nie musisz ustawiać android.r8.optimizedResourceShrinking=true. Zoptymalizowane zmniejszanie zasobów jest stosowane automatycznie, gdy w konfiguracji kompilacji włączysz isShrinkResources = true.

Sprawdzanie i konfigurowanie ustawień optymalizacji R8

Aby umożliwić R8 korzystanie z pełnych możliwości optymalizacji, usuń z pliku gradle.properties projektu ten wiersz, jeśli istnieje:

android.enableR8.fullMode=false

Pamiętaj, że włączenie optymalizacji aplikacji utrudnia zrozumienie śladów stosu, zwłaszcza jeśli R8 zmienia nazwy klas lub metod. Aby uzyskać ślady stosu, które prawidłowo odpowiadają kodowi źródłowemu, przeczytaj artykuł Przywracanie oryginalnego śladu stosu.

Jeśli R8 jest włączony, warto też utworzyć profile uruchamiania, aby jeszcze bardziej zwiększyć wydajność uruchamiania.

Jeśli włączenie optymalizacji aplikacji powoduje błędy, możesz je naprawić, stosując te strategie:

Jeśli chcesz zoptymalizować szybkość kompilacji, przeczytaj artykuł Konfigurowanie sposobu działania R8 runs, aby dowiedzieć się, jak skonfigurować R8 na podstawie środowiska.

Zmiany w działaniu AGP i R8

W tabeli poniżej znajdziesz najważniejsze funkcje wprowadzone w różnych wersjach wtyczki Androida do obsługi Gradle (AGP) i kompilatora R8.

Wersja AGP Wprowadzone funkcje
9.3 Uproszczony DSL:Nowy blok `optimization {}` wymaga mniej konfiguracji – zoptymalizowane zmniejszanie zasobów jest zawsze włączone, a domyślne reguły zachowywania Androida są opcjonalne.

Zestaw źródeł`keepRules`: jeśli używasz nowego DSL, musisz umieścić reguły zachowywania w zestawie źródeł src/<variant>/keepRules w plikach z sufiksem .keep. Zestawy źródeł są też zgodne ze starszym DSL.

Reguły konsumenta KMP (Kotlin MultiPlatform): KMP nie wymaga już ustawiania publish = true i obsługuje zestaw źródeł src/<variant>/keepRules z rozszerzeniem .keep.

Pamiętaj, że starszy DSL jest nadal obsługiwany.
9.1 Domyślnie przepakowane klasy: R8 przepakowuje klasy (przenosząc je do nienazwanego pakietu na najwyższym poziomie), aby jeszcze bardziej skompaktować DEX, eliminując konieczność określania opcji -repackageclasses. Informacje o tym, jak to działa i jak zrezygnować, znajdziesz w sekcji Opcje globalne.
9.0 Zoptymalizowane zmniejszanie zasobów: domyślnie włączone (kontrolowane za pomocą android.r8.optimizedResourceShrinking). Zoptymalizowane zmniejszanie zasobów pomaga zintegrować zmniejszanie zasobów z potokiem optymalizacji kodu, co prowadzi do mniejszych i szybszych aplikacji. Optymalizując jednocześnie odwołania do kodu i zasobów, identyfikuje i usuwa zasoby, do których odwołuje się wyłącznie nieużywany kod. Jest to znaczne ulepszenie w stosunku do poprzednich oddzielnych procesów optymalizacji.

Jest to szczególnie przydatne w przypadku aplikacji, które udostępniają znaczne zasoby i kod na różnych platformach, z mierzalnymi ulepszeniami o ponad 50% w rozmiarze aplikacji. Wynikające z tego zmniejszenie rozmiaru prowadzi do mniejszych plików do pobrania, szybszych instalacji i lepszych wrażeń użytkowników dzięki szybszemu uruchamianiu, lepszemu renderowaniu i mniejszej liczbie błędów ANR.

Filtrowanie reguł biblioteki: obsługa opcji globalnych (np. -dontobfuscate) w regułach konsumenta biblioteki została wycofana, a aplikacje będą je odfiltrowywać. Więcej informacji znajdziesz w artykule Dodawanie opcji globalnych.

Sprawdzanie wartości null w Kotlinie: domyślnie zoptymalizowane (kontrolowane za pomocą -processkotlinnullchecks). Ta wersja wprowadziła też znaczne ulepszenia w szybkości kompilacji. Więcej informacji znajdziesz w artykule Opcje globalne dotyczące dodatkowej optymalizacji.

Optymalizowanie określonych pakietów: możesz użyć packageScope, aby zoptymalizować określone pakiety. Jest to funkcja eksperymentalna. Więcej informacji znajdziesz w artykule Optymalizowanie określonych pakietów za pomocą packageScope.

Domyślnie zoptymalizowane: obsługa getDefaultProguardFile("proguard-android.txt") została wycofana, ponieważ zawiera ona -dontoptimize, którego należy unikać. Zamiast tego użyj "proguard-android-optimize.txt". Jeśli musisz globalnie wyłączyć optymalizację w aplikacji, dodaj flagę ręcznie do pliku ProGuard.
8.12 Zoptymalizowane zmniejszanie zasobów: dodano wstępną obsługę (kontrolowaną za pomocą android.r8.optimizedResourceShrinking). Zoptymalizowane zmniejszanie zasobów pomaga zintegrować zmniejszanie zasobów z potokiem optymalizacji kodu. W tej wersji AGP musisz włączyć tę funkcję ręcznie.

Śledzenie w Logcat: obsługa automatycznego śledzenia w oknie Logcat w Android Studio.
8.6 Ulepszone śledzenie: domyślnie obejmuje śledzenie nazwy pliku i numeru wiersza na wszystkich poziomach minSdk (wcześniej w wersji 8.2 wymagany był minSdk 26+).

Aktualizacja R8 pomaga zapewnić, że ślady stosu z zaciemnionych kompilacji są łatwo i wyraźnie czytelne. Ta wersja poprawia sposób mapowania numerów wierszy i plików źródłowych, co ułatwia narzędziom takim jak Logcat w Android Studio automatyczne śledzenie awarii do oryginalnego kodu źródłowego.
8.0 Domyślnie włączony tryb pełny: tryb pełny R8 zapewnia znacznie większe możliwości optymalizacji. Jest domyślnie włączony. Możesz zrezygnować, używając android.enableR8.fullMode=false.
7.0 Dostępny tryb pełny: wprowadzony jako funkcja opcjonalna za pomocą android.enableR8.fullMode=true. Tryb pełny stosuje bardziej zaawansowane optymalizacje, przyjmując bardziej rygorystyczne założenia dotyczące sposobu, w jaki kod używa odbicia i innych funkcji dynamicznych. Zmniejsza rozmiar aplikacji i zwiększa wydajność, ale może wymagać dodatkowych reguł zachowywania, aby zapobiec usuwaniu niezbędnego kodu.

Używanie R8 z innymi systemami kompilacji

AGP jest zalecanym i oficjalnie obsługiwanym systemem kompilacji aplikacji na Androida , ale możesz używać alternatywnego systemu kompilacji, takiego jak Bazel. Jeśli używasz Bazela, możesz zintegrować R8 z potokiem kompilacji, aby zmniejszać, zaciemniać i optymalizować aplikację.

Informacje o optymalizowaniu aplikacji na Androida za pomocą Bazela znajdziesz w dokumentacji rules_android Bazela. Pamiętaj, że Bazel nie jest oficjalnie obsługiwany w przypadku tworzenia aplikacji na Androida.