Jeśli Twoja aplikacja ma interfejs minSdk
API o wartości 20 lub starszej, a aplikacja oraz
do ponad 65 536 metod,występuje ten błąd kompilacji,
wskazuje, że aplikacja osiągnęła limit architektury kompilacji Androida:
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.
Starsze wersje systemu kompilacji zgłaszają inny błąd, co wskazuje na ten sam problem:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
W przypadku tych warunków błędu wyświetlana jest wspólna liczba: 65536. Ten numer to łączna liczba plików referencyjnych, które można przesłać wywoływana przez kod w pojedynczym pliku bajtowym Dalvik Executable (DEX). Z tego artykułu dowiesz się, jak obejść to ograniczenie przez włącz konfigurację aplikacji o nazwie multidex, która umożliwia w celu tworzenia i odczytywania wielu plików DEX.
Informacje o limicie 64 tys. plików referencyjnych
Pliki aplikacji na Androida (APK) zawierają wykonywalne pliki z kodem bajtowym w formacie z Dalvik Pliki wykonywalne (DEX) zawierające skompilowany kod służący do uruchamiania aplikacji. Specyfikacja pliku wykonywalnego Dalvik ogranicza łączną liczbę metod, które są mogą być odwoływane w pojedynczym pliku DEX do 65 536,w tym na urządzeniach z Androidem metod platformy, metod biblioteki i metod w Twoim kodzie.
W w kontekście informatyki, termin kilo lub K oznacza 1024 (lub 2^10). Ponieważ 65 536 to 64 x 1024, limit ten jest nazywany _64 tys. plików referencyjnych.Obsługa Multidex w wersjach starszych niż Android 5.0.
Wersje platformy starsze niż Android 5.0 (poziom interfejsu API 21) używają interfejsu Dalvik.
w środowisku wykonawczym do wykonywania kodu aplikacji. Domyślnie Dalvik ogranicza aplikacje do jednej
classes.dex
plik z kodem bajtowym na pakiet APK. Aby obejść ten problem,
dodaj bibliotekę Multidex do build.gradle
na poziomie modułu lub
build.gradle.kts
plik:
Odlotowe
dependencies { def multidex_version = "2.0.1" implementation "androidx.multidex:multidex:$multidex_version" }
Kotlin
dependencies { val multidex_version = "2.0.1" implementation("androidx.multidex:multidex:$multidex_version") }
Ta biblioteka staje się częścią głównego pliku DEX aplikacji, zarządza dostępem do dodatkowych plików DEX i zawartego w nich kodu. Aby wyświetlić bieżące wersje tej biblioteki, zobacz w wersji multidex.
Więcej informacji znajdziesz w sekcji dotyczącej skonfigurować aplikację pod kątem obsługi środowiska Multidex.Obsługa Multidex na Androidzie 5.0 i nowszych
Android 5.0 (poziom interfejsu API 21) i nowsze używają środowiska wykonawczego ART, które
natywnie obsługuje wczytywanie wielu plików DEX z plików APK. Sztuka
przeprowadza wstępną kompilację w momencie instalowania aplikacji, skanując
classesN.dex
pliki i skompilowanie ich w jeden
Plik OAT dla
przez urządzenie z Androidem. Dlatego, jeśli minSdkVersion
ma wartość 21 lub nowszą, format Multidex jest włączony domyślnie i nie potrzebujesz biblioteki Multidex.
Więcej informacji o Androidzie 5.0 przeczytaj artykuły Środowisko wykonawcze Android (ART) i Dalvik.
Uwaga: jeśli używasz Androida Studio, kompilacja jest zoptymalizowana pod kątem urządzeń docelowych, na których wdrażasz wdrożenie. Obejmuje to włączenie Multidex, gdy uruchomione są urządzenia docelowe Androida 5.0 lub nowszego, Ponieważ optymalizacja jest stosowana tylko podczas wdrażania aplikacji za pomocą w Android Studio, konieczne może być skonfigurowanie kompilacji wersji. dla multidex, aby uniknąć limitu 64 KB.
Unikaj limitu 64 tys.
Zanim skonfigurujesz aplikację, aby umożliwić korzystanie z odwołań do metod co najmniej 64 tys., wykonaj odpowiednie czynności , aby zmniejszyć łączną liczbę odwołań wywoływanych przez kod aplikacji, w tym metod zdefiniowanych przez do kodu aplikacji lub dołączonych bibliotek.
Poniższe strategie pomogą Ci uniknąć osiągnięcia limitu plików referencyjnych DEX:
- Sprawdzanie zależności bezpośrednich i przechodnich aplikacji
- Zastanów się, czy wartość dowolnej dużej zależności biblioteki uwzględnionej w aplikacji przewyższa ilość kodu dodawania do aplikacji. Częstym, ale problematycznym wzorcem jest uwzględnianie bardzo dużej biblioteki. bo kilka metod użytkowych było przydatnych. Zmniejszenie zależności kodu aplikacji często pomaga uniknąć limitu plików DEX.
- Usuń nieużywany kod za pomocą R8
- Włącz zmniejszanie kodu, by uruchomić R8 dla kompilacji wersji. Włącz zmniejszanie, aby zapewnić nie są wysyłane nieużywany kod wraz z plikami APK. Jeśli kompresowanie kodu jest skonfigurowane prawidłowo, może też usunąć z zależności nieużywany kod i zasoby.
Korzystając z tych technik, możesz zmniejszyć ogólny rozmiar pliku APK i uniknąć konieczności korzystania z multidex w aplikacji.
Konfigurowanie aplikacji pod kątem obsługi środowiska Multidex
Uwaga: jeśliminSdkVersion
ma wartość 21 lub większą, tryb multidex jest domyślnie włączony
i nie potrzebujesz biblioteki Multidex.
Jeśli minSdkVersion
ma wartość 20 lub niższą,
musi użyć funkcji
multidex Library i
te zmiany w projekcie aplikacji:
-
Zmodyfikuj plik
build.gradle
na poziomie modułu na włącz multidex i dodaj bibliotekę multidex jako zależność, jak w poniższym przykładzie:Odlotowe
android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 33 multiDexEnabled true } ... } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
Kotlin
android { defaultConfig { ... minSdk = 15 targetSdk = 33 multiDexEnabled = true } ... } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
- W zależności od tego, czy zastępujesz
Application
, wykonaj jedną z tych czynności:- .
Jeśli nie zastąpisz parametru
Application
, zmodyfikuj plik manifestu, aby ustawićandroid:name
w<application>
w następujący sposób:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <application android:name="androidx.multidex.MultiDexApplication" > ... </application> </manifest>
Jeśli zastąpisz parametr
Application
klasy, zmień ją na rozszerzenieMultiDexApplication
w ten sposób:Kotlin
class MyApplication : MultiDexApplication() {...}
Java
public class MyApplication extends MultiDexApplication { ... }
Jeśli zastąpisz
Application
ale nie można zmienić klasy bazowej, zamiast tego zastąp metodęattachBaseContext()
i wywołajMultiDex.install(this)
, aby włączyć Multidex:Kotlin
class MyApplication : SomeOtherApplication() { override fun attachBaseContext(base: Context) { super.attachBaseContext(base) MultiDex.install(this) } }
Java
public class MyApplication extends SomeOtherApplication { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
Uwaga: nie uruchamiaj
MultiDex.install()
lub dowolny inny kod poprzez odbicie lub JNI przed ukończeniemMultiDex.install()
. Śledzenie Multidex będzie nie realizuj tych wywołań, powodującClassNotFoundException
lub zweryfikując błędy z powodu nieprawidłowej partycji klasy między plikami DEX.
Teraz podczas tworzenia aplikacji narzędzia Android Build tworzą podstawowy plik DEX
(classes.dex
) i obsługujące pliki DEX
(classes2.dex
, classes3.dex
itd.) w razie potrzeby.
Następnie system kompilacji spakuje wszystkie pliki DEX do Twojego pliku APK.
W czasie działania zamiast wyszukiwania tylko w głównej aplikacji
classes.dex
, interfejsy API Multidex używają specjalnego programu ładującego klas do przeszukiwania wszystkich
dostępne pliki DEX.
Ograniczenia biblioteki Multidex
Biblioteka Multidex ma pewne znane ograniczenia. Włączając tę bibliotekę do konfiguracji kompilacji aplikacji, weź pod uwagę te kwestie:
- Instalacja plików DEX podczas uruchamiania na partycji danych urządzenia jest skomplikowana i może spowodować błąd ANR (Application Not Responding), jeśli dodatkowe pliki DEX będą duże. Do uniknąć tego problemu, włącz zmniejszanie kodu, by zminimalizować pliki DEX i usunąć nieużywane fragmenty kodu.
- Jeśli działa na urządzeniach z Androidem w wersji starszej niż 5.0 (poziom interfejsu API 21) za pomocą
Multidex nie wystarczy, aby obejść limit przydziału liniowego (numer 37008143). Ten limit został zwiększony o
Androida 4.0 (poziom interfejsu API 14), ale to nie rozwiązało całkowicie problemu.
W wersjach starszych niż 4.0 limit przydziału linearnego może zostać osiągnięty przed osiągnęliśmy limit indeksu DEX. Jeśli więc kierujesz reklamy na poziomy interfejsu API niższe niż 14, dokładnie przetestuj ją na tych wersjach platformy, ponieważ aplikacja może mają problemy podczas uruchamiania lub gdy są wczytywane określone grupy klas.
Zmniejszanie kodu może zmniejszyć wyeliminować te problemy.
Deklarowanie klas wymaganych w głównym pliku DEX
Podczas tworzenia każdego pliku DEX dla aplikacji Multidex narzędzia do kompilacji
złożonego procesu decyzyjnego w celu określenia, które klasy są potrzebne w głównej bibliotece DEX;
, aby aplikacja mogła się uruchomić. Jakiekolwiek wymagane zajęcia
nie jest dostarczany w głównym pliku DEX, a w rezultacie aplikacja ulega awarii.
z błędem java.lang.NoClassDefFoundError
.
Narzędzia do kompilacji rozpoznają ścieżki kodu, do których dostęp uzyskuje się bezpośrednio z aplikacji w kodzie. Ten problem może jednak występują, gdy ścieżki kodu są mniej widoczne. Na przykład gdy używana biblioteka złożonych zależności. Jeśli na przykład kod używa introspekcji lub wywołania metod Java z kodu natywnego, klasy te mogą nie zostać rozpoznane jako wymagane w podstawowym pliku DEX.
Jeśli otrzymasz java.lang.NoClassDefFoundError
,
musi ręcznie określić dodatkowe klasy wymagane w podstawowym pliku DEX
, deklarując je we właściwości multiDexKeepProguard
w swoim typie kompilacji. Jeśli klasa pasuje do
plik multiDexKeepProguard
, a następnie te zajęcia
zostanie dodany do głównego pliku DEX.
właściwość multiDexKeepProguard
Plik multiDexKeepProguard
używa tego samego formatu co ProGuard i obsługuje
i całej gramatyki ProGuard. Więcej informacji o tym, jak dostosować informacje przechowywane w aplikacji, znajdziesz w artykule
Wybierz kod, który chcesz zachować.
Plik określony w polu multiDexKeepProguard
powinien zawierać -keep
w dowolnej prawidłowej składni ProGuard. Przykład:
-keep com.example.MyClass.class
Możesz utworzyć plik o nazwie
multidex-config.pro
wygląda tak:
-keep class com.example.MyClass -keep class com.example.MyClassToo
Jeśli chcesz określić wszystkie klasy w pakiecie, plik wygląda tak:
-keep class com.example.** { *; } // All classes in the com.example package
Następnie możesz zadeklarować ten plik dla danego typu kompilacji w ten sposób:
Odlotowe
android { buildTypes { release { multiDexKeepProguard file('multidex-config.pro') ... } } }
Kotlin
android { buildTypes { getByName("release") { multiDexKeepProguard = file("multidex-config.pro") ... } } }
Optymalizuj multidex w budynkach deweloperskich
Konfiguracja multidex wymaga znacznie zwiększonego przetwarzania kompilacji ponieważ system kompilacji musi podejmować złożone decyzje dotyczące klas, muszą być uwzględnione w głównym pliku DEX i w których klasach można uwzględnić dodatkowych plików DEX. Oznacza to, że kompilacje przyrostowe korzystające z multidex zwykle są może potrwać dłużej i może spowolnić proces programowania.
Aby ograniczyć wydłużenie czasu przyrostowego kompilacji, użyj funkcji
predexing, aby ponownie wykorzystywać dane wyjściowe w formacie multidex między kompilacjami.
Wyodrębnianie treści przed deksowaniem korzysta z formatu ART dostępnego tylko na Androidzie 5.0
(poziom interfejsu API 21) i wyższy. Jeśli używasz Androida Studio, IDE automatycznie korzysta z predexingu
podczas wdrażania aplikacji na urządzeniu z Androidem 5.0 (poziom interfejsu API 21) lub nowszym.
Jeśli jednak uruchamiasz kompilacje Gradle z poziomu wiersza poleceń, musisz ustawić atrybut
minSdkVersion
do wersji 21 lub wyższej, by włączyć wstępne wczytywanie.
minSdkVersion
,
Jak widać:
Odlotowe
android { defaultConfig { ... multiDexEnabled true // The default minimum API level you want to support. minSdkVersion 15 } productFlavors { // Includes settings you want to keep only while developing your app. dev { // Enables pre-dexing for command-line builds. When using // Android Studio 2.3 or higher, the IDE enables pre-dexing // when deploying your app to a device running Android 5.0 // (API level 21) or higher, regardless of minSdkVersion. minSdkVersion 21 } prod { // If you've configured the defaultConfig block for the production version of // your app, you can leave this block empty and Gradle uses configurations in // the defaultConfig block instead. You still need to include this flavor. // Otherwise, all variants use the "dev" flavor configurations. } } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
Kotlin
android { defaultConfig { ... multiDexEnabled = true // The default minimum API level you want to support. minSdk = 15 } productFlavors { // Includes settings you want to keep only while developing your app. create("dev") { // Enables pre-dexing for command-line builds. When using // Android Studio 2.3 or higher, the IDE enables pre-dexing // when deploying your app to a device running Android 5.0 // (API level 21) or higher, regardless of minSdkVersion. minSdk = 21 } create("prod") { // If you've configured the defaultConfig block for the production version of // your app, you can leave this block empty and Gradle uses configurations in // the defaultConfig block instead. You still need to include this flavor. // Otherwise, all variants use the "dev" flavor configurations. } } buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } } } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
Aby poznać więcej strategii, które pomagają zwiększyć szybkość kompilacji, z poziomu Android Studio lub polecenia przeczytaj artykuł Optymalizacja szybkości kompilacji. Więcej informacji o używaniu wariantów kompilacji znajdziesz tutaj: Skonfiguruj warianty kompilacji.
Wskazówka: jeśli masz różne warianty kompilacji dla różnych
Multidex, dla każdego z nich możesz dostarczyć inny plik manifestu.
wariantu, więc tylko plik dla interfejsu API poziomu 20 i niższych zmienia wartość
Nazwa tagu <application>
. Możesz też
utwórz inną podklasę Application
dla każdego wariantu, aby
tylko podklasa dla interfejsu API poziomu 20 i niższych rozszerza klasę MultiDexApplication
lub
Wywołuje połączenie MultiDex.install(this)
.
Testowanie aplikacji multidex
Gdy piszesz testy instrumentacji dla aplikacji multidex, nie musisz niczego konfigurować
jeśli używasz
MonitoringInstrumentation
lub
.
AndroidJUnitRunner
z narzędzi pomiarowych. Jeśli używasz innego
Instrumentation
,
musisz zastąpić jej metodę onCreate()
tym kodem:
Kotlin
fun onCreate(arguments: Bundle) { MultiDex.install(targetContext) super.onCreate(arguments) ... }
Java
public void onCreate(Bundle arguments) { MultiDex.install(getTargetContext()); super.onCreate(arguments); ... }