.NET MAUI × Plugin.Firebase で「The Crashlytics build ID is missing」エラーが出る原因と解決手順【Android/iOS】

「.NET MAUI に Plugin.Firebase を入れたら実機・エミュで起動直後に The Crashlytics build ID is missing が出て落ちる」。この症状は Firebase Crashlytics のビルド工程が動いておらず、Build ID が生成されないことが原因です。本記事では Android/iOS の両方で発生要因を分解し、最短で復旧する手順、運用で再発させないための設定やデバッグ時の無効化方法、CI での注意点までを具体的なコードと設定例で解説します。

目次

発生しているエラー

Java.Lang.RuntimeException: Unable to get provider 
com.google.firebase.provider.FirebaseInitProvider: 
java.lang.IllegalStateException: The Crashlytics build ID is missing. 
This occurs when Crashlytics tooling is absent from your app's build configuration.

起動時に FirebaseInitProvider が初期化を行う段階で、Crashlytics がアプリ固有の Build ID を取得できず例外になります。Build ID は「ビルド時に Gradle/ビルドツールが生成する」ため、ビルドパイプラインに Crashlytics のツール(Gradle プラグイン等)が組み込まれていないと必ず失敗します。

原因の要点

  • Crashlytics の Build ID はビルド時に生成されるメタデータであり、実行時に自動では作られません。
  • .NET MAUI で Plugin.Firebase(ラッパー)だけを入れても、Android 側の Gradle プラグイン実行がなければ Build ID は作られません。
  • Android は com.google.gms.google-servicescom.google.firebase.crashlytics2 つのプラグイン適用が必要です。
  • iOS は CocoaPods/Framework のリンクが正しくないと初期化で落ちます(-ObjC リンカフラグや Crashlytics フレームワークの参照不備)。

最短解決チェックリスト(Android)

チェック項目OK の状態確認場所
google-services.json の配置Platforms/Android/google-services.json にあり、ビルドアクションが GoogleServicesJsonソリューションエクスプローラー → プロパティ(ビルドアクション)
Google Services プラグインが実行されるcom.google.gms.google-services が適用されるPlatforms/Android/build.gradle(後述の断片ファイル)
Crashlytics プラグインが実行されるcom.google.firebase.crashlytics が適用される同上
Plugin.Firebase の依存が最新NuGet 更新済み。競合/解決失敗なしNuGet パッケージマネージャー
クリーンビルドbin/, obj/ の削除後にビルドプロジェクト直下

対処の全体像

対処内容詳細
Crashlytics 用ツールの組み込みBuild ID が見つからないのは、Crashlytics Gradle プラグイン(com.google.firebase.crashlytics)が走っていないため。Android のモジュール(アプリ)にプラグインを適用する断片ファイルを追加し、再ビルドします。
Firebase 設定ファイルの配置Firebase コンソールで取得した google‑services.json(Android)/GoogleService‑Info.plist(iOS)を配置。
Android: Platforms/Android に置き、ビルドアクション GoogleServicesJson
iOS: Platforms/iOS に置き、ビルドアクション BundleResource
Google Services プラグイン適用Android 用ビルド断片で com.google.gms.google-services を適用し、Firebase リソースの生成を有効化。
NuGet の整合性Plugin.Firebase を最新に更新。各サブパッケージ(Auth、Analytics、Crashlytics 等)のバージョン衝突がないことを確認。
iOS 追加手順CocoaPods/Framework のリンク確認。Xcode ターゲットに -ObjC があること、FirebaseCrashlytics がリンクされていること。
デバッグのみ無効化収集をデバッグで OFF にする場合は、Android の AndroidManifest.xmlfirebase_crashlytics_collection_enabled=false を設定。iOS は Info.plist で同等のキーを設定。

手順(Android)

Firebase 設定ファイルを配置

  • Platforms/Android/google-services.json を追加。
  • ファイルの ビルドアクションを GoogleServicesJson に設定(プロパティウィンドウ)。
  • csproj で明示したい場合は次の ItemGroup を追加しておくと確実です。
<ItemGroup>
  <GoogleServicesJson Include="Platforms/Android/google-services.json" />
</ItemGroup>

Gradle プラグインを注入(ビルド断片ファイル)

.NET MAUI の Android プロジェクトでは、Platforms/Android 直下に置いた build.gradle(Groovy 断片)が最終的なアプリモジュールの build.gradle に結合されます。以下の断片を新規作成してください。

