preface

Cause: The project has been using Multidex :1.0.3 and wanted to upgrade. Here comes the surprise.

65536

When your application and the libraries it references exceed 65,536 methods, you will experience build errors indicating that your application has reached the limits of the Android build architecture:

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

Older versions of the build system reported different bugs, indicating the same problem:

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

Both error conditions show a common number: 65536. This number represents the total number of references that code in a single Dalvik executable (DEX) bytecode file can call. This question shows how to overcome this limitation by enabling an application configuration called Multidex, which allows your application to build and read multiple DEX files.

Reference limit for 64K

Android application (APK) files contain executable bytecode files in the form of Dalvik executable (DEX) files, which contain the compiled code used to run the application. The Dalvik Executable specification limits the total number of methods that can be referenced in a single DEX file to 65,536, including Android framework methods, library methods, and methods in your own code. In the context of computer science, the term Kilo, K means 1024 (or 2^10). Since 65,536 is equal to 64 X 1024, this limit is called the “64K reference limit.”

Resolve 64K limit

Multidex support for Android 5.0 and later

Android 5.0 (API level 21) and later uses a runtime called ART, which natively supports loading multiple DEX files from APK files. ART performs precompilation when the application is installed, scanning the classesn. dex files and compiling them into a single.oat file for the Android device to execute. Therefore, if your minSdkVersion is 21 or higher, Multidex is enabled by default, and you do not need the Multidex library.

Note: When running your application with Android Studio, the build is optimized for the target device to which you deploy. This includes enabling Multidex when the target device is running Android 5.0 or later. Because this optimization applies only when you deploy your application using Android Studio, you may still need to configure the release version for Multidex to avoid the 64K limit.

See, the best solution here is to set minSdkVersion to 21 or higher. What’s on the Internet

  • Multidex the pits you encounter
  • Multidex with secrets you have to say
  • It’s none of your business to know how Multidex works and how it works, if you want to.

[Fixed] Android SDK for 21 or higher, what about below 21? Let’s read on.

Multidex support prior to Android 5.0

Configure Multidex for your application

If your minSdkVersion is set to 21 or higher, multidex is enabled by default and you do not need the Multidex library.

However, if your minSdkVersion is set to 20 or lower, then you must use the Multidex library and make the following changes to your application project:

1. Modify the module-level build.gradle file to enable multidex and add the Multidex library as a dependency, as shown below:

  • Using AndroidX
android {
    defaultConfig {
        ...
        minSdkVersion 15 
        targetSdkVersion 30
        multiDexEnabled true
    }
    ...
}

dependencies {
    implementation "androidx.multidex:multidex:2.0.1"
}
Copy the code
  • Not using AndroidX(deprecated)
android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 30 multiDexEnabled true } ... } dependencies {implementation 'com. Android. Support: multidex: 1.0.3'}Copy the code

2. Depending on whether you overwrite the Application class, do one of the following:

  • If you do not override the Application class, edit your manifest file to set Android :name in the < Application > tag, as shown below:
<? The XML version = "1.0" encoding = "utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.scc.demo"> <application android:name="androidx.multidex.MultiDexApplication" > ... </application> </manifest>Copy the code
  • If you doOverrides the Application class, please change it to an extensionMultiDexApplication(Not required), as follows:
public class MyApplication extends MultiDexApplication { ... }
Copy the code
  • Or, if you doThe Application class is overridden but the base class cannot be changedThen you canCover attachBaseContext ()Methods andcallMultiDex.install(this)To enable Multidex:
public class MyApp extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); }}Copy the code

Note: Do not execute Multidex.install () or any other code via reflection or JNI until multidex.install () is complete. The Multidex trace does not follow these calls, resulting in a ClassNotFoundException or validation error due to class partitioning errors between DEX files.

Now, when you build your application, the Android build tool builds a primary DEX file (classes.dex) and supported DEX files (classes2.dex, classes3.dex, etc.) as needed. Build the system and then package all the DEX files into your APK.

At run time, the Multidex API uses special classloaders to search all available DEX files to find your method (instead of just searching in the main classes.dex file).

Limitations of the Multidex library

