Android 13で.NET MAUIアプリが「互換性がありません」でインストールできない原因と解決策(ABI/RIDとAAB/APKの正しい設定)

Android 13 端末に .NET MAUI アプリを入れようとして「App not installed as app isn’t compatible with your phone(お使いの端末と互換性がありません)」と表示された――開発・検証中にもっとも遭遇しやすい落とし穴です。本記事では、原因を正確に切り分けるための再現手順、ABI/RID の正しい指定方法、AAB/APK の配布設計、adb を使った診断までを一気通貫で解説します。

目次

Android 13 端末に .NET MAUI アプリをインストールできない原因と対処

結論から言うと、多くのケースでABI(CPU アーキテクチャ)の不一致が原因です。.NET for Android(.NET MAUI を含む)は .NET 9 以降、デフォルト挙動の見直しにより、必要な Runtime Identifier(RID)を明示しないと想定の ABI がビルド物に含まれないことがあります。そのため、端末が要求するネイティブライブラリ(例:arm64-v8a)が APK もしくは配布形態に含まれていないと、Android は「互換性がない」と判断し、インストールをブロックします。

まず確認すべき要点(要約)

  • 端末の ABI(arm64-v8a / armeabi-v7a / x86_64 / x86)。
  • ビルド成果物に含まれる ABI(lib/arm64-v8a/ 等が入っているか)。
  • プロジェクトの RID 指定(<RuntimeIdentifiers>)。
  • minSdk/targetSdk(MAUI では SupportedOSPlatformVersion との整合)。
  • 署名とアップグレード要件(既存インストールと異なる署名では上書き不可)。
  • Debug か Release か(一部端末は Debug APK を拒否)。
  • 提供元不明のアプリの許可(サイドロードする場合)。

症状の具体例

  • ギャラリーやファイルアプリから APK をタップ:
    「アプリをインストールできません。お使いの端末と互換性がありません」
  • adb install:
    INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113
  • Google Play 経由の内部テスト:対象端末に配信されない(互換性要件を満たしていない)。

原因と解決策を体系的に整理

課題解決策補足
.NET 9 から 64bit アーキテクチャが既定
.NET for Android は .NET 9 以降、32bit 向け RID(android-arm, android-x86)が自動で含まれない構成になりやすく、ビルド物に必要な ABI が欠落しがち。
必要な RID を明示
*.csproj に
<RuntimeIdentifiers>android-arm;android-arm64;android-x86;android-x64</RuntimeIdentifiers>
を追加。64bit 端末のみ対象なら android-arm64;android-x64 でも可。
マルチターゲット時は Condition を付けて Android のみに適用。ビルド時に不要な ABI を除くとサイズ削減にも寄与。
APK に 32bit/64bit のいずれかが含まれないAAB 配布 or 複数 APK
Play Console 経由なら AAB をアップロードし、ストア側が端末に最適化された ABI を自動配信。サイドロード時は、必要な ABI を含む APKであることを事前検証。
zipinfo -1 app-release.apk | grep '^lib/' で含有 ABI を確認。aapt dump badging で native-code 欄も確認可能。
端末側が 32bit 限定(旧機種)ハードウェアの確認/要件に合わせ端末選定Android 12 以降は 64bit 化が強く推奨されており、32bit 限定端末は減少。長期的には 64bit に寄せる設計が現実的。
既存インストールと署名が異なる一度アンインストールしてからインストール、または同一キーで再署名Debug ビルド → Release への上書き、CI のキー切り替え等で発生。adb uninstall <packageName> を実行。
minSdkVersion/targetSdkVersion の不整合MAUI の設定値を統一:
<SupportedOSPlatformVersion> と AndroidManifest の実際の minSdk が矛盾しないように
MAUI では SupportedOSPlatformVersion が 最低サポート API の意図。プロパティの重複設定があると期待通りに反映されないことがある。
android:exported の未設定MAUI テンプレートは原則自動設定。
明示が必要なら AndroidManifest の該当 Activity/Service に付与
API 31+ では Intent Filter を持つコンポーネントに android:exported 必須。
サイドロード設定の不足端末側で「提供元不明のアプリ」を許可Android 8.0 以降はアプリごとの許可制。ファイルアプリやブラウザごとに付与が必要。

最小構成の実例(.NET MAUI / ProjectName.csproj)