// ファイル: Platforms/Android/build.gradle  (Groovy 断片)
// Crashlytics / Google Services プラグインを使うための classpath
buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        // 例: プラグインの安定版。必要に応じてプロジェクトに合わせて更新
        classpath 'com.google.gms:google-services:4.4.2'
        classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.2'
    }
}

// <apply plugin> を使ってアプリモジュールにプラグインを適用
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics' </code></pre>

<p><strong>ポイント</strong></p>
<ul>
  <li>上記は <em>断片(fragment)</em>として結合されるため、<code>plugins { .. }</code> ブロックではなく <code>apply plugin</code> を使うのが安全です。</li>
  <li>すでに別の場所で同プラグインを適用していると「二重適用」エラーになるため、<em>適用箇所を一箇所に統一</em>してください。</li>
</ul>

<h3>AndroidManifest にメタデータ(任意)</h3>
<p>デバッグ中は Crashlytics を無効化したい場合のみ、次のメタデータを追加します(Release では外すか <code>true</code> にします)。</p>
<pre><code>&lt;application ...&gt;
  &lt;meta-data
      android:name="firebase_crashlytics_collection_enabled"
      android:value="false" /&gt;
&lt;/application&gt;
</code></pre>

<h3>クリーン &amp; 再ビルド</h3>
<ul>
  <li><code>bin/</code> と <code>obj/</code> を削除してから再ビルド(古い中間生成物が残っていると Build&nbsp;ID が更新されないことがあります)。</li>
  <li>ビルドログに <em>Crashlytics</em> のタスクが実行された痕跡(<em>Generating Crashlytics build ID</em> 等)が出力されることを確認します。</li>
</ul>

<h2>手順(iOS)</h2>
<h3>設定ファイルの配置</h3>
<ul>
  <li><code>Platforms/iOS/GoogleService-Info.plist</code> を追加し、ビルドアクションを <strong>BundleResource</strong> にします。</li>
</ul>
<h3>リンク設定の確認</h3>
<ul>
  <li>MAUI の iOS ビルドでは、Crashlytics を含む Firebase の <em>XCFramework</em> が NuGet 経由でリンクされます。Xcode プロジェクトを開き、以下を確認します。</li>
</ul>
<table>
  <thead>
    <tr>
      <th>設定</th>
      <th>内容</th>
      <th>どこで確認するか</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Other Linker Flags</td>
      <td><code>-ObjC</code> が含まれている</td>
      <td>Xcode &rarr; TARGETS &rarr; Build Settings</td>
    </tr>
    <tr>
      <td>Framework リンク</td>
      <td><code>FirebaseCrashlytics</code> 系フレームワークがリンクされている</td>
      <td>Xcode &rarr; TARGETS &rarr; General &rarr; Frameworks</td>
    </tr>
    <tr>
      <td>dSYM 生成</td>
      <td>Release で dSYM が生成される</td>
      <td>Xcode Archive/Export 設定</td>
    </tr>
  </tbody>
</table>
<h3>収集の無効化(任意)</h3>
<p>デバッグ時のみ Crashlytics を無効化するには、<code>Info.plist</code> に次のキーを追加します。</p>
<pre><code>&lt;key&gt;FirebaseCrashlyticsCollectionEnabled&lt;/key&gt;
&lt;false/&gt;
</code></pre>

<h2>Plugin.Firebase と NuGet の整合性</h2>
<p><code>Plugin.Firebase</code> は複数の Firebase SDK を内部で参照する <em>ラッパー</em>です。次を確認してください。</p>
<ul>
  <li>すべての Firebase 関連 NuGet を <strong>同一メジャー</strong>かつ最新に更新。</li>
  <li><strong>Crashlytics を使わない</strong>なら Crashlytics のパッケージを参照から外す(依存が残っていると <em>Build&nbsp;ID missing</em> が再発します)。</li>
</ul>
<table>
  <thead>
    <tr>
      <th>用途</th>
      <th>代表的なパッケージ</th>
      <th>注意点</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>コア</td>
      <td><code>Plugin.Firebase.Core</code> など</td>
      <td>最初に更新。バージョン差でランタイム例外が出やすい</td>
    </tr>
    <tr>
      <td>Crashlytics</td>
      <td><code>Plugin.Firebase.Crashlytics</code></td>
      <td>Android は Gradle プラグイン必須。iOS はフレームワークリンク確認</td>
    </tr>
    <tr>
      <td>他サービス</td>
      <td>Auth / Analytics / Messaging 等</td>
      <td>google-services.json のプレースホルダが必要(プロジェクト ID/アプリ ID)</td>
    </tr>
  </tbody>
