Multidex für Anwendungen mit über 64.000 Methoden aktivieren

Wenn Ihre App eine minSdk von API 20 oder niedriger hat und Ihre App und die Bibliotheken, auf die sie verweist, mehr als 65.536 Methoden enthalten, wird der folgende Buildfehler angezeigt, der darauf hinweist, dass Ihre App das Limit der Android-Buildarchitektur erreicht hat:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

Ältere Versionen des Build-Systems melden einen anderen Fehler, der auf denselben Fehler hinweist. Problem:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

Bei diesen Fehlerbedingungen wird eine gemeinsame Zahl angezeigt: 65536. Diese Zahl entspricht der Gesamtzahl der Verweise, die vom Code in einer einzelnen DEX-Bytecodedatei (Dalvik Executable) aufgerufen werden können. Auf dieser Seite wird erläutert, wie Sie diese Einschränkung Mit der sogenannten Multidex-App-Konfiguration um mehrere DEX-Dateien zu erstellen und zu lesen.

Referenzlimit von 64.000

Android-App-Dateien (APKs) enthalten ausführbare Bytecode-Dateien im Format von Dalvik Ausführbare Dateien (DEX), die den kompilierten Code zum Ausführen Ihrer Anwendung enthalten. Die Dalvik Executable-Spezifikation begrenzt die Gesamtzahl der Methoden, kann in einer einzelnen DEX-Datei bis 65.536 – einschließlich Android – Framework-Methoden, Bibliotheksmethoden und Methoden in Ihrem eigenen Code.

Im Kontext der Informatik steht der Begriff Kilo oder K für 1.024 (oder 2^10). Da 65.536 64 × 1.024 entspricht, wird dieses Limit als 64K-Referenzlimit bezeichnet.

Unterstützung von Multidex vor Android 5.0

Bei Versionen der Plattform vor Android 5.0 (API-Level 21) wird die Dalvik-Laufzeit zum Ausführen von App-Code verwendet. Standardmäßig beschränkt Dalvik Apps auf eine einzelne classes.dex-Bytecodedatei pro APK. Um diese Einschränkung zu umgehen, fügen Sie die Multidex-Bibliothek der Datei build.gradle oder build.gradle.kts auf Modulebene hinzu:

Groovy

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")
}

Diese Bibliothek wird Teil der primären DEX-Datei Ihrer App und verwaltet den Zugriff auf die zusätzlichen DEX-Dateien und den darin enthaltenen Code. Die aktuellen Versionen dieser Bibliothek finden Sie unter Multidex-Versionen.

Weitere Informationen finden Sie im Abschnitt zur konfiguriere deine App für Multidex.

Multidex-Unterstützung für Android 5.0 und höher

Android 5.0 (API-Level 21) und höher verwendet eine Laufzeit mit dem Namen ART, die unterstützt das Laden mehrerer DEX-Dateien aus APK-Dateien. ART führt bei der App-Installation eine Vorkompilierung durch, sucht nach classesN.dex-Dateien und kompiliert sie zu einer einzelnen OAT-Datei, die vom Android-Gerät ausgeführt wird. Wenn also Ihre minSdkVersion 21 oder höher ist, ist Multidex standardmäßig aktiviert und Sie benötigen die Multidex-Bibliothek nicht.

Weitere Informationen zur Laufzeit von Android 5.0 finden Sie unter Android Runtime (ART) und Dalvik.

Hinweis:Wenn Sie Ihre App mit Android Studio ausführen, ist der Build für die Zielgeräte optimiert, auf denen Sie die Bereitstellung vornehmen. Dazu gehört auch die Aktivierung von Multidex, wenn auf den Zielgeräten Android 5.0 oder höher ausgeführt wird. Da diese Optimierung nur angewendet wird, wenn Ihre Anwendung mit Android Studio müssen Sie möglicherweise noch Ihren Release-Build konfigurieren. um die 64.000-Grenze zu umgehen.

Das Limit von 64.000 KB vermeiden

Bevor Sie Ihre App für die Verwendung von 64K oder mehr Methodenreferenzen konfigurieren, sollten Sie Folgendes tun um die Gesamtzahl der von Ihrem App-Code aufgerufenen Verweise zu reduzieren, einschließlich der durch Ihren App-Code oder enthaltene Bibliotheken.

Die folgenden Strategien können Ihnen helfen, das Erreichen des DEX-Referenzlimits zu vermeiden:

Direkte und transitive Abhängigkeiten Ihrer App prüfen
Überlegen Sie, ob der Wert einer großen Bibliotheksabhängigkeit, die Sie in Ihre App aufnehmen, den Codeumfang überwiegt, der der App hinzugefügt wird. Ein häufiges, aber problematisches Muster ist die Aufnahme einer sehr großen Bibliothek, weil einige Dienstmethoden nützlich waren. Die Reduzierung der Abhängigkeiten Ihres App-Codes kann oft helfen, Sie vermeiden das DEX-Referenzlimit.
Ungenutzten Code mit R8 entfernen
Codekomprimierung aktivieren, um R8 auszuführen für Ihre Release-Builds. Aktivieren Sie die Verkleinerung, mit Ihren APKs keinen ungenutzten Code versenden. Wenn die Codekomprimierung richtig konfiguriert ist, können auch nicht verwendete Codeelemente und Ressourcen aus Ihren Abhängigkeiten entfernt werden.