&lt;PropertyGroup&gt;
  &lt;TargetFrameworks&gt;net9.0-android&lt;/TargetFrameworks&gt;

  &lt;!-- Android のみ複数 ABI を出力 --&gt;
  &lt;RuntimeIdentifiers Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'"&gt;
    android-arm;android-arm64;android-x86;android-x64
  &lt;/RuntimeIdentifiers&gt;

  &lt;!-- 既存の SupportedOSPlatformVersion は必要に応じて調整 --&gt;
  &lt;SupportedOSPlatformVersion&gt;21.0&lt;/SupportedOSPlatformVersion&gt;

  &lt;!-- 配布形式:AAB を既定にする場合 --&gt;
  &lt;AndroidPackageFormat&gt;aab&lt;/AndroidPackageFormat&gt;

  &lt;!-- Release ビルドでサイズを抑える例 --&gt;
  &lt;DebugType&gt;portable&lt;/DebugType&gt;
  &lt;AndroidUseSharedRuntime&gt;false&lt;/AndroidUseSharedRuntime&gt;
  &lt;AotAssemblies&gt;false&lt;/AotAssemblies&gt; &lt;!-- 必要に応じて true --&gt;
  &lt;EnableLLVM&gt;false&lt;/EnableLLVM&gt;
&lt;/PropertyGroup&gt;

ポイントは <RuntimeIdentifiers> を Android TFM のみに条件付きで設定することです。iOS や Windows を同時にターゲットにしている場合でも、他プラットフォームに影響しません。

端末 ABI とプロジェクト設定の対応表

端末の CPU/OSインストール可能な ABI推奨 RID 設定備考
64bit ARM(一般的な Android 13 端末)arm64-v8a(場合により armeabi-v7a も可)android-arm64(+ 互換性維持のため android-arm を追加することも)サイズ最適化で 64bit のみに絞る設計が主流
32bit ARM(旧端末)armeabi-v7aandroid-arm長期的にはサポート外にする判断も検討
x86_64 エミュレータx86_64android-x64エミュレータ検証を重視する環境で有効
x86 エミュレータ(旧)x86android-x86今からの新規対応は非推奨

ビルド・配布の実践パターン

1) AAB(Android App Bundle)で配布

Google Play Console を利用する前提であれば、AAB を一択にすると、Play が端末に合わせて最適な ABI を自動配布してくれます。サイズと互換性の両立が容易です。

dotnet publish -f net9.0-android -c Release -p:AndroidPackageFormat=aab \
  -p:RuntimeIdentifiers=android-arm64;android-arm

2) 直接 APK をサイドロード

全ての ABI を 1 つの APK に同梱することも可能ですが、サイズが膨らみます。必要な範囲に絞りましょう。

dotnet publish -f net9.0-android -c Release -p:AndroidPackageFormat=apk \
  -p:RuntimeIdentifiers=android-arm64

完成した APK に必要な ABI が入っているかは次のコマンドで確認できます。

