Introducing and configuring MultiDex and improving build efficiency

Posted by goldberg on Fri, 12 Jul 2019 20:02:07 +0200

MultiDex

Recently, optimize upgrade project, finally reported the 64K method limit problem, and record the solution conveniently;

Reasons for 64K limit

The Android APK file is essentially a compressed file that contains the classes.dex file, an executable Dalvik byte code file that holds all the compiled Java code.The Dalvik executable specification limits the maximum number of methods a single DEX file can drink to 65536, including the Android Framework, third-party libraries referenced by APP, and its own methods (which feels like a design mistake);

Use MultiDex to resolve 64K restrictions

Before Android 5.0

Before 5.0, the system used a Dalvik virtual machine to execute Android applications. Dalvik generated only one DEX file for each APK. To avoid exceeding the 64K limit, we could only split one DEX into several dex, similar to classes.dex,classes2.dex,classes3.dex. When the application started, the program loaded the main DEX first, and then the main dex.Add it to the other Dex in turn; Google has launched a library called MultiDex Support Library, which can be found under / extras/android/support/mulidex/;

After Android 5.0

After 5.0, the system began to use ART's virtual machine instead of Dalvik's. ART naturally supports APK to load multiple dex files. It can scan all dex files directly and compile them into an oat file, referring to loading oat directly instead of one loading dex file.

Configuring with MultiDex

MultiDex is mainly configured in Gradle files, but you do not only need to configure Gradle files in Module, but also Gradle files in the project root directory.
First, let's configure the Gradle file in Module with the following code:

apply plugin: 'com.android.application'

android {
    // productFlavors are two sets of run configurations set up to avoid reloading the DEX once per run
    productFlavors {
        dev {
            minSdkVersion 21
        }
        prod {
            minSdkVersion 14
        }
    }
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.example.itgungnir.testmultidex"
        minSdkVersion 11
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        // Set MultiDex Available
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    // Ensure that other LIBS are not preDex
    dexOptions {
        preDexLibraries = false
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
    // MultiDex Dependency
    compile 'com.android.support:multidex:1.0.1'
}

After configuring the Gradle file under Module, configure the Gradle file under Project s.The code in the file is as follows:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

// Ensure that all files specified in the dex_files file are loaded into Main Dex
afterEvaluate {
    tasks.matching {
        it.name.startsWith('dex')
    }.each { dx ->
        if (dx.additionalParameters == null) {
            dx.additionalParameters = []
        }
        dx.additionalParameters += '--multi-dex'
        dx.additionalParameters += "--main-dex-list=$projectDir/dex_files".toString()
    }
}

As you can see, there is mainly a block of afterEvaluate code added here, and dex_files on the last line is a.Txt file that holds all the files you want to load into MainDex by default.This dex_files file is in the same directory as this Gradle file. Here is the code in the dex_files.txt file (you can add it as needed):

android/support/multidex/BuildConfig/class
android/support/multidex/MultiDex$V14/class
android/support/multidex/MultiDex$V19/class
android/support/multidex/MultiDex$V4/class
android/support/multidex/MultiDex/class
android/support/multidex/MultiDexApplication/class
android/support/multidex/MultiDexExtractor$1/class
android/support/multidex/MultiDexExtractor/class
android/support/multidex/ZipUtil$CentralDirectory/class
android/support/multidex/ZipUtil/class

Finally, you need to inject MultiDex into the project's Application file with the following code:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // Inject MultiDex into the project
        // The attachBaseContext method is executed before onCreate.Is the way developers can control the earliest execution of an application
        MultiDex.install(this);
    }
}

Finally, remember to configure Application in Manifest

Improving build efficiency

After adding MultiDex to your project, you click the Build button and find that it's not as fast as it used to be; if it's a very large application, it's incredibly fast; to reduce the build time added by pouring MultiDex into the development phase, we can use productFlavors to build it in the main module build.gradle file of the projectTwo flavor s, one for development and one for production;

android{
      productFlavors{
             dev{
                    //Smiling Version in Development
                    minSdkVersion 21
             }
             prod{
                    //Actual minimum version of app
                    minSdkVersion 14
             }
      }
}

Once the above configuration is complete, we can use devDebug variant to build our application, which combines the configuration of dev's productFlavor with debug's buildType, that is, the resulting APK will not use ProGuard;

Next we show how to use devDebug, a Build Variant, using the command line:

./gradlew installDevDebug

In Android Studio, click Build Variant on the right to open the corresponding module and select devDebug.

Topics: Android Gradle Junit Java