</table>

<h2>デバッグ時のみ Crashlytics を無効化する設計</h2>
<p>チーム開発で誤ってデバッグクラッシュを送信しないために、<em>デフォルトは無効</em>、Release だけ有効にする設計が安全です。</p>
<h3>Android(Manifest でオフ)</h3>
<pre><code>&lt;!-- Debug ビルドの Manifest(ビルド構成別にファイルを分けても良い) --&gt;
&lt;application&gt;
  &lt;meta-data
      android:name="firebase_crashlytics_collection_enabled"
      android:value="false" /&gt;
&lt;/application&gt;
</code></pre>
<h3>iOS(Info.plist でオフ)</h3>
<pre><code>&lt;key&gt;FirebaseCrashlyticsCollectionEnabled&lt;/key&gt;
&lt;false/&gt;
</code></pre>
<p>必要であれば実行時に API で上書きします(Pseudocode)。</p>
<pre><code>// 例: アプリ設定のトグルで有効化する
CrossFirebaseCrashlytics.Current.SetCrashlyticsCollectionEnabled(true);
</code></pre>

<h2>Build&nbsp;ID が作られる仕組み(理解すると速い)</h2>
<p>Crashlytics の Gradle プラグインはビルド工程で</p>
<ol>
  <li>アプリとビルドに一意な <em>Build&nbsp;ID</em> を生成</li>
  <li>その ID をアプリのリソースやメタデータに書き込み</li>
  <li>(Release 時)R8 の <em>mapping.txt</em> などのシンボルを収集・アップロード</li>
</ol>
<p>実行時の Crashlytics は、この ID が無いと初期化に進めません。そのため「プラグインが回っていない = 100% 再現する」エラーです。プラグイン適用と設定ファイルの配置、これが根治策です。</p>

<h2>再発防止のためのビルド規約(チーム向け)</h2>
<ul>
  <li><strong>プロジェクトに <code>Platforms/Android/build.gradle</code> を必ず同梱</strong>し、内容にバージョンコメントを付ける。</li>
  <li>新規クローン時は <strong>必ずクリーンビルド</strong>(<code>bin/</code>, <code>obj/</code> 削除)。</li>
  <li>Firebase の設定ファイルは <strong>環境ごとに切替</strong>(Debug/Release、ステージング/本番の JSON/Plist を誤投入しない)。</li>
  <li>Crashlytics の収集は <strong>デフォルト OFF</strong>(Debug)・<strong>Release で ON</strong>。運用事故を避ける。</li>
</ul>

<h2>CI/CD(GitHub Actions / Azure Pipelines でも落ちないために)</h2>
<table>
  <thead>
    <tr>
      <th>項目</th>
      <th>推奨設定</th>
      <th>理由</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>JDK</td>
      <td>JDK 17</td>
      <td>Gradle/Android Gradle Plugin の要件に適合</td>
    </tr>
    <tr>
      <td>Gradle キャッシュ</td>
      <td>有効化。ただし <code>~/.gradle/caches</code> を時々無効化/パージ</td>
      <td>プラグイン更新時の取りこぼしを防止</td>
    </tr>
    <tr>
      <td>ビルドコマンド</td>
      <td><code>dotnet build -c Release -f net8.0-android</code></td>
      <td>MAUI の標準パイプラインで Gradle タスクが自動実行</td>
    </tr>
    <tr>
      <td>設定ファイル</td>
      <td><code>google-services.json</code> / <code>GoogleService-Info.plist</code> を<strong>安全に供給</strong>(Secure Files/Secrets)</td>
      <td>誤コミット防止と環境切替</td>
    </tr>
    <tr>
      <td>Release だけシンボル送信</td>
      <td>Debug ビルドでは Crashlytics 収集/アップロードを停止</td>
      <td>ノイズ削減とビルド時間短縮</td>
    </tr>
  </tbody>
</table>

