Too many classes in --main-dex-list, main dex capacity exceeded
Asked Answered
H

3

28

I'm trying to run instrumentation test cases but getting the below error while dex conversion UNEXPECTED TOP-LEVEL EXCEPTION:

com.android.dex.DexException: Too many classes in --main-dex-list, main dex capacity exceeded
        at com.android.dx.command.dexer.Main.processAllFiles(Main.java:494)
        at com.android.dx.command.dexer.Main.runMultiDex(Main.java:334)
        at com.android.dx.command.dexer.Main.run(Main.java:244)
        at com.android.dx.command.dexer.Main.main(Main.java:215)
        at com.android.dx.command.Main.main(Main.java:106)

:App:dexDebug FAILED

How to resolve this issue in gradle?

Honghonied answered 22/9, 2015 at 15:35 Comment(1)
You are probably using Google Play Services. If you are using Android Studio, try to only use the subcomponents you need (like ads, games etc.), not all at once. It's a known issue and it is hardly going to be fixed in near future. The issue is that Dalvik only support 65535 (2^16 - 1) classes. Once all devices are using native ART, it's not going to be a problem anymore.Westbrook
E
25

Let's first understand the problem:

On pre-Lollipop devices, only main dex is being loaded by the framework. To support multi-dex applications you have to explicitly patch application class loader with all the secondary dex files (this is why your Application class have to extend MultiDexApplication class or call MultiDex#install).

This means that your application's main dex should contain all the classes that are potentially accessible before class loader patching.

You will receive java.lang.ClassNotFoundException if your application code will try to reference a class that was packaged in one of your secondary dex files before successfully patching application class loader.

I've documented here how plugin decides which classes should be packaged in main-dex.
If total amount of methods that those classes are referencing exceeds the 65,536 limit, then build will fail with Too many classes in --main-dex-list, main dex capacity exceeded error.

I can think of three possible solutions for this issue:

  1. (The easiest solution, but not suitable for most of the applications) Change your minSdkVersion to 21.
  2. Shrink your application code. This was discussed many times previously (see here and here).
  3. If none of the above solutions work for you, you can try to use my workaround for this issue - I'm patching the Android gradle plugin to not include Activity classes in main dex. It's a bit hacky, but works well for me.

There's an issue in Android bug tracker regarding this error. Hopefully the Tools team will provide a better solution soon.


Update (4/27/2016)

Version 2.1.0 of Gradle plugin allows to filter main-dex list classes.
Warning: this is using an unsupported api that will be replaced in the future.

For example, to exclude all activity classes you can do:

afterEvaluate {
  project.tasks.each { task ->
    if (task.name.startsWith('collect') && task.name.endsWith('MultiDexComponents')) {
      println "main-dex-filter: found task $task.name"
      task.filter { name, attrs ->
        def componentName = attrs.get('android:name')
        if ('activity'.equals(name)) {
          println "main-dex-filter: skipping, detected activity [$componentName]"
          return false
        } else {
          println "main-dex-filter: keeping, detected $name [$componentName]"
          return true
        }
      }
    }
  }
}

You can also check my example project that demonstrates this issue (and applies the above filtering).


Update 2 (7/1/2016)

Version 2.2.0-alpha4 of Gradle plugin (with build-tools v24) finally solves this issue by reducing multidex keep list to a minimum.
The unsupported (and undocumented) filter from 2.1.0 should not be used anymore. I've updated my sample project, demonstrating that build succeeds now without any custom build logic.

Ewing answered 25/9, 2015 at 10:46 Comment(11)
Hi, I had to use the same patch as well. But what is the root cause of this issue? And any idea how to avoid this?Honghonied
I've edited my answer, please let me know if you have further questions.Ewing
Thanks it helped a lot.Honghonied
Hi, I decided to go with proguard to cut down the number of methods. And with plugin 1.3.1 I'm able to generate the apk without the patch code. But with latest 2.0.0 plugin I'm unable to do so. I'm ending getting the same error. Why it works well in 1.3.1 but in 2.0.0 ?Honghonied
You can use my workaround patch till the issue resolved. To better understand why you're receiving different results with 1.3.1 and 2.0.0 versions: are you building using Android Studio or directly with gradlew from the command line? I'm asking because if you're building with AS 2.0 with Instant Run enabled - it will add about 140 methods + 3*class# to your dex in debug builds. Can you try to run ./gradlew clean assembleRelease and inform me on results?Ewing
I'm not using Android studio. I'm directly running on Gradle. Gradle clean assembleDebug. I enabled proguard for debug buildType. Realease build works well even in 2.0.0 but debug build fails.Honghonied
I see. Can you compare app/build/intermediates/multi-dex/{variant}/maindexlist.txt files (where variant is debug or release) between release and debug builds (and maybe also between v2.0 release to v.1.3.1 release)? This file governs which classes will be included in main-dex.Ewing
For debug build, there are few entries with name "-keep class classname" is present in 1.3.1 maindexlist file and missing in 2.0.0 . There are no other differences. And one more observation is, both 1.3.1 and 2.0.0 removes same number of classes.Honghonied
Yeah, it doesn't help much. At this step I'd download the dx tool sources and debug it with your project's build parameters (look for dx invocation command in your build logs). It's maybe a long way, but by doing this you will be able to find the root cause of your problem.Ewing
Thank you so much for your suggestions. I feel that few methods are getting added with the new plugin version. As you mentioned i should wait for the issue to be fixed.Honghonied
Very very helpful, thanks man!! I owe you a beer (if you do take it) hahahahaSigne
D
24

One other way to resolve this issue is to remove classes with Runtime annotations from the main DEX file:

android {

    dexOptions {
        keepRuntimeAnnotatedClasses false
    }

}

This is particularly helpful for applications which are using dependency injection frameworks since even for Dagger annotations are usually kept in runtime.

Dissatisfaction answered 12/12, 2016 at 9:27 Comment(3)
Thanks! This helps. I already had the following dexOptions listed additionalParameters += '--minimal-main-dex' additionalParameters += '--set-max-idx-number=50000'Saffron
Hello! Have you ever run into any issues or crashes because of keepRuntimeAnnotatedClasses false?Devi
@Devi nope, everything was fineDissatisfaction
C
-3

You have two choices.

  1. use ProGuard to strip down number of methods
  2. use multidex feature

My advice - go with ProGuard, it require as little as zero changes to source code

Canea answered 23/9, 2015 at 1:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.