Aby aplikacja była jak najmniejsza i szybka, zoptymalizuj ją i zmniejsz
kompilację do publikacji w isMinifyEnabled = true
.
Spowoduje to zmniejszanie, co skutkuje usunięciem nieużywanego kodu i zasobów. zaciemnianie kodu, które skraca nazwy klas i członków grupy w aplikacji; oraz optymalizację, która stosuje bardziej agresywne strategie, by jeszcze bardziej ograniczyć rozmiar aplikacji i zwiększanie jej wydajności. Na tej stronie opisujemy, jak R8 które pozwalają wykonać te zadania w czasie kompilacji w projekcie i jak dostosować .
Gdy tworzysz projekt za pomocą wtyczka Androida do obsługi Gradle w wersji 3.4.0 lub nowszej, wtyczka nie używa już ProGuard do optymalizacji kodu w czasie kompilowania. Zamiast tego wtyczka współpracuje z kompilatorem R8, aby obsługiwać: zadania w czasie kompilacji:
- Zmniejszanie kodu (lub drżenie drzew): wykrywa i bezpiecznie usuwa nieużywane klasy, pola, metody i atrybuty z aplikacji i jej biblioteki zależności (co jest cennym narzędziem do pracy wokół 64 tys. plików referencyjnych). Na przykład, jeśli używasz tylko kilka interfejsów API zależności biblioteki, zmniejszenie może zidentyfikować kod biblioteki że aplikacja nie używa, i usuń tylko ten kod z aplikacji. Do więcej informacji znajdziesz w sekcji poświęconej zmniejszaniu kodu.
- Zmniejszanie zasobów: usuwa nieużywane zasoby z aplikacji w pakiecie. włącznie z nieużywanymi zasobami w zależnościach biblioteki aplikacji. Działa w w połączeniu z kurczeniem kodu, tak że po usunięciu nieużywanego kodu wszystkie zasoby, do których już się nie odwołują, możesz bezpiecznie usunąć. Aby się uczyć Więcej informacji znajdziesz w sekcji zmniejszyć zasoby.
- Optymalizacja: sprawdza i zmienia kod, aby poprawić czas działania.
i jeszcze bardziej zmniejsz rozmiar plików DEX aplikacji. Ten
poprawia wydajność kodu w czasie działania kodu nawet o 30%, znacząco ulepszając
czas uruchamiania
i czasu renderowania klatek. Jeśli na przykład R8 wykryje, że
else {}
gałąź danej instrukcji if/else nie jest wykonywana, R8 usuwa kod dla gałąźelse {}
. Więcej informacji znajdziesz w sekcji optymalizacji kodu. - Zaciemnianie (lub minifikacja identyfikatora): skraca nazwę klas. i członków grupy, co zmniejsza rozmiar plików DEX. Aby dowiedzieć się więcej, wejdź na sekcji o zaciemnianiu kodu.
Podczas tworzenia wersji produkcyjnej aplikacji R8 można skonfigurować tak, omówionych powyżej zadań kompilacyjnych. Możesz też wyłączyć określone lub dostosować działanie R8 za pomocą plików reguł ProGuard. R8 działa ze wszystkimi istniejącymi plikami reguł ProGuard, zaktualizowanie wtyczki Androida do obsługi Gradle tak, aby używała R8, nie powinno wymagać zmiany istniejących reguł.
Włącz zmniejszanie, zaciemnianie i optymalizację
Jeśli używasz Androida Studio 3.4 lub wtyczki Android do obsługi Gradle w wersji 3.4.0 lub nowszej, R8 jest domyślny kompilator, który konwertuje kod bajtowy Java projektu na format DEX działający na platformie Android. Jednak podczas tworzenia nowego projektu w Android Studio, zmniejszanie, zaciemnianie i optymalizacja kodu nie są domyślnie włączone. To dlatego, że optymalizacje podczas kompilowania zwiększają czas na stworzenie projektu. Mogą też spowodować błędy, jeśli nie będziesz dostosować kod, który chcesz zachować.
Dlatego podczas tworzenia ostatecznej wersji pliku najlepiej jest włączyć te zadania kompilacyjne. którą przetestujesz przed opublikowaniem. Aby włączyć zmniejszanie, zaciemnianie, i optymalizację, umieść w skrypcie kompilacji na poziomie projektu te elementy.
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" ) } } ... }
Odlotowe
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' } } ... }
Pliki konfiguracji R8
R8 używa plików z regułami ProGuard, aby modyfikować domyślne działanie i ulepszać poznawać strukturę aplikacji, np. klasy, które stanowią punkty wejścia; do kodu aplikacji. Chociaż można modyfikować niektóre z tych plików reguł, niektóre mogą być generowane automatycznie przez narzędzia czasu kompilacji, takie jak AAPT2, lub odziedziczone z zależności biblioteki aplikacji. Tabela poniżej zawiera źródeł plików reguł ProGuard, z których korzysta R8.
Źródło | Lokalizacja | Opis |
Android Studio, | <module-dir>/proguard-rules.pro
|
Gdy tworzysz nowy moduł w Android Studio, IDE tworzy plik
proguard-rules.pro w katalogu głównym tego modułu.
Domyślnie ten plik nie stosuje żadnych reguł. Dodaj więc własne Tutaj reguły ProGuard, takie jak niestandardowy zachowaj reguły. |
Wtyczka Androida do obsługi Gradle | Wygenerowany przez wtyczkę Androida do obsługi Gradle podczas kompilowania. | Wtyczka Androida do obsługi Gradle generuje
proguard-android-optimize.txt , która obejmuje reguły
jest przydatny w większości projektów na Androida.
@Keep*
adnotacji.
Domyślnie podczas tworzenia nowego modułu w Android Studio moduł skrypt kompilacji zawiera ten plik reguł w kompilacji do publikacji. dla Ciebie.
Uwaga: wtyczka Androida do obsługi Gradle zawiera dodatkowe wstępnie zdefiniowane proGuard
plików reguł, ale zalecamy
|
Zależności bibliotek |
W bibliotece AAR:
W bibliotece JAR: Oprócz tych lokalizacji wtyczka Androida do obsługi Gradle w wersji 3.6 lub nowszej obsługuje kierowane reguły ograniczania. |
Jeśli biblioteka AAR lub JAR została opublikowana z własnym plikiem reguł i uwzględnić tę bibliotekę jako zależność czasu kompilowania, R8 automatycznie stosuje te reguły podczas kompilowania projektu. Oprócz konwencjonalnych reguł ProGuard wtyczka Androida do obsługi Gradle 3.6 lub nowsza wersja obsługuje też docelowych reguł ograniczania. To są reguły kierowane na konkretne urządzenia kurczące (R8 lub ProGuard) i pomniejszania. Używanie plików reguł spakowanych z bibliotekami jest przydatne, jeśli reguły są wymagane do prawidłowego funkcjonowania biblioteki. podał już instrukcje rozwiązywania problemów. Pamiętaj jednak, że reguły są dodatkowe, nie można usunąć pewnych reguł ujętych w zależności bibliotecznej, może wpłynąć na kompilację innych części aplikacji. Jeśli na przykład plik biblioteka zawiera regułę wyłączania optymalizacji kodu, która wyłącza tę regułę i optymalizacji całego projektu. |
Android Asset Package Tool 2 (AAPT2) | Po utworzeniu projektu w minifyEnabled true :
<module-dir>/build/intermediates/aapt_proguard_file/.../aapt_rules.txt
|
AAPT2 generuje reguły zachowywania na podstawie odwołań do zajęć w aplikacji pliku manifestu, układów i innych zasobów aplikacji. Na przykład AAPT2 zawiera element zachowuj regułę dla każdej aktywności zarejestrowanej w pliku manifestu aplikacji jako i punktu wejścia. |
Niestandardowe pliki konfiguracji | Domyślnie, gdy tworzysz nowy moduł w Android Studio, IDE
tworzy <module-dir>/proguard-rules.pro , aby umożliwić Ci dodanie własnych
reguł.
|
Możesz uwzględnić dodatkowe konfiguracje, a R8 stosuje je podczas kompilowania. |
Jeśli ustawisz właściwość minifyEnabled
na wartość true
, R8 połączy reguły ze wszystkich
z dostępnych źródeł wymienionych powyżej. Należy pamiętać o tym,
rozwiązywać problemy z modelem R8, ponieważ inne zależności czasu kompilowania
takich jak zależności bibliotek, mogą wprowadzić zmiany w działaniu R8,
których nie wiemy.
Aby wygenerować pełny raport ze wszystkimi regułami, których używa R8 podczas tworzenia
projekt, umieść w pliku proguard-rules.pro
modułu te informacje:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
Docelowe reguły ograniczania
Wtyczka Androida do obsługi Gradle w wersji 3.6 lub nowszej obsługuje biblioteki reguły dotyczące kierowania konkretnych reduktorów (R8 lub ProGuard) i konkretnych wersji. Ten umożliwia programistom bibliotekom dostosowanie reguł do optymalnego działania w projektach które korzystają z nowych wersji zmniejszających rozmiar, przy czym umożliwia pozostawienie istniejących reguł używane w projektach ze starszymi wersjami kurczaka.
Aby określić docelowe reguły ograniczania, programiści bibliotek muszą je uwzględnić w określonych lokalizacjach w bibliotece AAR lub JAR, jak opisano poniżej.
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>
Oznacza to, że docelowe reguły ograniczania są przechowywane w: META-INF/com.android.tools
katalogu JAR lub katalogu META-INF/com.android.tools
wewnątrz
classes.jar
ARA.
W tym katalogu może znajdować się wiele katalogów o nazwach w postaci
r8-from-<X>-upto-<Y>
lub proguard-from-<X>-upto-<Y>
, aby wskazać,
dla których są zapisywane reguły wewnątrz katalogów.
Pamiętaj, że części -from-<X>
i -upto-<Y>
są opcjonalne. Wersja <Y>
jest wyłącznie, a zakresy wersji muszą być ciągłe.
np. r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
i r8-from-8.2.0
.
aby utworzyć prawidłowy zestaw docelowych reguł ograniczania. Zasady określone w
Katalog r8-from-8.0.0-upto-8.2.0
będzie używany przez R8 od wersji 8.0.0 do
ale bez wersji 8.2.0.
Biorąc pod uwagę te informacje, wtyczka Androida do obsługi Gradle w wersji 3.6 lub nowszej wybierze
z pasujących katalogów R8. Jeśli biblioteka nie określa kierowania
reguł ograniczania, wtyczka Androida do obsługi Gradle wybierze reguły ze starszej
lokalizacji (proguard.txt
w przypadku AAR lub
META-INF/proguard/<ProGuard-rules-file>
w przypadku pliku JAR).
Programiści bibliotek mogą uwzględnić docelowe reguły ograniczania lub starsze reguły ProGuard w swoich bibliotekach lub oba typy, jeśli chcą zachować zgodność z wtyczką Androida do obsługi Gradle w wersji starszej niż 3.6 lub innymi narzędziami.
Uwzględnij dodatkowe konfiguracje
Gdy tworzysz nowy projekt lub moduł w Android Studio, IDE tworzy plik
<module-dir>/proguard-rules.pro
z własnymi regułami. Ty
może również zawierać dodatkowe reguły z innych plików, dodając je do polecenia
proguardFiles
w skrypcie kompilacji modułu.
Możesz na przykład dodać reguły, które są unikalne dla każdego wariantu kompilacji, dodając
inną właściwość proguardFiles
w odpowiednim bloku productFlavor
.
za to plik Gradle dodaje atrybut flavor2-rules.pro
do rodzaju usług flavor2
.
Teraz flavor2
wykorzystuje wszystkie 3 reguły ProGuard, ponieważ te z zasady release
także zostaną zastosowane.
Możesz też dodać właściwość testProguardFiles
, która określa
lista plików ProGuard, które znajdują się tylko w testowym pakiecie APK:
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") } } }
Odlotowe
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' } } }
Zmniejszanie kodu
Zmniejszanie kodu za pomocą R8 jest domyślnie włączone po ustawieniu minifyEnabled
usłudze na true
.
Zmniejszanie kodu (nazywane też potrząsaniem drzew) to proces usuwania kodu. które według R8 nie są wymagane w czasie działania. Ten proces może znacznie ograniczyć rozmiaru aplikacji, jeśli na przykład aplikacja zawiera wiele zależności bibliotek, wykorzystuje tylko niewielką część swoich funkcji.
Aby skrócić kod aplikacji, R8 najpierw określa wszystkie punkty wejścia aplikacji na podstawie połączonego zestawu plików konfiguracji. Te punkty wejścia obejmują wszystkie klasy, których platforma Android może używać do otwierania Aktywność lub usługi w aplikacji. R8 sprawdza od każdego punktu wejścia kodu aplikacji, by utworzyć wykres wszystkich metod, zmiennych członkowskich i innych klas, do których aplikacja może mieć dostęp w czasie działania. Kod, który nie jest połączony z ten wykres jest uważany za nieosiągalny i można go usunąć z aplikacji.
Rysunek 1 przedstawia aplikację, która jest uzależniona od biblioteki środowiska wykonawczego. Podczas sprawdzania
kodu aplikacji, R8 wskazuje, że metody foo()
, faz()
i bar()
są
jest osiągalny z punktu wejścia MainActivity.class
. Jednak klasa
Aplikacja OkayApi.class
ani jej metoda baz()
nigdy nie są używane przez aplikację w czasie działania oraz
R8 usuwa ten kod po zmniejszeniu aplikacji.
R8 określa punkty wejścia za pomocą reguł -keep
w projekcie
Pliki konfiguracji R8. Oznacza to, że reguły przechowywania określają,
klas, które nie powinny być odrzucane przez R8 przy zmniejszaniu aplikacji, a R8 uwzględnia
jako punkty wejścia do aplikacji. Wtyczka Androida do obsługi Gradle
i AAPT2 automatycznie generują reguły przechowywania, które są wymagane przez większość aplikacji
projekty, takie jak aktywność, widoki czy usługi w aplikacji. Pamiętaj jednak:
Jeśli chcesz dostosować to domyślne działanie przy użyciu dodatkowych reguł zachowywania, przeczytaj
sekcji o tym, jak dostosować kod do zachowania.
Jeśli zamiast tego chcesz zmniejszyć rozmiar zasobów aplikacji, przejdź do sekcji z informacjami o zmniejszaniu zasobów.
Pamiętaj, że po zmniejszeniu projektu biblioteki aplikacja zależna od tej biblioteki obejmuje zmniejszone klasy biblioteki. Może być konieczne dostosowanie reguł przechowywania w bibliotece, w pliku APK biblioteki brakuje klas. Jeśli tworzysz i publikujesz bibliotekę w formacie AAR, lokalne pliki JAR, od których Twoja biblioteka nie jest w pliku AAR.
Wybierz kod, który chcesz zachować
W większości przypadków domyślny plik reguł ProGuard (proguard-android-optimize.txt
)
wystarcza do usunięcia nieużywanego kodu przez R8. Pamiętaj jednak:
R8 może mieć trudności z poprawną analizą i może spowodować,
potrzebne aplikacji. Przykłady sytuacji, w których może zostać niesłusznie usunięte
kod obejmuje:
- Gdy aplikacja wywołuje metodę z interfejsu natywnego Java (JNI)
- Gdy aplikacja wyszukuje kod w czasie działania (np. podczas odbicia)
Testowanie aplikacji powinno wykazać błędy spowodowane niewłaściwym usunięciem. ale możesz też zobaczyć, który kod został usunięty generując raport o usuniętym kodzie.
Aby naprawić błędy i wymusić zachowanie określonego kodu w R8, dodaj
-keep
w pliku reguł ProGuard. Na przykład:
-keep public class MyClass
Możesz też dodać parametr
@Keep
adnotację do kodu,
którą chcesz zachować. Dodanie elementu @Keep
do zajęć powoduje zachowanie całej klasy bez zmian.
Dodanie ich do metody lub pola spowoduje również zachowanie metody/pola (oraz jego nazwy).
. Pamiętaj, że ta adnotacja jest dostępna tylko wtedy, gdy używasz
Biblioteka adnotacji AndroidX
a gdy dołączysz plik z regułami ProGuard, który jest w pakiecie z Androidem
wtyczki Gradle zgodnie z opisem w sekcji o
włącz zmniejszanie.
Korzystając z opcji -keep
, należy wziąć pod uwagę wiele kwestii. w przypadku
więcej informacji o dostosowywaniu pliku reguł znajdziesz w
Instrukcja ProGuard.
Rozwiązywanie problemów
by dowiedzieć się, jakie inne typowe problemy mogą wystąpić po
Usuń biblioteki natywne
Domyślnie biblioteki kodu natywnego są usuwane z kompilacji wersji aplikacji. Obejmuje to usunięcie tabeli symboli i danych debugowania zawarte we wszystkich bibliotekach natywnych używanych przez aplikację. Usuwanie kodu natywnego biblioteki pozwalają znacząco zmniejszyć rozmiar plików. jednak niemożliwe jest zdiagnozowanie awarii w Konsoli Google Play z powodu brakujących informacji (np. nazw klas i funkcji).
Obsługa natywnych awarii
Konsola Google Play zgłasza awarie natywne w kategorii Android Vitals. Kilka możesz wygenerować i przesłać plik symboli do debugowania kodu natywnego aplikacji. Ten plik umożliwia symbolizowane zrzuty stosu awarii (obejmujące klasy i nazwy funkcji) w Android Vitals, aby ułatwić debugowanie aplikacji w wersji produkcyjnej. Te kroki różnią się w zależności od wersji wtyczki Androida do obsługi Gradle używanej w oraz dane wyjściowe kompilacji projektu.
Wtyczka Androida do obsługi Gradle w wersji 4.1 lub nowszej
Jeśli w ramach projektu tworzysz pakiet Android App Bundle, możesz automatycznie dołączyć
pliku symboli do debugowania kodu natywnego. Aby uwzględnić ten plik w kompilacjach wersji, dodaj parametr
do pliku build.gradle.kts
aplikacji:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
Wybierz jeden z tych poziomów symboli debugowania:
- Użyj funkcji
SYMBOL_TABLE
, aby uzyskać nazwy funkcji w symbolicznych zrzutach stosu w Konsoli Play. Ten poziom obsługuje tombstone. - Użyj
FULL
, aby uzyskać nazwy funkcji, pliki i numery wierszy w Konsoli Play symboliczne zrzuty stosu.
Jeśli Twój projekt tworzy plik APK, użyj przedstawionych ustawień kompilacji build.gradle.kts
wcześniej, aby oddzielnie wygenerować plik symboli do debugowania kodu natywnego. ręcznie.
prześlij plik symboli do debugowania kodu natywnego
z Konsolą Google Play. W ramach procesu kompilacji narzędzie Gradle Androida
wtyczka generuje ten plik w następującej lokalizacji projektu:
app/build/outputs/native-debug-symbols/variant-name/native-debug-symbols.zip
Wtyczka Androida do obsługi Gradle w wersji 4.0 lub starszej (i inne systemy kompilacji)
W ramach procesu kompilacji wtyczka Androida do obsługi Gradle przechowuje kopię pliku biblioteki w katalogu projektu. Struktura katalogów jest podobna do tej:
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
Skompresuj zawartość tego katalogu:
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
ręcznie. prześlij plik
symbols.zip
z Konsolą Google Play.
Zmniejszanie zasobów
Zmniejszanie zasobów działa tylko w połączeniu ze zmniejszaniem kodu. Po kurczący kod usuwa cały nieużywany kod, zmniejszający zasoby może zidentyfikować zasobów, których aplikacja wciąż używa. Dotyczy to zwłaszcza dodawania kodu bibliotek, które zawierają zasoby, należy usunąć nieużywany kod biblioteki, zasoby biblioteki stają się nieodwołane, więc zasób z kurczakiem.
Aby włączyć zmniejszanie zasobów, ustaw właściwość shrinkResources
do true
w skrypcie kompilacji (wraz
minifyEnabled
, aby zmniejszyć kod). Na przykład:
Kotlin
android { ... buildTypes { getByName("release") { isShrinkResources = true isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" ) } } }
Odlotowe
android { ... buildTypes { release { shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
Jeśli nie masz jeszcze aplikacji korzystającej z usługi minifyEnabled
zmniejszanie kodu, a potem spróbuj to zrobić przed włączeniem funkcji shrinkResources
,
bo może być konieczne edytowanie pliku proguard-rules.pro
na
zachowuj klasy lub metody, które są tworzone lub wywoływane dynamicznie, zanim
zacznij usuwać zasoby.
Wybierz zasoby, które chcesz zachować
Jeśli chcesz zachować lub odrzucić konkretne zasoby, utwórz plik XML.
w projekcie, używając tagu <resources>
i określ każdy z nich
zasób do zachowania w atrybucie tools:keep
i każdy zasób
odrzuć w atrybucie tools:discard
. Oba atrybuty akceptują
rozdzielana przecinkami lista nazw zasobów. Gwiazdki możesz użyć jako
symbol wieloznaczny.
Na przykład:
<?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" />
Zapisz ten plik w zasobach projektu, na przykład pod adresem
res/raw/my.package.keep.xml
Kompilacja nie spakuje tego pliku w
.
Uwaga: nazwa pliku keep
musi być unikalna. Kiedy
gdy różne biblioteki zostaną połączone, ich reguły przechowywania będą sprzeczne
powodując potencjalne problemy z ignorowanymi regułami lub zachowywane
i zasobami Google Cloud.
Określanie zasobów do odrzucenia może wydawać się głupawe,
zamiast je usuwać, ale może to być przydatne, gdy używasz wariantów kompilacji. Dla:
możesz na przykład umieścić wszystkie zasoby we wspólnym katalogu projektów,
a następnie utwórz osobny plik my.package.build.variant.keep.xml
dla każdego z nich.
wariant kompilacji, gdy wiesz, że dany zasób wydaje się być używany w kodzie
(i nie zostanie usunięta przez usługę zmniejszająca), ale wiesz, że nie zostanie
używany dla danego wariantu kompilacji. Narzędzia do kompilacji
nieprawidłowo zidentyfikował zasób jako potrzebny, co może być spowodowane tym,
kompilator dodaje identyfikatory zasobów w tekście, a analizator zasobów może nie
rozpoznawanie różnicy między prawdziwie przywoływanym zasobem a wartością całkowitą
w kodzie, które ma tę samą wartość.
Włącz rygorystyczne sprawdzanie odwołań
Normalnie narzędzie do obniżania zasobów może dokładnie określić,
i zgody na określone zastosowania ich danych. Jeśli jednak kod nawiązuje połączenie z
Resources.getIdentifier()
(lub jeśli któraś z Twoich bibliotek tak działa, plik AppCompat
), co oznacza, że kod wyszukuje nazwy zasobów na podstawie
dynamicznie generowanych ciągów znaków. Gdy to zrobisz, będzie działać zmniejszanie zasobów
defensywny domyślnie i oznacza wszystkie zasoby z pasującym formatem jako
potencjalnie używanych i niedostępnych do usunięcia.
Na przykład ten kod powoduje, że wszystkie zasoby z atrybutem
Prefiks img_
do oznaczenia jako używany.
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());
Zmniejsza ono też wszystkie stałe łańcuchowe
oraz różne zasoby res/raw/
w poszukiwaniu zasobów
Adresy URL mają format podobny do
file:///android_res/drawable//ic_plus_anim_016.png
Jeśli znajdzie
ciągi takie jak ten lub inne, które wyglądają, jakby można je było wykorzystać do tworzenia adresów URL
nie zostaną usunięte.
Oto przykłady bezpiecznego pomniejszania, który jest domyślnie włączony.
Możesz jednak wyłączyć to ustawienie. i określić
aby narzędzie do ograniczania zasobów zatrzymywało tylko te zasoby, których użycie jest pewne. Do
w tym celu ustaw shrinkMode
na strict
w
keep.xml
w ten sposób:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" />
Jeśli włączysz tryb ścisłego ograniczania, a Twój kod odwołuje się do
z dynamicznie generowanymi ciągami znaków, jak pokazano powyżej, musisz
ręcznie zachować te zasoby za pomocą atrybutu tools:keep
.
Usuń nieużywane zasoby alternatywne
Zmniejszający zasoby Gradle usuwa tylko zasoby, do których się nie odwołuje
przez kod aplikacji, co oznacza, że nie usunie
i zasobów alternatywnych dla różnych konfiguracji urządzeń. W razie potrzeby:
możesz użyć właściwości resConfigs
wtyczki Androida do obsługi Gradle,
usuń pliki zasobów alternatywnych, których aplikacja nie potrzebuje.
Na przykład jeśli używasz biblioteki, która zawiera zasoby językowe
(np. AppCompat lub Usługi Google Play), aplikacja zawiera wszystkie
przetłumaczone ciągi językowe wiadomości w tych bibliotekach, niezależnie od tego,
reszta aplikacji jest przetłumaczona na te same języki lub nie. Jeśli chcesz
zachować tylko języki oficjalnie obsługiwane przez aplikację, możesz określić
we właściwości resConfig
. Wszystkie materiały dla
Usunięto nieokreślone języki.
Z poniższego fragmentu dowiesz się, jak ograniczyć zasoby językowe do Angielski i francuski:
Kotlin
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }
Odlotowe
android { defaultConfig { ... resConfigs "en", "fr" } }
Przy publikowaniu aplikacji w formacie Android App Bundle domyślnie tylko języki skonfigurowane na urządzeniu użytkownika są pobierane podczas instalowania aplikacji. I podobnie, tylko zasoby pasujące do gęstości ekranu urządzenia i natywny biblioteki zgodne z interfejsem ABI urządzenia są uwzględniane w pobieranym pliku. Więcej zapoznaj się z Aplikacja na Androida Konfiguracja pakietu.
W przypadku starszych aplikacji publikowanych z plikami APK (utworzonych przed sierpniem 2021 r.) możesz: dostosować gęstość ekranu lub zasoby ABI, które należy uwzględnić w pliku APK tworzenie wielu plików APK, które są kierowane na inną konfigurację urządzenia.
Scal zduplikowane zasoby
Domyślnie Gradle scala też zasoby o identycznej nazwie, takie jak
obiekty rysowane o tej samej nazwie, które mogą znajdować się w różnych folderach zasobów. Ten
zachowanie nie zależy od właściwości shrinkResources
i
nie można wyłączyć, ponieważ konieczne jest uniknięcie błędów w przypadku wielu
zasobów pasują do nazwy, którą wyszukuje Twój kod.
Scalanie zasobów ma miejsce tylko wtedy, gdy co najmniej 2 pliki są identyczne nazwę, typ i kwalifikator zasobu. Gradle wybiera plik, który bierze pod uwagę być najlepszą opcją (według priorytetu opisanego wg poniżej) i przekazuje tylko ten jeden zasób do AAPT do dystrybucji efekt końcowy.
Gradle szuka zduplikowanych zasobów w tych lokalizacjach:
- Główne zasoby, powiązane z głównym zbiorem źródłowym, zwykle
w lokalizacji:
src/main/res/
. - Nakładki wersji z typu kompilacji i jej smaków.
- Zależności projektu biblioteki.
Gradle scala zduplikowane zasoby w tej kaskadowej kolejności według priorytetu:
Zależności → Główny → Rodzaj kompilacji → Typ kompilacji
Jeśli na przykład zduplikowany zasób pojawia się zarówno w zasobach głównych, rodzaj kompilacji, Gradle wybiera ten z rodzaju kompilacji.
Jeśli identyczne zasoby występują w tym samym zbiorze źródłowym, Gradle nie może scalić
i powoduje wystąpienie błędu scalania zasobów. Może się tak zdarzyć, jeśli zdefiniujesz wiele
zestawy źródeł we właściwości sourceSet
na koncie
build.gradle.kts
– na przykład, jeśli zarówno src/main/res/
,
i src/main/res2/
zawierają identyczne zasoby.
Zaciemnianie kodu
Szyfrowanie ma na celu zmniejszenie rozmiaru aplikacji przez skrócenie nazw klasy, metody i pola aplikacji. Oto przykład: zaciemnianie kodu przy użyciu 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
Zaciemnianie kodu nie usuwa kodu z aplikacji, ale znacznie zmniejsza rozmiar można zobaczyć w aplikacjach z plikami DEX, które indeksują wiele klas, metod i pól. Gdy jednak zaciemnianie kodu zmienia nazwy różnych części kodu, niektóre zadania takich jak sprawdzanie zrzutów stosu, wymagają dodatkowych narzędzi. Aby zrozumieć śledzenia stosu po zaciemnieniu kodu, przeczytaj sekcję o tym, dekodować zaciemniony zrzut stosu.
Dodatkowo, jeśli kod opiera się na przewidywalnych nazwach metod aplikacji i zajęć, na przykład używając refleksji, należy traktować te podpisów jako punktów wejścia i określ dla nich reguły zachowywania, tak jak to opisano w o tym, jak wybrać kod do zachowania. Te funkcje pozwalają zgodnie z regułami R8 nie tylko zachowa kod w ostatecznej wersji DEX aplikacji, jego oryginalnej nazwy.
Dekodowanie zaciemnionego zrzutu stosu
Gdy mechanizm R8 zaciemnia kod, trudno jest zrozumieć zrzut stosu (jeśli nie jest to możliwe), ponieważ nazwy klas i metod mogły zostać została zmieniona. Aby uzyskać oryginalny zrzut stosu, ponownie śledzić zrzut stosu.
Optymalizacja kodu
Aby jeszcze bardziej zoptymalizować aplikację, R8 dokładnie sprawdza kod poziomu konta, aby usunąć więcej nieużywanego kodu. Tam, gdzie to możliwe, przeredagować kod, i mniej szczegółowe. Oto kilka przykładów takich optymalizacji:
- Jeśli Twój kod nigdy nie używa gałęzi
else {}
w danej instrukcji if/else, R8 może usunąć kod gałęzielse {}
. - Jeśli Twój kod wywołuje metodę tylko w kilku miejscach, R8 może ją usunąć i umieścić go w kilku witrynach połączeń.
- Jeśli R8 ustali, że klasa ma tylko jedną niepowtarzalną podklasę, a klasa to sama nie jest utworzona (na przykład abstrakcyjna klasa bazowa używana tylko przez konkretnej klasy implementacji), R8 może połączyć te dwie klasy usunąć je z aplikacji.
- Aby dowiedzieć się więcej, przeczytaj Posty na blogu na temat optymalizacji R8 autorstwa Jake'a Whartona.
R8 nie umożliwia wyłączenia ani włączenia dyskretnych optymalizacji ani modyfikacji
zachowanie optymalizacji. R8 ignoruje wszystkie reguły ProGuard, które próbują
aby modyfikować domyślne optymalizacje, takie jak -optimizations
czy
-optimizationpasses
To ograniczenie jest ważne, ponieważ gdy R8 nie przestaje
tych ulepszeń, utrzymanie standardowego zachowania
w zakresie optymalizacji pomaga
Zespół Studio możesz łatwo rozwiązywać i rozwiązywać napotkane problemy.
Pamiętaj, że włączenie optymalizacji spowoduje zmianę zrzutów stosu dla aplikacji. Na przykład wbudowanie spowoduje usunięcie ramek stosu. Zapoznaj się z sekcją na temat: wycofywać, aby dowiedzieć się, jak uzyskać pierwotne zrzuty stosu.
Wpływ na wydajność środowiska wykonawczego
Jeśli włączone jest zmniejszanie, zaciemnianie i optymalizacja, R8 poprawi wydajność kodu w czasie działania (w tym czas uruchamiania i klatek w wątku UI) o 30%. Wyłączenie dowolnej z tych opcji znacznie ogranicza zestaw optymalizacji Zastosowania R8.
Jeśli włączona jest funkcja R8, należy też tworzenie profili startowych, co pozwoli Ci uzyskiwać jeszcze lepsze wyniki w przypadku startupów.
Włącz bardziej agresywne optymalizacje
R8 zawiera zestaw dodatkowych optymalizacji (nazywanych „trybem całego ruchu”), które sprawia, że działa inaczej niż ProGuard. Te optymalizacje są włączone przez domyślnie od Wtyczka Androida do obsługi Gradle w wersji 8.0.0.
Możesz wyłączyć te dodatkowe optymalizacje, uwzględniając w sekcji
plik gradle.properties
Twojego projektu:
android.enableR8.fullMode=false
Ze względu na dodatkowe optymalizacje R8 działa inaczej niż ProGuard, może wymagać dodania dodatkowych reguł ProGuard, aby uniknąć czasu działania jeśli używasz reguł przeznaczonych dla ProGuard. Na przykład załóżmy, że Twój odwołuje się do klasy za pomocą interfejsu Java Reflection API. Gdy nie używasz „tryb całego ruchu”, R8 zakłada, że zamierzasz badać obiekty i manipulować nimi w momencie działania tej klasy – nawet jeśli Twój kod faktycznie tego nie robi – i automatycznie zachowuje klasę i jej inicjator statyczny.
Jednak w „trybie całego ruchu” R8 nie zakłada tego założenia, a w przypadku R8 twierdzi, że w przeciwnym razie kod nigdy nie używa klasy w czasie działania, usuwa z końcowej wersji pliku DEX aplikacji. Oznacza to, że jeśli chcesz zachować zajęcia i swoje inicjator statyczny, musisz uwzględnić regułę zachowywania w pliku reguł że.
W razie problemów podczas korzystania z „trybu pełnego” R8 zapoznaj się z R8 – strona z najczęstszymi pytaniami . Jeśli nie możesz rozwiązać problemu, zgłoś błąd.
Wycofuję zrzuty stosu
Kod przetwarzany przez R8 jest zmieniany na różne sposoby, co może powodować zrzuty stosu trudniejsze do zrozumienia, ponieważ zrzuty stosu nie będą dokładnie odpowiadać kodowi źródłowemu. Ten może dotyczyć zmian w numerach wierszy, jeśli informacje debugowania nie zachowywano. Może to być spowodowane optymalizowaniem, takim jak wstęp i konspekt. co jest największym czynnikiem zaciemniania kodu, ponieważ nawet klasy i metody zmieniać nazwy.
Aby przywrócić pierwotny zrzut stosu, R8 udostępnia funkcje narzędzia wiersza poleceń retrace, które jest w pakiecie z pakietem narzędzi wiersza poleceń.
Aby umożliwić cofanie zrzutów stosu aplikacji, upewnij się,
zachowuje wystarczającą ilość informacji do ponownego użycia, dodając
do pliku proguard-rules.pro
modułu:
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
Atrybut LineNumberTable
zachowuje informacje o pozycji
w metodach, które umożliwiają wydrukowanie tych pozycji w zrzutach stosu. Atrybut SourceFile
daje pewność, że we wszystkich potencjalnych środowiskach wykonawczych wydrukowane są informacje o pozycji.
Dyrektywa -renamesourcefileattribute
ustawia nazwę pliku źródłowego w stosie
ślady tylko do SourceFile
. Rzeczywista nazwa oryginalnego pliku źródłowego nie jest
wymagane przy wycofywaniu, ponieważ plik mapowania zawiera oryginalny plik źródłowy.
Przy każdym uruchomieniu R8 tworzy plik mapping.txt
, który
zawiera informacje potrzebne do zmapowania zrzutów stosu z powrotem do oryginału
zrzuty stosu. Android Studio zapisze plik w
<module-name>/build/outputs/mapping/<build-type>/
katalogu.
Podczas publikowania aplikacji w Google Play możesz przesłać plik mapping.txt
dla każdej wersji aplikacji. W przypadku publikowania za pomocą pakietów Android App Bundle
jest automatycznie dołączany do treści pakietu aplikacji. Następnie Google
Google Play będzie ponownie śledzić przychodzące zrzuty stosu w przypadku problemów zgłoszonych przez użytkowników,
możesz je sprawdzić w Konsoli Play. Więcej informacji znajdziesz w Centrum pomocy
artykuł o tym,
usuwać zaciemnienie kodu w zrzucie stosu awarii.
Rozwiązywanie problemów przy użyciu R8
W tej sekcji omawiamy strategie rozwiązywania problemów z kurczenia, zaciemniania i optymalizacji przy użyciu R8. Jeśli nie znajdziesz rozwiązania zapoznaj się z poniższymi informacjami R8 – strona z najczęstszymi pytaniami oraz Przewodnik rozwiązywania problemów ProGuard.
Generowanie raportu o usuniętym (lub zachowanym) kodzie
Aby pomóc w rozwiązaniu niektórych problemów z R8, warto wyświetlić raport
cały kod usunięty z aplikacji przez R8. Dla każdego modułu, który ma być
aby wygenerować ten raport, dodaj -printusage <output-dir>/usage.txt
do listy niestandardowej
z regułami. Gdy włączysz R8 i stworzysz aplikację, R8 wygeneruje błąd
raportu o określonej ścieżce i nazwie pliku. Zgłoszenie usuniętego kodu
wygląda podobnie do tego:
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
...
Jeśli zamiast tego chcesz zobaczyć raport punktów wejścia określany przez R8
przestrzegaj reguł przechowywania w swoim projekcie , uwzględnij -printseeds <output-dir>/seeds.txt
w
. Gdy włączysz R8 i stworzysz aplikację, R8 wygeneruje
raport o podanej ścieżce i nazwie pliku. Raport dotyczący zachowanych wpisów
punktów wygląda podobnie do tego:
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
...
Rozwiązywanie problemów ze zmniejszaniem zasobów
Gdy zmniejszasz zasoby, kompilacja pokazuje podsumowanie zasobów usuniętych z aplikacji. (Najpierw kliknij Przełącz widok, po lewej stronie okna, aby wyświetlić szczegółowy tekst wygenerowany przez Gradle). Na przykład:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
Gradle tworzy też też plik diagnostyczny o nazwie resources.txt
w
<module-name>/build/outputs/mapping/release/
(ten sam
jako pliki wyjściowe ProGuard). Plik zawiera m.in. informacje o tym,
zasoby odwołują się do innych zasobów i wskazują, które zasoby są używane
usunięto.
Aby na przykład dowiedzieć się, dlaczego @drawable/ic_plus_anim_016
to
wciąż w aplikacji, otwórz plik resources.txt
i wyszukaj go
nazwę pliku. Możesz zauważyć, że odwołuje się do niego inny zasób,
następujące:
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
Już wiesz, dlaczego @drawable/add_schedule_fab_icon_anim
jest osiągalny. Jeśli wyszukasz w górę, zobaczysz, że zasób jest wymieniony
w sekcji „Osiągalne zasoby główne to:”. Oznacza to, że istnieje odwołanie do kodu
do add_schedule_fab_icon_anim
(czyli jego identyfikator R.drawable to
w osiągniętym kodzie).
Jeśli nie używasz ścisłego sprawdzania, identyfikatory zasobów mogą być oznaczane jako osiągalne jeśli istnieją stałe ciągi znaków, które wyglądają, jakby można je było wykorzystać do nazwy zasobów ładowanych dynamicznie. W takim przypadku, jeśli wyszukasz w wynikach kompilacji dla nazwy zasobu możesz zobaczyć taki komunikat:
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.
Jeśli widzisz jeden z tych ciągów i masz pewność, że nie jest to
jest używany do dynamicznego wczytywania danego zasobu, możesz użyć funkcji
tools:discard
, aby poinformować system kompilacji o jego usunięciu,
Jak opisano w sekcji dotyczącej dostosowywania zasobów do zachowania.