--main-dex-list 中的类太多,超出主 dex 容量 [英] Too many classes in --main-dex-list, main dex capacity exceeded

查看:29
本文介绍了--main-dex-list 中的类太多,超出主 dex 容量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试运行仪器测试用例,但在 dex 转换时出现以下错误意外的顶级异常:

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

如何在 gradle 中解决这个问题?

How to resolve this issue in gradle?

推荐答案

我们先来了解一下问题:

Let's first understand the problem:

在 Lollipop 之前的设备上,框架仅加载主 dex.要支持多 dex 应用程序,您必须使用所有辅助 dex 文件显式修补应用程序类加载器(这就是为什么您的 Application 类必须扩展 MultiDexApplication 类或调用 MultiDex#install).

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).

这意味着您的应用程序的主 dex 应该包含在类加载器修补之前可能访问的所有类.

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

如果您的应用程序代码尝试引用在成功修补应用程序类加载器之前打包在您的辅助 dex 文件之一中的类.

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.

我已经在此处记录插件如何决定哪些类应该打包在 main-dex 中.
如果这些类引用的方法总数超过 65,536 个限制,则构建将失败并出现 Too many classes in --main-dex-list, main dex capacity exceeded 错误.

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. (最简单的解决方案,但不适用于大多数应用程序) 将 minSdkVersion 更改为 21.
  2. 缩小您的应用程序代码.这在之前已经讨论过很多次(参见 这里这里).
  3. 如果以上解决方案都不适合您,您可以尝试使用 我的解决方法 解决这个问题 - 我正在修补 Android gradle 插件,使其不在主 dex 中包含 Activity 类.这有点hacky,但对我来说效果很好.
  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.

Android 错误跟踪器中存在关于此错误的一个问题.希望工具团队能尽快提供更好的解决方案.

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

更新(2016 年 4 月 27 日)

2.1.0 版的 Gradle 插件允许过滤 main-dex 列表类.
警告:这是在使用不受支持的 api,将来会被替换.

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).

更新 2(2016 年 7 月 1 日)

Gradle 插件 2.2.0-alpha4 版本(带有 build-tools v24)最终通过 将多索引保持列表减少到最低限度.
不应再使用 2.1.0 中不受支持(且未记录)的过滤器.我已经更新了我的 示例项目,证明现在构建成功,无需任何自定义构建逻辑.

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.

这篇关于--main-dex-list 中的类太多,超出主 dex 容量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