Mit diesen Techniken können Sie die Gesamtgröße Ihres APKs verringern und die Notwendigkeit von Multidex in Ihrer App vermeiden.

App für Multidex konfigurieren

Hinweis: Wenn minSdkVersion auf 21 oder höher festgelegt ist, ist MultiDex standardmäßig aktiviert und Sie benötigen die MultiDex-Bibliothek nicht.

Wenn Ihre minSdkVersion auf 20 oder niedriger eingestellt ist, muss die Multidex-Bibliothek und die folgenden Änderungen an Ihrem App-Projekt vorgenommen haben:

  1. Ändern Sie die build.gradle-Datei auf Modulebene, um MultiDex zu aktivieren und die MultiDex-Bibliothek als Abhängigkeit hinzuzufügen, wie hier gezeigt:

    Groovy

    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")
    }
  2. Je nachdem, ob Sie den Application führen Sie einen der folgenden Schritte aus:
    • Wenn Sie Application nicht überschreiben , bearbeiten Sie Ihre Manifestdatei und legen Sie android:name im <application>-Tag so an:

      <?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>
    • Wenn Sie die Klasse Application überschreiben, ändern Sie sie so, dass sie von MultiDexApplication erbt:

      Kotlin

      class MyApplication : MultiDexApplication() {...}

      Java

      public class MyApplication extends MultiDexApplication { ... }
    • Wenn Sie die Application-Klasse überschreiben, die Basisklasse aber nicht geändert werden kann, überschreiben Sie stattdessen die Methode attachBaseContext() und rufen Sie MultiDex.install(this) auf, um Multidex zu aktivieren:

      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);
        }
      }

      Achtung:Nicht ausführen MultiDex.install() oder einem anderen Code durch Reflexion oder JNI, bevor MultiDex.install() abgeschlossen ist. Bei der Multidex-Verfolgung diesen Aufrufen nicht folgen, ClassNotFoundException verursachen oder Fehler überprüfen aufgrund einer fehlerhaften Klassenpartition zwischen DEX-Dateien.

Wenn Sie Ihre App jetzt erstellen, erstellen die Android-Build-Tools eine primäre DEX-Datei (classes.dex) und nach Bedarf unterstützende DEX-Dateien (classes2.dex, classes3.dex usw.). Das Build-System verpackt dann alle DEX-Dateien in Ihrem APK.

Zur Laufzeit suchen Sie dann nicht nur in der Haupt-, classes.dex-Datei verwenden, verwenden die Multidex-APIs ein spezielles Klassenladeprogramm, um alle verfügbaren DEX-Dateien für Ihre Methoden.

Einschränkungen der Multidex-Bibliothek

Für die multidex-Bibliothek gelten einige bekannte Einschränkungen. Beachten Sie Folgendes, wenn Sie die Bibliothek in die Build-Konfiguration Ihrer App einbinden:

  • Die Installation von DEX-Dateien beim Starten auf der Datenpartition eines Geräts ist komplex und kann zu ANR-Fehlern (App antwortet nicht) führen, wenn die sekundären DEX-Dateien groß sind. Bis aktivieren Sie das Verkleinern von Code, die Größe von DEX-Dateien zu reduzieren und nicht verwendete Codeteile zu entfernen.
  • Bei der Ausführung auf Versionen vor Android 5.0 (API-Level 21) reicht die Verwendung von Multidex nicht aus, um das Limit für linearalloc zu umgehen (Problem 37008143). Dieses Limit wurde erhöht in Android 4.0 (API-Level 14), aber dadurch wurde das Problem nicht vollständig behoben.

    Bei Versionen unter Android 4.0 wird möglicherweise das Limit für linearalloc erreicht, bevor das Limit für den DEX-Index erreicht wird. Wenn Sie eine Ausrichtung auf API-Ebenen vornehmen, die niedriger sind als 14. Testen Sie diese Versionen der Plattform gründlich, da Ihre App Probleme beim Start oder beim Laden bestimmter Gruppen von Klassen auftreten.

    Durch Code-Shrinking können diese Probleme reduziert oder möglicherweise beseitigt werden.

In der primären DEX-Datei erforderliche Klassen deklarieren

Beim Erstellen jeder DEX-Datei für eine Multidex-App treffen die Build-Tools komplexe Entscheidungen, um festzustellen, welche Klassen in der primären DEX-Datei benötigt werden, damit Ihre App gestartet werden kann. Erforderliche Kurse nicht in der primären DEX-Datei angegeben ist, stürzt die App mit dem Fehler java.lang.NoClassDefFoundError.

