web-dev-qa-db-ja.com

--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でこの問題を解決するにはどうすればよいですか?

26

最初に問題を理解しましょう。

Lollipop以前のデバイスでは、メインdexのみがフレームワークによってロードされています。マルチdexアプリケーションをサポートするには、アプリケーションクラスローダーにすべてのセカンダリdexファイルを明示的にパッチする必要があります(これが、アプリケーションクラスが MultiDexApplication classを拡張するか、 MultiDex#install を呼び出す必要がある理由です=)。

つまり、アプリケーションのメインdexには、クラスローダーパッチを適用する前にアクセスできる可能性のあるすべてのクラスが含まれている必要があります。

Java.lang.ClassNotFoundException を受け取ります。アプリケーションクラスローダーに正常にパッチを適用する前に、アプリケーションコードがセカンダリdexファイルのいずれかにパッケージ化されたクラスを参照しようとする場合。

ここに文書化されています main-dexにパッケージ化するクラスをプラグインが決定する方法。
これらのクラスが参照しているメソッドの合計数が65,536の制限を超える場合、ビルドはToo many classes in --main-dex-list, main dex capacity exceededエラー。

この問題の3つの可能な解決策を考えることができます。

  1. (最も簡単な解決策ですが、ほとんどのアプリケーションには適していません)minSdkVersionを21に変更します。
  2. アプリケーションコードを縮小します。これは以前に何度も議論されました( here および here を参照)。
  3. 上記の解決策のどれもうまくいかない場合は、この問題に 私の回避策 を使用しようとすることができます-Android gradleプラグインにActivityクラスを含めないようにパッチを当てていますちょっとハックですが、私にはうまくいきます。

問題 in Androidこのエラーに関してバグトラッカーがあります。ツールチームがより良い解決策を提供することを願っています。


更新(2016年4月27日)

Gradleプラグインのバージョン2.1.0では、メイン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
        }
      }
    }
  }
}

また、この問題を示す(そして上記のフィルタリングを適用する)my example project を確認することもできます。


Update 2(2016年7月1日)

Gradleプラグインのバージョン2.2.0-alpha4(build-tools v24を使用)は、最終的にこの問題を multidexキープリストを最小限に抑える で解決します。
2.1.0でサポートされていない(ドキュメント化されていない)フィルターは使用しないでください。 サンプルプロジェクト を更新し、カスタムビルドロジックなしでビルドが成功することを実証しました。

23
Alex Lipov

この問題を解決するもう1つの方法は、メインDEXファイルからランタイムアノテーションを持つクラスを削除することです。

Android {

    dexOptions {
        keepRuntimeAnnotatedClasses false
    }

}

これは、依存関係注入フレームワークを使用しているアプリケーションでは特に便利です。Daggerアノテーションの場合でも、通常は実行時に保持されるためです。

22
Dmitry Zaytsev