The Multidex library has some known limitations that you should be aware of and test when incorporating them into your application build configuration:

  • Installing the DEX file to the data partition of the device during startup is complex, and if the secondary DEX file is large, it may result in an application unresponsive (ANR) error. To avoid this problem, enable code shrinkage to minimize the size of the DEX file and remove unused portions of the code.
  • When running on versions of Android prior to 5.0 (API level 21),Using Multidex is not enough to solve the LinearAlloc limit (Problem 78035). This limitation was increased in Android 4.0 (API level 14), but it is not completely resolved. On versions younger than Android 4.0, you may reach the linear allocation limit before reaching the DEX index limit. So if your goalAPI level below 14, please do it on these versions of the platformThorough testingBecause your application may have problems at startup or when loading a particular class group.

Code reduction can reduce or possibly eliminate these problems.

Declare the required classes in the main DEX file

If you receive a Java. Lang. NoClassDefFoundError, then you have to pass in building types used in multiDexKeepFile or multiDexKeepProguard attributes declare them, These additional classes are specified manually as required in the main DEX file. If a class matches in the multiDexKeepFile or multiDexKeepProguard file, the class is added to the main DEX file.

MultiDexKeepFile properties

Your file should be specified in the multiDexKeepFile which each row contains a class, format for com/example/MyClass. Class. For example, you could create a file multidex-config.txt like this:

com/scc/MyClass.class
com/scc/MyOtherClass.class
Copy the code

You can then declare the file for the build type, as follows:

android { buildTypes { release { multiDexKeepFile file('multidex-config.txt') ... }}}Copy the code

Note: Gradle reads the path relative to the build. Gradle file, so the above example works if multidex-config. TXT is in the same directory as the build. Gradle file.

MultiDexKeepProguard properties

The multiDexKeepProguard file uses the same format as Proguard and supports the entire Proguard syntax.

The file you specify in multiDexKeepProguard should contain the -keep option in any valid ProGuard syntax. For example, -keep com.scc.myclass.class. You can create a file called multidex-config.pro, as shown below:

-keep class com.scc.MyClass
-keep class com.scc.MyClassToo
Copy the code

To specify all the classes in the package, the file would look like this:

-keep class com.scc.** { *; } // all classes in the com.scc packageCopy the code

You can then declare the file for the build type as follows:

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

Optimize Multidex in development releases

To reduce longer incremental build times, use pre-dexing to reuse the Multidex output between builds. Pre-dexing relies on the ART format available only on Android 5.0 (API level 21) and later. If you are using Android Studio 2.3 or later, the IDE will automatically use this feature when deploying your application to a device running Android 5.0 (API level 21) or higher.

Note: Android plug-ins for Gradle 3.0.0 and higher include further improvements to optimize build speed, such as dexing by class (so that only the classes you modify are re-indexed). In general, you should always upgrade to the latest version of Android Studio and Android plug-ins for the best development experience.

However, if you are running Gradle builds from the command line, you need to set minSdkVersion to 21 or higher to enable pre-dexing. A useful strategy for preserving production version Settings is to create two versions of the application using production style: development style and release style, with different values of minSdkVersion, as shown below.

android { defaultConfig { ... MultiDexEnabled True // Lowest API level. MinSdkVersion 15} productFlavors {dev {//(API level 21) or higher. MinSdkVersion 21} prod {// If you have defaultConfig block configured for the production version // For your application, you can leave this block blank and Gradle will use its configuration // instead of defaultConfig block. You still need to include this flavor. // Otherwise, all variants are configured with "dev". } } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard - rules. Pro' dependencies}}} {implementation "androidx. Multidex: multidex: 2.0.1"}Copy the code

Avoid the 64K limit

Before configuring an application to enable 64K or more method references, you should take steps to reduce the total number of references invoked by the application code, including methods defined by the application code or contained libraries. The following policies can help you avoid reaching the DEX reference limit:

  • Check your application’s direct and pass-through dependencies– Ensure that any large library dependencies you include in your application are used in a way that exceeds the amount of code added to your application. A common anti-pattern is to include a very large library because some utility method is useful. Reducing your application code dependencies can often help you avoid DEX reference restrictions.
  • Use R8 to remove unused code– Enable code shrink to run R8 for your release. Enabling shrink ensures that you do not send unused code with the APK.

Using these techniques may help you avoid enabling Multidex in your application, while also reducing the overall size of the APK.

That’s all for this article, hoping to help and inspire you to learn Android Multidex.