「.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-servicesとcom.google.firebase.crashlyticsの2 つのプラグイン適用が必要です。 - 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.xml に firebase_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><application ...>
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />
</application>
</code></pre>
<h3>クリーン & 再ビルド</h3>
<ul>
<li><code>bin/</code> と <code>obj/</code> を削除してから再ビルド(古い中間生成物が残っていると Build 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 → TARGETS → Build Settings</td>
</tr>
<tr>
<td>Framework リンク</td>
<td><code>FirebaseCrashlytics</code> 系フレームワークがリンクされている</td>
<td>Xcode → TARGETS → General → 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><key>FirebaseCrashlyticsCollectionEnabled</key>
<false/>
</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 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><!-- Debug ビルドの Manifest(ビルド構成別にファイルを分けても良い) -->
<application>
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />
</application>
</code></pre>
<h3>iOS(Info.plist でオフ)</h3>
<pre><code><key>FirebaseCrashlyticsCollectionEnabled</key>
<false/>
</code></pre>
<p>必要であれば実行時に API で上書きします(Pseudocode)。</p>
<pre><code>// 例: アプリ設定のトグルで有効化する
CrossFirebaseCrashlytics.Current.SetCrashlyticsCollectionEnabled(true);
</code></pre>
<h2>Build ID が作られる仕組み(理解すると速い)</h2>
<p>Crashlytics の Gradle プラグインはビルド工程で</p>
<ol>
<li>アプリとビルドに一意な <em>Build 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 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 () => {
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)
<application>
<meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false"/>
</application>
iOS: Info.plist で収集 OFF(Debug)
<key>FirebaseCrashlyticsCollectionEnabled</key>
<false/>
MAUI プロジェクトファイル(抜粋)
<ItemGroup>
<GoogleServicesJson Include="Platforms/Android/google-services.json" />
<BundleResource Include="Platforms/iOS/GoogleService-Info.plist" />
</ItemGroup>
なぜ「Plugin.Firebase を入れただけ」ではダメなのか
Plugin.Firebase はクロスプラットフォームの API 面を整える「ラッパー」で、ネイティブ SDK のビルド工程(Gradle/CocoaPods)まで肩代わりするものではありません。特に Android の Crashlytics は「Gradle プラグインがビルド時に実行されて初めて動く」設計なので、プラグイン適用が抜けると今回のエラーになります。裏を返せば、プラグインさえ入っていれば外部コードの変更は不要で、プロジェクト設定だけで解決できます。
チェックリスト(最終確認)
- Android:
build.gradle断片でgoogle-servicesとcrashlyticsを適用した。 - Android:
google-services.jsonのビルドアクションはGoogleServicesJson。 - iOS:
GoogleService-Info.plistのビルドアクションはBundleResource。リンク設定(-ObjC)済み。 - Debug:収集 OFF(Manifest/Info.plist)。Release:収集 ON。
- NuGet は最新で依存の不整合なし。
- クリーンビルドしてエラーが解消した。
まとめ
- 例外の直接原因は Crashlytics の Build ID 未生成。
- Android は
com.google.gms.google-servicesとcom.google.firebase.crashlyticsの 2 プラグインが必須。 google‑services.json/GoogleService‑Info.plistを正しい場所とビルドアクションで配置。- iOS はフレームワークのリンク確認(
-ObjC、Crashlytics の参照)。 - デバッグでは収集を無効化して開発ノイズを防止。Release だけ有効化。
- これらの設定で、Plugin.Firebase を使った .NET MAUI アプリは例外なく起動し、Crashlytics も正常に動作します。

コメント