Se la tua app ha minSdk
di API 20 o versioni precedenti e la tua app e
librerie a cui fa riferimento superano i 65.536 metodi, si verifica il seguente errore di build
indica che la tua app ha raggiunto il limite dell'architettura della build di Android:
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.
Le versioni precedenti del sistema di compilazione segnalano un errore diverso, che indica lo stesso problema:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
Queste condizioni di errore mostrano un numero comune: 65536. Questo numero rappresenta il numero totale di riferimenti che possono essere richiamati dal codice all'interno di un singolo file bytecode Dalvik eseguibile (DEX). Questa pagina spiega come superare questa limitazione attivando una configurazione dell'app nota come multidex, che consente all'app di compilare e leggere più file DEX.
Informazioni sul limite di 64.000 riferimenti
I file APK (app per Android) contengono file bytecode eseguibili sotto forma di file Dalvik Executable (DEX), che contengono il codice compilato utilizzato per eseguire l'app. La specifica Dalvik Executable limita a 65.536 il numero totale di metodi a cui è possibile fare riferimento all'interno di un singolo file DEX, inclusi i metodi del framework Android, i metodi della libreria e i metodi nel tuo codice.
Nella nel contesto dell'informatica, il termine kilo o K indica 1024 (ovvero 2^10). Poiché 65.536 corrisponde a 64 x 1024, questo limite è denominato _Limite di riferimento di 64.000_.Supporto di Multidex precedente ad Android 5.0
Le versioni della piattaforma precedenti ad Android 5.0 (livello API 21) utilizzano Dalvik
per l'esecuzione del codice dell'app. Per impostazione predefinita, Dalvik limita le app a una singola
classes.dex
file di bytecode per APK. Per aggirare il problema
limitazione, aggiungi la libreria multidex al livello build.gradle
a livello di modulo oppure
build.gradle.kts
file:
dependencies { def multidex_version = "2.0.1" implementation "androidx.multidex:multidex:$multidex_version" }
dependencies { val multidex_version = "2.0.1" implementation("androidx.multidex:multidex:$multidex_version") }
Questa libreria diventa parte del file DEX principale della tua app e poi gestisce l'accesso ai file DEX aggiuntivi e al codice che contengono. Per visualizzare le versioni attuali di questa libreria, consulta le versioni multidex.
Per ulteriori dettagli, consulta la sezione su come configurare la tua app per multidex.Supporto di Multidex per Android 5.0 e versioni successive
Android 5.0 (livello API 21) e versioni successive utilizza un runtime chiamato ART che
supporta in modo nativo il caricamento di più file DEX dai file APK. ARTE
esegue la precompilazione al momento dell'installazione dell'app, analizzando
classesN.dex
file e la loro compilazione in un'unica
file OAT per
esecuzione da parte del dispositivo Android. Pertanto, se minSdkVersion
è 21 o superiore, il multidex è abilitato per impostazione predefinita e non è necessaria la libreria multidex.
Per ulteriori informazioni su Android 5.0 runtime, leggi Android Runtime (ART) e Dalvik.
Nota: quando esegui l'app utilizzando Android Studio, la build è ottimizzata per i dispositivi di destinazione su cui esegui il deployment. Ciò include l'attivazione di multidex quando i dispositivi di destinazione eseguono Android 5.0 e versioni successive. Poiché questa ottimizzazione viene applicata solo quando esegui il deployment dell'app utilizzando Android Studio, potrebbe essere comunque necessario configurare la build della release per il multidex per evitare il limite dei 64K.
Evitare il limite di 64 KB
Prima di configurare l'app in modo da consentire l'uso di almeno 64.000 riferimenti di metodi, segui questi passaggi per ridurre il numero totale di riferimenti chiamati dal codice dell'app, inclusi i metodi definiti del codice dell'app o delle librerie incluse.
Le seguenti strategie possono aiutarti a evitare di raggiungere il limite di riferimenti DEX:
- Controlla le dipendenze dirette e trasitive della tua app
- Valuta se il valore di una dipendenza da una libreria di grandi dimensioni inclusa nella tua app supera la quantità di codice aggiunto all'app. Un pattern comune, ma problematico, è includere una libreria molto grande perché alcuni metodi di utilità sono utili. Spesso, ridurre le dipendenze del codice dell'app può aiutarti a evitare il limite di riferimenti DEX.
- Rimuovere il codice inutilizzato con R8
- Abilita la riduzione del codice per eseguire R8 per le build delle tue release. Attiva la riduzione per assicurarti di non spediscano il codice inutilizzato con gli APK. Se la riduzione del codice è configurata correttamente, puoi anche rimuovere codice e risorse inutilizzati dalle tue dipendenze.
L'utilizzo di queste tecniche può aiutarti a ridurre le dimensioni complessive dell'APK e evitare la necessità di multidex nella tua app.
Configura la tua app per Multidex
Nota: seminSdkVersion
è impostato su 21 o versioni successive, il multidex è abilitato per impostazione predefinita
e non è necessaria la libreria multidex.
Se il valore di minSdkVersion
è impostato su 20 o su un valore inferiore,
deve utilizzare
libreria multidex e
le seguenti modifiche al progetto dell'app:
-
Modifica il file
build.gradle
a livello di modulo in abilita multidex e aggiungi la libreria multidex come dipendenza, come mostrato qui:android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 33 multiDexEnabled true } ... } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
android { defaultConfig { ... minSdk = 15 targetSdk = 33 multiDexEnabled = true } ... } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
- A seconda che sostituisci o meno la classe
Application
, esegui una delle seguenti operazioni:Se non sostituisci la classe
Application
, modifica il file manifest per impostareandroid:name
nel tag<application>
come segue:<?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>
Se sostituisci la classe
Application
, modificala in modo che estendaMultiDexApplication
, come segue:Se sostituisci la classe
Application
, ma non è possibile modificare la classe di base, allora sostituisci il metodoattachBaseContext()
e chiamaMultiDex.install(this)
per attivare il multidex:class MyApplication : SomeOtherApplication() { override fun attachBaseContext(base: Context) { super.attachBaseContext(base) MultiDex.install(this) } }
public class MyApplication extends SomeOtherApplication { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
Attenzione: non eseguire
MultiDex.install()
o qualsiasi altro codice tramite la riflessione o JNI prima del completamento diMultiDex.install()
. Il tracciamento multidex non seguire queste chiamate, causandoClassNotFoundException
errori o verificando gli errori a causa di una partizione di classe non valida tra i file DEX.
Ora, quando crei la tua app, gli strumenti di sviluppo Android creano un file DEX principale
(classes.dex
) e file DEX di supporto
(classes2.dex
, classes3.dex
e così via) in base alle esigenze.
Il sistema di compilazione pacchettizza quindi tutti i file DEX nell'APK.
In fase di esecuzione, anziché cercare solo nel file classes.dex
principale, le API multidex utilizzano un caricatore di classi speciale per cercare i tuoi metodi in tutti i file DEX disponibili.
Limitazioni della libreria multidex
La raccolta multidex presenta alcune limitazioni note. Quando incorpori la libreria nella configurazione di compilazione dell'app, tieni presente quanto segue:
- L'installazione di file DEX durante l'avvio sulla partizione dati di un dispositivo è complessa e può causare errori L'applicazione non risponde (ANR) se i file DEX secondari sono di grandi dimensioni. Per evitare questo problema, attiva la riduzione del codice per ridurre al minimo le dimensioni dei file DEX e rimuovere le parti di codice inutilizzate.
- Se vengono eseguite su versioni precedenti ad Android 5.0 (livello API 21), utilizzando
multidex non è sufficiente per aggirare il limite linearalloc (problema 37008143). Questo limite è stato aumentato in
Android 4.0 (livello API 14), ma il problema non è stato completamente risolto.
Nelle versioni precedenti ad Android 4.0, potresti raggiungere il limite di linearalloc prima di raggiungere il limite dell'indice DEX. Se quindi scegli come target livelli API inferiori a 14, eseguire test approfonditi su queste versioni della piattaforma, perché la tua app potrebbe riscontrano problemi all'avvio o quando vengono caricati gruppi specifici di corsi.
La compressione del codice può ridurre o addirittura eliminare questi problemi.
Dichiara le classi richieste nel file DEX principale
Quando si crea ogni file DEX per un'app multidex, gli strumenti di creazione
un processo decisionale complesso per determinare quali classi sono necessarie nel file DEX principale
per avviare correttamente l'app. Se un corso obbligatorio
durante l'avvio non è fornito nel file DEX principale, l'app si arresta in modo anomalo
con l'errore java.lang.NoClassDefFoundError
.
Gli strumenti di compilazione riconoscono i percorsi del codice a cui si accede direttamente dal codice dell'app. Tuttavia, questo problema può si verificano quando i percorsi del codice sono meno visibili, ad esempio quando una libreria che utilizzi ha di dipendenze complesse. Ad esempio, se il codice utilizza introspezione o chiamata di metodi Java da codice nativo, queste classi potrebbero non essere riconosciute come obbligatoria nel file DEX principale.
Se ricevi java.lang.NoClassDefFoundError
, devi specificare manualmente le classi aggiuntive richieste nel file DEX principale dichiarandole con la proprietà multiDexKeepProguard
nel tipo di build. Se un corso corrisponde a
il file multiDexKeepProguard
, poi la classe
viene aggiunto al file DEX principale.
proprietà multiDexKeepProGuard
Il file multiDexKeepProguard
utilizza lo stesso formato di ProGuard e supporta il
l'intera grammatica di ProGuard. Per ulteriori informazioni su come personalizzare i contenuti memorizzati nella tua app, vedi
Personalizzare il codice da conservare.
Il file specificato in multiDexKeepProguard
deve contenere -keep
in qualsiasi sintassi ProGuard valida. Ad esempio:
-keep com.example.MyClass.class
. Puoi creare un file chiamato
multidex-config.pro
che ha il seguente aspetto:
-keep class com.example.MyClass -keep class com.example.MyClassToo
Se vuoi specificare tutte le classi di un pacchetto, il file sarà simile al seguente:
-keep class com.example.** { *; } // All classes in the com.example package
Poi puoi dichiarare il file per un tipo di compilazione, come segue:
android { buildTypes { release { multiDexKeepProguard file('multidex-config.pro') ... } } }
android { buildTypes { getByName("release") { multiDexKeepProguard = file("multidex-config.pro") ... } } }
Ottimizza il multidex nelle build di sviluppo
Una configurazione multidex richiede un tempo di elaborazione della build molto più elevato perché il sistema di build deve prendere decisioni complesse su quali classi devono essere incluse nel file DEX principale e quali classi possono essere incluse nei file DEX secondari. Ciò significa che le build incrementali che utilizzano multidex in genere impiegano più tempo e possono potenzialmente rallentare il processo di sviluppo.
Per ridurre i tempi di compilazione incrementali più lunghi, utilizza il pre-dexing per riutilizzare l'output multidex tra le compilazioni.
Il pre-dexing si basa su un formato ART disponibile solo su Android 5.0
(livello API 21) e superiore. Se utilizzi Android Studio, l'IDE utilizza automaticamente il pre-dexing
durante il deployment dell'app su un dispositivo con Android 5.0 (livello API 21) o versioni successive.
Tuttavia, se esegui build di Gradle dalla riga di comando, devi impostare
minSdkVersion
su 21 o versioni successive per attivare il pre-dexing.
minSdkVersion
,
come mostrato:
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" }
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") }
Scoprire altre strategie utili per migliorare la velocità delle build da Android Studio o dal comando vedi Ottimizzare la velocità di compilazione. Per ulteriori informazioni sull'utilizzo delle varianti di build, consulta Configurare le varianti di build.
Suggerimento:se hai diverse varianti di build per diverse varianti
esigenze multidex, puoi fornire un file manifest diverso per ogni
pertanto solo il file per il livello API 20 o inferiore modifica la
Nome tag <application>
. Puoi anche
creare una sottoclasse Application
diversa per ogni variante in modo che
solo la sottoclasse per il livello API 20 e versioni precedenti espanda la classe MultiDexApplication
o
chiami MultiDex.install(this)
.
Testa le app multidex
Quando scrivi test di misurazione per app multidex, non è necessaria alcuna configurazione aggiuntiva se utilizzi una misurazione MonitoringInstrumentation
o AndroidJUnitRunner
. Se utilizzi un altro
Instrumentation
,
devi sostituire il metodo onCreate()
con il seguente codice:
fun onCreate(arguments: Bundle) { MultiDex.install(targetContext) super.onCreate(arguments) ... }
public void onCreate(Bundle arguments) { MultiDex.install(getTargetContext()); super.onCreate(arguments); ... }