zipinfo -1 bin/Release/net9.0-android/*Signed.apk | grep '^lib/'
aapt dump badging bin/Release/net9.0-android/*Signed.apk | grep native-code

3) Bundletool を使って分割 APK を生成・配布(上級)

AAB からローカルで .apks(分割 APK セット)を作成・検証し、手元の端末にインストールできます。

# AAB から分割 APK セットを作成
java -jar bundletool.jar build-apks \
  --bundle=app-release.aab \
  --output=app.apks \
  --mode=universal \
  --ks=my-release-key.jks --ks-pass=pass:xxxx --ks-key-alias=alias --key-pass=pass:xxxx

# 端末へインストール

java -jar bundletool.jar install-apks --apks=app.apks 

adb で端末・ログを確認する

端末がサポートする ABI を確認

adb shell getprop ro.product.cpu.abilist
adb shell getprop ro.product.cpu.abilist64
adb shell getprop ro.product.cpu.abilist32

インストール失敗時の詳細ログを確認

adb install app-release.apk
# 失敗時はログに原因が出ることが多い
adb logcat | grep -i "PackageManager" -n
# 代表例:INSTALL_FAILED_NO_MATCHING_ABIS / SIGNATURE MISMATCH など

既存アプリをクリーンにしてから再インストール

# パッケージ名は AndroidManifest もしくは aapt dump badging で確認
adb uninstall com.companyname.projectname
adb install app-release.apk

Visual Studio / VS Code での注意点

  • テンプレート直後でも安全ではない:RID が足りない・Debug 署名での上書き・AAB/APK の形態違いなどで躓く。
  • Debug 実行の限界:一部ベンダー機は Debuggable APK のサイドロードを厳格に拒否することがある。Release + 署名で検証を。
  • 複数フレームワークの混在:<TargetFrameworks> に iOS/Windows を含む場合、Android 向け設定は Condition で範囲限定。

「互換性がありません」を確実に解消するチェックリスト

  1. 端末の ABI を確認(adb shell getprop)。
  2. プロジェクトに適切な RID を追加(android-arm64 等)。
  3. Release でビルドし、AndroidPackageFormat を aab か apk へ明示。
  4. ビルド物の ABI を検証(zipinfo / aapt)。
  5. 既存ビルドとの署名差を回避:上書きで失敗するなら一度アンインストール。
  6. minSdk/targetSdk を見直し(端末の API と整合)。
  7. サイドロード許可をオン(APK を手動インストールする場合)。
  8. adb のエラーメッセージを読み、NO_MATCHING_ABIS なら ABI、SIGNATURE なら署名、MIN_SDK なら API という具合に切り分け。

トラブル別・原因の見分け方(ログの読み方)

adb / 端末メッセージ主原因対処
INSTALL_FAILED_NO_MATCHING_ABISABI が一致しない/含まれていないRID を追加し再ビルド、APK 内 lib/ フォルダの有無を確認
INSTALL_FAILED_UPDATE_INCOMPATIBLE
または「アプリをインストールできません」(上書き時)
既存アプリと署名が異なるadb uninstall でアンインストール後に再インストール、もしくは同一キーで署名
Failure [INSTALL_FAILED_OLDER_SDK]minSdkVersion が端末より高いSupportedOSPlatformVersion(最低 API)を見直し
INSTALL_PARSE_FAILED_MANIFEST_MALFORMEDManifest の記述不備(android:exported など)MAUI の生成結果を確認。必要なら明示的に付与

CI/CD(GitHub Actions)の最小例

name: build-android
on:
  push:
    branches: [ main ]
jobs:
  android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '9.0.x'
      - name: Restore
        run: dotnet restore
      - name: Publish AAB (arm64 + arm)
        run: |
          dotnet publish MyApp.csproj -f net9.0-android -c Release \
            -p:AndroidPackageFormat=aab \
            -p:RuntimeIdentifiers=android-arm64;android-arm \
            -p:AndroidKeyStore=true \
            -p:AndroidSigningKeyStore=${{ secrets.ANDROID_KEYSTORE_PATH }} \
            -p:AndroidSigningStorePass=${{ secrets.ANDROID_KEYSTORE_PASS }} \
            -p:AndroidSigningKeyAlias=${{ secrets.ANDROID_KEY_ALIAS }} \
            -p:AndroidSigningKeyPass=${{ secrets.ANDROID_KEY_PASS }}

このように CI 側でも RID を明示し、署名情報をシークレットで供給すると、手元と同等の成果物を安定して生成できます。

よくある誤解とベストプラクティス

  • 「SupportedOSPlatformVersion を下げれば解決する」→誤り
    ABI 不一致が原因なら効果はありません。まず RID と APK の lib/ を検証しましょう。
  • 「android:exported を付ければ通る」→部分的
    Manifest の要件は満たせても、ABI が欠けていれば同じメッセージで失敗します。
  • 「とりあえず全部の ABI を入れる」→初期は可、徐々に絞る
    初期調査としては有効ですが、配布時は 64bit 中心へ最適化するのが現在の標準です。

プロジェクト設定の落とし穴(MAUI 固有)

  • Directory.Build.props / Directory.Build.targets による上書き
    ソリューション共通の設定が Android 用の RuntimeIdentifiers を上書きしていることがあります。MSBuild のビルドログ(dotnet build -bl)で評価結果を確認しましょう。
  • $(TargetFramework) の評価
    net9.0-android と net9.0 は別物です。条件式に $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android' を使うのが安全。
  • 複数構成の生成物が混在
    古い obj/bin が残って原因の切り分けを妨げます。dotnet clean や git clean -xdf を適宜実施。

診断の全体フロー(保存版)

  1. クリーン:dotnet clean、bin/ と obj/ を削除。
  2. RID を追加:android-arm64(必要に応じ android-arm / android-x64)。
  3. Release + 署名で aab または apk を生成。
  4. 成果物の ABI 確認:zipinfo と aapt。
  5. 端末の ABI 確認:adb shell getprop。
  6. クリーンインストール:既存アプリをアンインストールし、adb install。
  7. ログで確認:失敗なら adb logcat で原因を特定。
  8. Play 配信なら AAB で:内部テストトラックで端末別の可配性を確認。

ケーススタディ:テンプレート直後の MAUI アプリが Android 13 で入らない

質問例のように、Visual Studio Code で新規作成した MAUI テンプレートをそのまま Release ビルドし、Android 13(API 33)の物理端末へサイドロードすると互換性エラーになることがあります。以下の手順で改善します。

  1. RuntimeIdentifiers を追加
    android-arm64;android-arm を最低限指定(64bit 端末中心ならまず android-arm64)。
  2. Release + 署名でビルドし、zipinfo で lib/arm64-v8a/ の存在を検証。
  3. 端末の ABI を確認:arm64-v8a が含まれているか。
  4. 既存インストールを削除:開発中の署名違いで上書きできない場合がある。
  5. 再インストール:adb install で導入。

最小限の MSBuild/CLI コマンド集

# .NET / SDK 情報
dotnet --info

# 依存復元
dotnet restore

# Release ビルド(APK)
dotnet publish -f net9.0-android -c Release \
  -p:AndroidPackageFormat=apk \
  -p:RuntimeIdentifiers=android-arm64

# Release ビルド(AAB)
dotnet publish -f net9.0-android -c Release \
  -p:AndroidPackageFormat=aab \
  -p:RuntimeIdentifiers=android-arm64

# 署名済み APK の検証
apksigner verify --print-certs bin/Release/net9.0-android/*Signed.apk

Manifest の最適化メモ

  • android:exported:MAUI テンプレートは必要なコンポーネントに自動付与されます。独自の IntentFilter を追加した場合は、対象 Activity/Service に忘れず設定。
  • 権限:不要な権限は削除。端末によっては権限ポリシーでインストール時に警告・拒否されることがある。

パフォーマンスとサイズの観点

  • ABI を絞る:想定ユーザーが 64bit 端末中心なら android-arm64 のみにするだけで APK サイズが大幅削減。
  • AOT/LLVM:起動時間短縮のため AOT を使うとサイズ増。プロファイルガイド(PGO)と併用し、製品段階でチューニング。

まとめ

Android 13 端末で .NET MAUI アプリが「互換性がない」と表示される主因の多くは、ビルド成果物に端末が求める ABI が入っていないことです。RuntimeIdentifiers を Android ターゲットに対して明示し、Release + 署名で AAB/APK をビルド。zipinfo と aapt で成果物の ABI を確認し、adb で端末の ABI とログを照合すれば、短時間で原因を特定できます。上記の最小構成とチェックリストをそのまま適用するだけで、Android 13(API 33)端末でも .NET MAUI アプリを安定してインストールできるようになります。


付録:コピペで使えるテンプレート(完全版)

&lt;Project Sdk="Microsoft.NET.Sdk"&gt;

  &lt;PropertyGroup&gt;
    &lt;TargetFrameworks&gt;net9.0-android&lt;/TargetFrameworks&gt;
    &lt;UseMaui&gt;true&lt;/UseMaui&gt;

    &lt;!-- Android のみ ABI を定義 --&gt;
    &lt;RuntimeIdentifiers Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'"&gt;
      android-arm64;android-arm
    &lt;/RuntimeIdentifiers&gt;

    &lt;!-- 最低サポート API。必要に応じて調整 --&gt;
    &lt;SupportedOSPlatformVersion&gt;21.0&lt;/SupportedOSPlatformVersion&gt;

    &lt;!-- 配布形式(Play 配信なら aab 推奨) --&gt;
    &lt;AndroidPackageFormat&gt;aab&lt;/AndroidPackageFormat&gt;

    &lt;!-- Release 最適化(例) --&gt;
    &lt;AndroidUseSharedRuntime&gt;false&lt;/AndroidUseSharedRuntime&gt;
    &lt;AotAssemblies&gt;false&lt;/AotAssemblies&gt;
    &lt;EnableLLVM&gt;false&lt;/EnableLLVM&gt;
  &lt;/PropertyGroup&gt;

  &lt;ItemGroup&gt;
    &lt;MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" /&gt;
  &lt;/ItemGroup&gt;

&lt;/Project&gt;

この設定から開始し、対象ユーザーの端末分布に合わせて RuntimeIdentifiers を最適化していくのが実践的です。


追加のチェックポイント(再掲・最短で直すために)

  1. Release ビルドで署名付き APK/AAB を生成(Debug は一部端末で拒否)。
  2. minSdk/targetSdk が端末より高すぎないか。
  3. 提供元不明のアプリの許可(APK 手動導入時)。
  4. adb install のエラーを確認:INSTALL_FAILED_NO_MATCHING_ABIS 等で ABI 不一致が分かる。

以上を実施すれば、Android 13 端末への .NET MAUI アプリのインストール問題は高い確率で解消できます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次