Die Build-Tools erkennen die Codepfade für Code, auf den direkt über Ihren App-Code zugegriffen wird. Dieses Problem kann jedoch treten auf, wenn die Codepfade weniger sichtbar sind, z. B. wenn eine von Ihnen verwendete Bibliothek und komplexe Abhängigkeiten. Wenn der Code beispielsweise die Inspektion oder Aufrufe von Java-Methoden aus nativem Code verwendet, werden diese Klassen möglicherweise nicht als erforderlich in der primären DEX-Datei erkannt.

Wenn du java.lang.NoClassDefFoundError erhältst, muss die im primären DEX erforderlichen zusätzlichen Klassen manuell angeben indem Sie sie mit dem Attribut multiDexKeepProguard in Ihrem Build-Typ deklarieren. Wenn eine Klasse in der multiDexKeepProguard-Datei übereinstimmt, wird sie der primären DEX-Datei hinzugefügt.

Eigenschaft „multiDexKeepProguard“

Die Datei multiDexKeepProguard hat dasselbe Format wie ProGuard und unterstützt die gesamte ProGuard-Grammatik. Weitere Informationen dazu, wie Sie festlegen können, was in Ihrer App gespeichert wird, finden Sie unter Festlegen, welcher Code beibehalten werden soll

Die Datei, die Sie in multiDexKeepProguard angeben, muss -keep enthalten. -Optionen in einer beliebigen gültigen ProGuard-Syntax. Beispiel: -keep com.example.MyClass.class. Erstellen Sie eine Datei namens multidex-config.pro, die so aussieht:

-keep class com.example.MyClass
-keep class com.example.MyClassToo

Wenn Sie alle Klassen in einem Paket angeben möchten, sieht die Datei so aus:

-keep class com.example.** { *; } // All classes in the com.example package

So deklarieren Sie diese Datei für einen Build-Typ:

Groovy

android {
    buildTypes {
        release {
            multiDexKeepProguard file('multidex-config.pro')
            ...
        }
    }
}

Kotlin

android {
    buildTypes {
        getByName("release") {
            multiDexKeepProguard = file("multidex-config.pro")
            ...
        }
    }
}

Multidex in Entwicklungs-Builds optimieren

Eine Multidex-Konfiguration erfordert eine deutlich erhöhte Build-Verarbeitung da das Build-System komplexe Entscheidungen darüber treffen muss, welche Klassen muss in der primären DEX-Datei enthalten sein und welche Klassen in sekundäre DEX-Dateien. Das bedeutet, dass inkrementelle Builds mit Multidex in der Regel und kann den Entwicklungsprozess verlangsamen.

Um längere inkrementelle Build-Zeiten abzumildern, verwenden Sie Predexing zur Wiederverwendung der Multidex-Ausgabe zwischen Builds Das Vorab-Dexing verwendet ein ART-Format, das nur auf Android 5.0 (API-Level 21) und höher verfügbar ist. Wenn Sie Android Studio verwenden, verwendet die IDE automatisch Predexing wenn Sie Ihre App auf einem Gerät mit Android 5.0 (API-Level 21) oder höher bereitstellen. Wenn Sie jedoch Gradle-Builds über die Befehlszeile ausführen, müssen Sie den Parameter minSdkVersion auf 21 oder höher, um das Pre-Dexing zu aktivieren.

Um die Einstellungen für Ihr Produktions-Builds können Sie zwei Versionen Ihrer App Verwendung von Geschmacksrichtungen – eine Version mit Entwicklungs- und eine Version mit Release-Flair – mit verschiedene Werte für minSdkVersion, wie hier gezeigt:

Groovy

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")
}

Weitere Strategien zur Verbesserung der Build-Geschwindigkeit über Android Studio oder den Befehl Build-Geschwindigkeit optimieren. Weitere Informationen zur Verwendung von Build-Varianten finden Sie unter Build-Varianten konfigurieren

Tipp:Wenn Sie verschiedene Build-Varianten für verschiedene Multidex-Anforderungen erfüllt, können Sie für jedes sodass nur die Datei für API-Level 20 und niedriger <application>-Tag-Name. Sie können auch für jede Variante eine andere Application-Unterklasse erstellen, sodass nur die Unterklasse für API-Ebene 20 und niedriger die MultiDexApplication-Klasse erweitert oder MultiDex.install(this) aufruft.

Multidex-Apps testen

Wenn Sie Instrumentierungstests für Multidex-Apps schreiben, ist keine zusätzliche Konfiguration erforderlich wenn Sie eine MonitoringInstrumentation oder ein AndroidJUnitRunner Instrumentierung. Wenn Sie eine andere Instrumentation, dann müssen Sie die onCreate()-Methode mit dem folgenden Code überschreiben:

Kotlin

fun onCreate(arguments: Bundle) {
  MultiDex.install(targetContext)
  super.onCreate(arguments)
  ...
}

Java

public void onCreate(Bundle arguments) {
  MultiDex.install(getTargetContext());
  super.onCreate(arguments);
  ...
}