TL;DR
あなたのアプリ(依存しているすべてのライブラリを含む)が65,536個のメソッド参照数を超えました。これは単一のDEXファイルの上限です。修正方法はminSdkによって異なります:
- minSdk < 21:
build.gradleでMultiDexを有効にし、MultiDexApplicationを継承します。 - minSdk ≥ 21:ARTが複数のDEXファイルをネイティブで処理します。
multiDexEnabled trueを設定するだけで完了です。 - いずれの場合も、R8シュリンキングを有効にしてください。リリースビルドで参照数を大幅に削減できます。
エラーの詳細
AGPBI: {"kind":"error","text":"The number of method references in a .dex file cannot exceed 64K.",
"sources":[{}],"tool":"Dexer"}
...
com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
このエラーはGradleビルド中、コンパイルが成功した後のdexingステップで発生します。通常、重い依存関係(Firebase、Google Play Services、またはRetrofit + OkHttpのフルスタックなど)を追加した直後に現れます。
発生する原因
DEXフォーマットはメソッドの参照に16ビットのインデックスを使用します。これにより上限はちょうど65,536(0xFFFF + 1)に制限され、例外はありません。現代のアプリはこの上限を予想以上に早く超えてしまいます。Google Play Servicesだけで以前は約20,000個の参照を消費していました。Retrofit、Room、いくつかのFirebaseモジュールを追加すると、ビジネスロジックを1行も書く前に上限を超えてしまいます。
ビルドが失敗する前に現在の状況を確認したい場合は、dexcountプラグインをインストールしてください:
# build.gradle (プロジェクトレベル)
buildscript {
dependencies {
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:4.0.0'
}
}
# build.gradle (アプリレベル)
apply plugin: 'com.getkeepsafe.dexcount'
次に./gradlew assembleDebugを実行します。プラグインがビルド出力にパッケージごとのメソッド数の内訳を表示します。
修正1 — minSdk ≥ 21(最も簡単な方法)
ART(Android 5.0以上)は複数のDEXファイルをデフォルトで読み込みます。必要なのは1つのフラグだけです:
// app/build.gradle
android {
defaultConfig {
minSdk 21
multiDexEnabled true
}
}
追加の依存関係は不要です。Applicationクラスの変更も不要です。同期して再ビルドするだけです。
修正2 — minSdk < 21(レガシーサポート)
古いDalvikデバイスでは、MultiDexサポートライブラリを手動で組み込む必要があります。
ステップ1 — 依存関係を追加する:
// app/build.gradle
android {
defaultConfig {
minSdk 16
multiDexEnabled true
}
}
dependencies {
implementation 'androidx.multidex:multidex:2.0.1'
}
ステップ2 — Applicationクラスを更新する。
オプションA — MultiDexApplicationを直接継承する(カスタムベースクラスをまだ持っていない場合の最も簡単な方法):
// Kotlin
class MyApp : MultiDexApplication() {
// 既存のコード
}
// Java
public class MyApp extends MultiDexApplication {
// 既存のコード
}
オプションB — 代わりにattachBaseContextをオーバーライドする(すでに他のクラスを継承していて親クラスを変更できない場合に使用):
// Kotlin
class MyApp : SomeOtherBaseApp() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
// Java
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
ステップ3 — AndroidManifest.xmlに登録する(デフォルトのApplicationを使用していない場合):
<application
android:name=".MyApp"
...>
修正3 — R8でシュリンクする(どの修正を選んでも実施すること)
MultiDexによってビルドが通るようになります。しかし、メソッド数が多いと問題が残ります。Android 4.x では、コールドスタート時に複数のDEXファイルを読み込むことで、起動時間が200〜500ms余分にかかる場合があります。R8はDEXステージに到達する前にデッドコードを除去します:
// app/build.gradle
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
debug {
// 64K上限に近い場合はここでも有効にする
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
R8はAGP 3.4以降でデフォルトになっています。古い環境では、gradle.propertiesに以下の行を追加してください:
android.enableR8=true
修正4 — 依存関係を見直す
実際に使用している量よりはるかに多くをインポートしていることが本当の問題の場合があります。よくある原因をいくつか挙げます:
- Google Play Servicesのモノリス:
com.google.android.gms:play-servicesはすべてを引き込みます(約36,000個の参照)。必要なものだけをインポートしてください。Mapsにはplay-services-maps、サインインにはplay-services-authなど。 - 重複する推移的依存関係:
./gradlew app:dependenciesを実行し、同じライブラリが複数のバージョンで現れていないか確認してください。重複するたびに参照数が増えます。 - 古いサポートライブラリ:まだ
com.android.supportを使用している場合、AndroidXに移行することで参照数が削減されます。書き直されたアーティファクトはよりスリムです。
# リリースビルドの完全な依存関係ツリー
./gradlew app:dependencies --configuration releaseRuntimeClasspath
# パッケージごとのメソッド数(dexcountプラグインが必要)
./gradlew assembleDebug
修正が効いたか確認する
./gradlew assembleDebugを実行します — DexIndexOverflowExceptionが消えているはずです。- ビルド出力で
1 DEX file writtenまたは2 DEX files writtenを確認し、MultiDexが有効になっていることを確かめます。 - Android 4.xデバイスまたはエミュレーター(pre-21をサポートしている場合)でテストし、
ClassNotFoundExceptionなしにアプリが起動することを確認します。 - Android StudioでBuild → Analyze APKを開き、パッケージごとのDEXサイズとメソッド数を確認します。
MultiDex有効化後のよくある落とし穴
- Android < 5.0でのコールドスタートの遅延:最初の起動時にAPKからセカンダリDEXファイルが展開されます。低スペックのハードウェアでは2〜5秒かかる場合があります。スプラッシュスクリーンを使用するか、初期化を遅らせて遅延を隠してください。
- 実行時のClassNotFoundException:Applicationクラスより前に読み込まれるクラス(カスタムContentProviderなど)がセカンダリDEXに配置される場合があります。
multiDexKeepProguardまたはmultiDexKeepFileを使用してプライマリDEXに固定してください。 - インクリメンタルビルドがまだ失敗する:古いDEXキャッシュがMultiDex追加後にエラーを引き起こす場合があります。
./gradlew cleanを実行してフルリビルドを行ってください。
# クラスをプライマリDEXに固定する:
# app/build.gradle
android {
defaultConfig {
multiDexEnabled true
multiDexKeepFile file('multidex-config.txt')
}
}
# multidex-config.txt
com/example/MyContentProviderHelper.class

