Подтвердить что ты не робот

Слишком много классов в --main-dex-list, основная емкость dex превышена

Я пытаюсь запустить тестовые тесты, но получаю следующую ошибку при преобразовании dex НЕОПРЕДЕЛЕННОЕ ИСКЛЮЧЕНИЕ ТОП-УРОВНЯ:

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?

4b9b3361

Ответ 1

Позвольте сначала понять проблему:

В устройствах с предварительным Lollipop загружается только основной файл dex. Чтобы поддерживать приложения с несколькими деками, вам необходимо явно установить загрузчик классов приложений со всеми вторичными файлами dex (вот почему ваш класс приложения должен расширять MultiDexApplication или вызов MultiDex # install).

Это означает, что основной дескриптор приложения должен содержать все классы, которые потенциально доступны перед патчем загрузчика классов.

Вы получите java.lang.ClassNotFoundException, если ваш код приложения попытается ссылаться на класс, который был упакован в один из ваших дополнительных файлов dex, прежде чем успешно исправлять класс приложения погрузчик.

Я документировал здесь, как плагин решает, какие классы должны быть упакованы в main-dex.
Если общее количество методов, на которые ссылаются эти классы, превышает предел 65 536, тогда сборка завершится с ошибкой Too many classes in --main-dex-list, main dex capacity exceeded.

Я могу представить три возможных решения этой проблемы:

  • (Самое простое решение, но не подходит для большинства приложения) Измените minSdkVersion на 21.
  • Сократите свой код приложения. Это обсуждалось много раз ранее (см. здесь и здесь).
  • Если ни одно из вышеперечисленных решений не работает для вас, вы можете попытаться использовать мой обходной путь для этой проблемы - я исправляю Android gradle, чтобы не включать классы активности в основной файл. Это немного хаки, но хорошо работает для меня.

Здесь проблема в отслеживании ошибок Android в отношении этой ошибки. Надеемся, что команда Tools скоро предложит лучшее решение.


Обновление (4/27/2016)

Версия 2.1.0 плагина gradle позволяет фильтровать классы списка main-dex.
Предупреждение: здесь используется неподдерживаемый api, который будет заменен в будущем.

Например, чтобы исключить все классы активности, которые вы можете выполнить:

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

Вы также можете проверить проект , который демонстрирует эту проблему (и применяет вышеуказанную фильтрацию).


Обновление 2 (7/1/2016)

Версия 2.2.0-alpha4 из gradle плагина (с встроенными инструментами v24), наконец, решает эту проблему уменьшает список ведомых файлов с минимальным значением.
Неподдерживаемый (и недокументированный) фильтр из 2.1.0 больше не должен использоваться. Я обновил свой образец проекта, продемонстрировав, что сборка успешно завершена без какой-либо пользовательской логики сборки.

Ответ 2

Еще один способ решить эту проблему - удалить классы с аннотациями Runtime из основного файла DEX:

android {

    dexOptions {
        keepRuntimeAnnotatedClasses false
    }

}

Это особенно полезно для приложений, которые используют рамки внедрения инъекций, поскольку даже для аннотаций Dagger обычно хранятся во время выполнения.

Ответ 3

У вас есть два варианта.

  • используйте ProGuard для удаления ряда методов.
  • использовать функцию multidex

Мой совет - зайдите в ProGuard, он потребует всего лишь нулевых изменений в исходном коде