.NET MAUIでAndroidアプリをReleaseでpublishすると、bundletoolが「Invalid dex file indices…classes2.dexが見つかる」として失敗することがあります。Xamarin時代のkeystoreを流用して署名設定を追加した直後に出やすい現象で、原因はコードではなくWindowsの地域設定(数字の形式)にあるケースが多いです。ここでは再現条件の整理から、最短で直す手順、再発防止までをまとめます。
発生するエラーと典型的な状況
次のように dotnet publish でAndroid向けに発行(公開)しようとしたタイミングで失敗します。Debugビルドでは通るのに、Release publishでだけ落ちる、というパターンが代表的です。
dotnet publish -c Release -f net6.0-android
ログには以下のようなメッセージが出ます(環境により前後は多少異なります)。
[BT : 1.8.1] error : Invalid dex file indices, expecting file 'classes?.dex' but found 'classes2.dex'
| 項目 | 内容 |
|---|---|
| 発生タイミング | Releaseでpublish(特にAAB生成や署名処理が走る工程) |
| 対象 | .NET MAUI(Android)/net6.0-android など |
| よくある前提 | Xamarin時代に作ったkeystoreを流用し、csprojに署名設定(<AndroidKeyStore>True</AndroidKeyStore>等)を追加 |
| 症状 | 「classes?.dex を期待したが classes2.dex が見つかった」とdexファイル名の整合性で弾かれる |
なぜkeystore設定後に起きやすいのか
結論から言うと、keystoreそのものが壊れているわけではありません。署名設定を入れると、publish時に「署名付きの成果物を作る」ための工程が増え、結果として AAB(Android App Bundle)の作成やbundletoolによる検証 が確実に走るようになります。この検証工程でdexファイルの並び・命名(classes.dex, classes2.dex, classes3.dex…)が厳密にチェックされ、そこで初めて問題が表面化します。
よくある現象は次のとおりです。
- Debug(APK中心)では通る
- Release publish(AAB+署名+検証)で落ちる
つまり「署名を入れたから壊れた」ではなく、「署名を入れたことで、厳密な検証を通るルートに入った」という見方が正確です。
前提知識:dexファイル名のルール(classes.dex / classes2.dex)
Androidでは、コンパイル結果のバイトコードが .dex(Dalvik Executable)としてパッケージに入ります。アプリ規模が大きいとdexが複数に分かれ(いわゆるマルチdex)、次の命名規則になります。
| dex番号 | 期待されるファイル名 | 補足 |
|---|---|---|
| 1つ目 | classes.dex | 最初は数字が付かない(classes1.dex ではない) |
| 2つ目 | classes2.dex | ここから数字が付く |
| 3つ目以降 | classes3.dex… | 連番で続く |
bundletoolはこの連番が正しいか、ファイル名が正しいかをチェックします。したがって「数字の文字が別物」になると、連番として認識できずに失敗します。
原因:classes?.dex の「?」は“数字の文字化け”であることが多い
このエラーの核心は、dexのインデックス番号部分がASCIIの「0〜9」になっていない 可能性が高いことです。
本来、2つ目のdexは classes2.dex という ASCIIの「2」 を含むファイル名になるはずです。しかし、Windowsの言語/地域設定(とくに数字の表示形式)が影響して、ビルド工程のどこかで数字がロケール依存の文字になり、結果として「見た目は2に見えるが別文字」という状態を作ります。
たとえば、数字の“表記”には次のようなバリエーションがあります。
| 見た目 | 文字の例 | よくある由来 | ASCIIの2と同一? |
|---|---|---|---|
| 2 | 2 | 英語(US)などの通常設定 | はい |
| 2 | 全角2(U+FF12) | 全角数字が混ざる環境、コピー&ペーストなど | いいえ |
| ٢ | アラビア・インド数字の2(例) | アラビア系ロケール、ネイティブ数字設定 | いいえ |
| २ | デーヴァナーガリー数字の2(例) | ヒンディー語系ロケール等 | いいえ |
ログ上は「classes?.dex」のように ? に見えますが、これは「本当は何らかの別文字なのに、ログ出力の文字コードや表示環境の都合で ? になっている」ケースが典型です。結果としてツール側は「期待している dex 名」と「実際にある dex 名」が一致しないと判断し、Invalid dex file indices で停止します。
「dexが多すぎる」問題と混同しない
Androidのビルドエラーには「メソッド数が多すぎてdexが分割される」「マルチdex設定が必要」といった別系統の話もあります。しかし今回のエラーは、dexの“数”そのものではなく、dexファイル名の整合性(インデックス)で落ちています。混同すると遠回りになります。
| よくある別エラー | 原因の方向性 | 今回(Invalid dex file indices)との違い |
|---|---|---|
| 65K制限やMultiDex関連 | 参照メソッド数、分割設定、R8/ProGuard | 「dexが作れない/入りきらない」の話で、ファイル名の文字化けとは別 |
| 署名失敗(keystore/パスワード) | 証明書・エイリアス・パスワードの不一致 | 署名工程の失敗で、dexインデックスの検証エラーではない |
| Android SDK/Build Tools不足 | SDKパス、ビルドツールの欠落 | 環境構築エラーで、特定のファイル名を期待する系とは挙動が違う |
対処:Windowsの地域設定(数値形式)を英語の0-9に揃える
回避策として最も効果が高いのは、Windowsの「地域/形式/数字」設定を英語(例:English (United States))相当にする ことです。ポイントは「表示言語」だけではなく、地域設定の“数字の形式が0-9(半角)になっていること” です。
| 設定箇所 | 推奨 | 理由 |
|---|---|---|
| 地域の形式(Regional format) | English (United States) など | 数値のフォーマットが英語の0-9になりやすい |
| ネイティブ数字(Use native digits) | 無効/使わない(Never) | ロケール依存の数字(別文字)を避けられる |
| システムロケール(非Unicodeプログラムの言語) | 必要なら英語に | 古いツールや一部の工程が影響を受ける場合がある |
Windows 11での変更手順(例)
- 「設定」→「時刻と言語」→「言語と地域」を開く
- 「地域」または「地域の形式(Regional format)」を English (United States) などに変更
- 「関連設定」から「管理用の言語設定」やコントロールパネルの「地域」を開ける場合は、追加設定(形式) で数字(ネイティブ数字)の扱いを確認
- 変更後、サインアウト/再起動を挟む(反映が曖昧な場合の保険)
Windows 10での変更手順(例)
- 「設定」→「時刻と言語」→「地域」を開く
- 「地域設定」や「地域の形式」を English (United States) に変更
- 「関連設定」→「日付、時刻、または数値形式の変更」(コントロールパネルの「地域」)を開き、形式/数字の設定を確認
数字がASCIIかどうかを確認する(PowerShell)
UIでの設定変更が難しい場合や、変更しても直らない場合は「今のカルチャで0〜9がどう扱われているか」を先に確認すると切り分けが早くなります。
$c = Get-Culture
$c.Name
$c.NumberFormat.NativeDigits
$c.NumberFormat.DigitSubstitution
NativeDigits に 0 1 2 3 4 5 6 7 8 9 以外の文字が出る場合は要注意です(見た目が似ていても別文字の可能性があります)。
重要なのは「英語表示にすること」ではなく、数字が0-9として扱われる状態にすることです。見た目が同じ“2”でも、内部的に別文字だとファイル名としては一致しません。
やり直し手順:Clean → Rebuild → publish(生成物を残さない)
設定変更後にそのままpublishし直しても、途中生成物(obj や bin)に“問題のある命名”が残っていると再発しやすくなります。次の手順で一度まっさらにしてから再実行するのが安全です。
dotnetコマンドでクリーンする
dotnet clean -c Release -f net6.0-android
dotnet publish -c Release -f net6.0-android
フォルダごと削除して完全に作り直す(推奨)
プロジェクト直下で bin と obj を削除してからpublishします。
rmdir /s /q bin
rmdir /s /q obj
dotnet publish -c Release -f net6.0-android
Visual Studioで作業している場合も、
- 「ビルド」→「ソリューションのクリーン」
- 「ビルド」→「ソリューションのリビルド」
- その後にpublish
の順に進めると、古い生成物による取りこぼしが減ります。
直ったかを確認する方法(dexファイル名を目で見る)
原因が「数字の文字」なので、成果物の中身を確認すると納得感が高まります。AABが生成できるところまで進む場合は、AABの中にあるdex名を見てください。
AABを展開して確認する
- publish後に生成された
.aabを探す(例:bin\Release\net6.0-android\publish\配下) .aabはzipなので、7-Zip等で開くbase/dex/付近にclasses.dex,classes2.dex… が並ぶか確認
コマンドで見るなら、JDKが入っている環境では次のように一覧化できます(Windowsならfindstrで絞り込み)。
jar tf YourApp.aab | findstr /i dex
jar tf YourApp.aab | findstr /i classes
もし classes2.dex のような全角数字や、見慣れない数字が混ざっていたら、まさにこの問題のパターンです。地域設定を英語の0-9に揃えてクリーンビルドすると、classes2.dex のようにASCII数字に統一されます。
言語を英語にしたのに直らないときのチェックリスト
「Windowsの表示言語を英語にしたのに直らない」という場合、表示言語ではなく“地域の形式”や“数字設定”が残っていることが多いです。次の順で潰すと切り分けが早いです。
| チェック項目 | 確認ポイント | 対処の方向性 |
|---|---|---|
| 地域の形式 | Regional format が英語(US等)になっているか | 「地域」設定を変更 |
| ネイティブ数字 | 数字がローカル表記になっていないか | 「ネイティブ数字を使わない(Never)」に寄せる |
| システムロケール | 非Unicodeプログラムの言語が影響していないか | 管理用設定で英語に変更(必要に応じて) |
| 古い生成物 | bin/objが残っていないか | bin/obj削除→再publish |
| 複数環境の混在 | 同じブランチを別PCでビルドして成果物を流用していないか | publish環境を固定し、成果物の出所を統一 |
また、ログ上の ? は“表示の問題”でもあるため、コンソールの文字コードをUTF-8にしても見た目は改善する可能性があります。しかし本件は「ファイル名の一致判定」で落ちているため、表示を直すだけでは根本解決にならない点に注意してください。
署名設定(csproj)の例と注意点
keystore流用自体は一般的な運用です。設定はプロジェクトにより異なりますが、イメージしやすいように典型例を載せます(パスやパスワードは環境に合わせてください)。
<PropertyGroup>
<AndroidKeyStore>True</AndroidKeyStore>
<AndroidSigningKeyStore>YourKeyStore.keystore</AndroidSigningKeyStore>
<AndroidSigningStorePass>******</AndroidSigningStorePass>
<AndroidSigningKeyAlias>your_alias</AndroidSigningKeyAlias>
<AndroidSigningKeyPass>******</AndroidSigningKeyPass>
</PropertyGroup>
この設定を入れたからエラーが起きるのではなく、「署名ありpublishの工程で問題が顕在化する」だけです。署名設定を外して回避するのは一時的な切り分けには有効ですが、最終的には地域設定(数字)を直して、署名ありpublishが通る状態に戻すのが本筋です。
再発防止:チーム開発・CIでハマらないための運用
この手のロケール依存バグは、個人PCの設定差で突然発生し、原因に辿り着きにくいのが厄介です。再発防止として、次の運用をおすすめします。
- publish担当マシン(またはCI)を固定し、地域設定(数字形式)を明文化する
- リリース時は必ず bin/obj削除→publish を手順に含める
- 「突然通らなくなった」時に備え、エラー文(Invalid dex file indices / classes?.dex) をチームのナレッジに残す
- 可能なら CIで署名付きAABを生成し、ローカル依存を減らす(Azure DevOps/GitHub Actions等)
特にCIは、実行環境のカルチャが安定しやすく、個人の地域設定に引きずられません。ローカルでの再現が難しい場合でも、CIで成功しているなら「環境差(ロケール差)」が疑いどころになります。
まとめ
Invalid dex file indicesでclasses?.dexと出る場合、「?」は数字の文字化けである可能性が高い- 表示言語だけでなく、地域設定の数値形式(0-9のASCII数字) を揃えるのが重要
- 設定変更後は bin/obj削除(クリーン)→Rebuild→publish を徹底する
- 成果物(AAB)を展開して
classes2.dexの“2”がASCIIになっているか確認すると確実
コードをいくら見直しても直らないタイプのエラーなので、環境(特に数字の形式)を疑うのが最短ルートです。同じ症状で詰まっている場合は、まず地域設定を見直し、クリーンからやり直してみてください。

コメント