<h2>よくあるつまずきと解決</h2>
<ul>
  <li><strong>「プラグインが二重に適用されてエラー」</strong><br>他の Gradle 断片やテンプレートと併用している場合、<code>plugins { ... }</code> と <code>apply plugin:</code> の二重適用に注意。<em>どちらか一方</em>に統一します。</li>
  <li><strong>「google-services.json を置いたがビルドが拾ってくれない」</strong><br>ビルドアクションが <code>GoogleServicesJson</code> になっているか再確認。相対パスのミスも要注意。</li>
  <li><strong>「Crashlytics を使わないのに落ちる」</strong><br>Crashlytics のパッケージがどこかで参照されている可能性。<em>参照を外す</em>か、プラグインを正しく適用して Build&nbsp;ID を生成します。</li>
  <li><strong>「マルチモジュールの Gradle 設定で意図通りに結合されない」</strong><br>断片はアプリモジュール(:app)に適用される想定です。<code>build.gradle</code> を <code>Platforms/Android</code> 直下に置いているか確認。</li>
  <li><strong>「ProGuard/R8 のエラー」</strong><br>Release で有効な場合、R8 の最適化により初期化コードが消されることがあります。必要に応じて <code>proguard.cfg</code> に keep ルールを追加します(例:<code>-keep class com.google.firebase.** { *; }</code>)。</li>
</ul>

<h2>動作確認のすすめ(安全に検証)</h2>
<ol>
  <li>デバッグで起動して <em>エラーが消えた</em>こと(初期化例外が無くなる)を確認。</li>
  <li>Release ビルドで起動。ログに Crashlytics の初期化メッセージが出ることを確認。</li>
  <li>テストクラッシュ(開発環境のみ)で報告経路を検証します。
    <pre><code>// 例: 起動数秒後に意図的に例外(検証時のみ)
MainThread.BeginInvokeOnMainThread(async () =&gt; {
    await Task.Delay(3000);
    throw new Exception("Crashlytics test crash");
});

本番リリース前に Debug では収集しない設計になっているかも合わせて点検してください。

コード/設定のサンプルまとめ

Android: build.gradle 断片

buildscript {
    repositories { google(); mavenCentral() }
    dependencies {
        classpath 'com.google.gms:google-services:4.4.2'
        classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.2'
    }
}
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'

Android: Manifest で収集 OFF(Debug)

&lt;application&gt;
  &lt;meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false"/&gt;
&lt;/application&gt;

iOS: Info.plist で収集 OFF(Debug)

&lt;key&gt;FirebaseCrashlyticsCollectionEnabled&lt;/key&gt;
&lt;false/&gt;

MAUI プロジェクトファイル(抜粋)

&lt;ItemGroup&gt;
  &lt;GoogleServicesJson Include="Platforms/Android/google-services.json" /&gt;
  &lt;BundleResource Include="Platforms/iOS/GoogleService-Info.plist" /&gt;
&lt;/ItemGroup&gt;

なぜ「Plugin.Firebase を入れただけ」ではダメなのか

Plugin.Firebase はクロスプラットフォームの API 面を整える「ラッパー」で、ネイティブ SDK のビルド工程(Gradle/CocoaPods)まで肩代わりするものではありません。特に Android の Crashlytics は「Gradle プラグインがビルド時に実行されて初めて動く」設計なので、プラグイン適用が抜けると今回のエラーになります。裏を返せば、プラグインさえ入っていれば外部コードの変更は不要で、プロジェクト設定だけで解決できます。

チェックリスト(最終確認)

  • Androidbuild.gradle 断片で google-servicescrashlytics を適用した。
  • Androidgoogle-services.json のビルドアクションは GoogleServicesJson
  • iOSGoogleService-Info.plist のビルドアクションは BundleResource。リンク設定(-ObjC)済み。
  • Debug:収集 OFF(Manifest/Info.plist)。Release:収集 ON。
  • NuGet は最新で依存の不整合なし。
  • クリーンビルドしてエラーが解消した。

まとめ

  • 例外の直接原因は Crashlytics の Build ID 未生成
  • Android は com.google.gms.google-servicescom.google.firebase.crashlytics の 2 プラグインが必須。
  • google‑services.jsonGoogleService‑Info.plist を正しい場所とビルドアクションで配置。
  • iOS はフレームワークのリンク確認(-ObjC、Crashlytics の参照)。
  • デバッグでは収集を無効化して開発ノイズを防止。Release だけ有効化。
  • これらの設定で、Plugin.Firebase を使った .NET MAUI アプリは例外なく起動し、Crashlytics も正常に動作します。

この記事を書いた人

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

コメント

コメントする

目次