Demasiadas clases en main main-dex-list, la capacidad principal dex excedida


Estoy tratando de ejecutar casos de prueba de instrumentación, pero obtener el error a continuación, mientras que la conversión dex EXCEPCIÓN INESPERADA DE NIVEL SUPERIOR:

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

¿Cómo resolver este problema en gradle?

Author: Prudhvi, 2015-09-22

3 answers

Primero entendamos el problema:

En dispositivos pre-Lollipop, el framework solo carga main dex. Para soportar aplicaciones multi-dex, debe parchear explícitamente application class loader con todos los archivos secundarios dex (esta es la razón por la que su clase de aplicación tiene que extender MultiDexApplication class o llamar MultiDex#install).

Esto significa que el dex principal de su aplicación debe contener todas las clases que son potencialmente accesibles antes de parchear el cargador de clases.

Recibirá java.lang.ClassNotFoundException si el código de su aplicación intentará hacer referencia a una clase que se empaquetó en uno de sus archivos dex secundarios antes de parchear con éxito el cargador de clases de la aplicación.

He documentado aquí cómo el plugin decide qué clases deben empaquetarse en main-dex.
Si la cantidad total de métodos a los que hacen referencia esas clases excede el límite de 65,536, entonces la compilación fallará con Too many classes in --main-dex-list, main dex capacity exceeded error.

Se me ocurren tres posibles soluciones para este problema:

  1. (La solución más fácil, pero no adecuada para la mayoría de los aplicaciones) Cambie su minSdkVersion a 21.
  2. Reduzca el código de su aplicación. Esto fue discutido muchas veces anteriormente (ver aquí y aquí).
  3. Si ninguna de las soluciones anteriores funciona para usted, puede intentar usar mi solución para este problema : estoy parcheando el gradle de Android plugin para no incluir clases de actividad en dex principal. Es un poco raro, pero funciona bien para mí.

Hay un problema en Android bug Tracker con respecto a este error. Esperamos que el equipo de Herramientas proporcione una mejor solución pronto.


Actualizar (4/27/2016)

La versión 2.1.0 del complemento Gradle permite filtrar las clases de la lista main-dex.
Advertencia: esto está utilizando una api no compatible que se reemplazará en el futuro.

Para ejemplo, para excluir todas las clases de actividad puedes hacer:

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

También puede comprobar mi proyecto de ejemplo que demuestra este problema (y aplica el filtrado anterior).


Actualizar 2 (7/1/2016)

La versión 2.2.0-alpha4 del complemento Gradle (con build-tools v24) finalmente resuelve este problema al reducir la lista de mantenimiento multidex a un mínimo .
El filtro no soportado (e indocumentado) de la versión 2.1.0 ya no debería usarse. He actualizado mi proyecto de ejemplo, que demuestra que la compilación tiene éxito ahora sin ninguna lógica de compilación personalizada.

 21
Author: Alex Lipov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:56

Otra forma de resolver este problema es eliminar clases con anotaciones en tiempo de ejecución del archivo principal DEX:

android {

    dexOptions {
        keepRuntimeAnnotatedClasses false
    }

}

Esto es particularmente útil para las aplicaciones que están utilizando marcos de inyección de dependencias, ya que incluso para las anotaciones de Dagger generalmente se mantienen en tiempo de ejecución.

 18
Author: Dmitry Zaytsev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-24 11:58:35

Tienes dos opciones.

  1. utilice ProGuard para eliminar el número de métodos
  2. utilice la función multidex

Mi consejo-ir con ProGuard, requiere tan poco como cero cambios en el código fuente

 -1
Author: vigilancer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-23 01:05:06