J'essaie d'exécuter des cas de test d'instrumentation mais j'obtiens l'erreur ci-dessous lors de la conversion dex EXCEPTION INATTENDUE DE HAUT NIVEAU:
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
Comment résoudre ce problème en gradle?
Comprenons d'abord le problème:
Sur les appareils pré-Lollipop, seul le dex principal est chargé par le framework. Pour prendre en charge les applications multi-dex, vous devez patcher explicitement le chargeur de classe d'application avec tous les fichiers dex secondaires (c'est pourquoi votre classe Application doit étendre la classe MultiDexApplication ou appeler MultiDex # install =).
Cela signifie que le dex principal de votre application doit contenir toutes les classes potentiellement accessibles avant l'application de correctifs au chargeur de classe.
Vous recevrez Java.lang.ClassNotFoundException si votre code d'application essaie de référencer une classe qui a été empaquetée dans l'un de vos fichiers dex secondaires avant de patcher avec succès le chargeur de classe d'application.
J'ai documenté ici comment le plugin décide quelles classes doivent être empaquetées dans main-dex.
Si le nombre total de méthodes référencées par ces classes dépasse la limite de 65 536, la génération échouera avec Too many classes in --main-dex-list, main dex capacity exceeded
Erreur.
Je peux penser à trois solutions possibles à ce problème:
Il y a n problème dans Android bug tracker concernant cette erreur. J'espère que l'équipe Tools fournira bientôt une meilleure solution.
Mise à jour (27/04/2016)
La version 2.1.0 du plugin Gradle permet de filtrer les classes de liste main-dex.
Attention: ceci utilise une API non prise en charge qui sera remplacée à l'avenir.
Par exemple, pour exclure toutes les classes d'activités, vous pouvez:
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
}
}
}
}
}
Vous pouvez également vérifier mon exemple de projet qui illustre ce problème (et applique le filtrage ci-dessus).
Mise à jour 2 (01/07/2016)
La version 2.2.0-alpha4 du plugin Gradle (avec build-tools v24) résout enfin ce problème en réduisant la liste de conservation multidex au minimum .
Le filtre non pris en charge (et non documenté) de 2.1.0 ne devrait plus être utilisé. J'ai mis à jour mon exemple de projet , démontrant que la construction réussit maintenant sans aucune logique de construction personnalisée.
Une autre façon de résoudre ce problème consiste à supprimer les classes avec des annotations d'exécution du fichier DEX principal:
Android {
dexOptions {
keepRuntimeAnnotatedClasses false
}
}
Cela est particulièrement utile pour les applications qui utilisent des infrastructures d'injection de dépendances, car même pour les annotations Dagger, elles sont généralement conservées lors de l'exécution.