Flutter x Firebase Crashlyticsの導入〜運用まで

Flutter x Firebase Crashlyticsの導入〜運用まで

2025.09.07

はじめに

FirebaseCrashlyticsは、アプリのクラッシュレポートを収集・分析するためのツールです。
直近触ることがあり改めて気づき学びがあったので、本記事でFlutterアプリへの導入から運用、注意点をまとめてみます。

導入

0. 前提条件

Flutterプロジェクトの作成
Firebaseプロジェクトの導入

1. FirebaseCrashlyticsの導入

pubspec.yamlにfirebase_crashlyticsパッケージを追加します。

pubspec.yaml
dependencies:
  firebase_crashlytics: ^any

2. クラッシュハンドラの構成

main.dartに以下の通り記述することで、アプリクラッシュ以外のエラーも補足します。

main.dart
Future<void> main() async {
    WidgetsFlutterBinding.ensureInitialized();
    await Firebase.initializeApp();

    // リリースモードの時だけCrashlyticsに送信する
    if (kReleaseMode) {
	    // Flutterフレームワーク内でスローされたすべてのエラーを補足しCrashlyticsレポートを送信
	    FlutterError.onError = (errorDetails) {
	      FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
	    };

	    // Flutterフレームワークで処理されない非同期エラーを補足しCrashlyticsレポートを送信
	    PlatformDispatcher.instance.onError = (error, stack) {
	      FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
	      return true;
	    };
    }

    runApp(MyApp());
}

3. キャッチされた例外を送信

「2. クラッシュハンドラの構成」の対応だけでは補足できないErrorやExceptionがあります。

そのためroggleパッケージを使って、ログレベルがエラー以上の時だけ手動でFirebaseCrashlyticsに送信できるようにします。

logger.dart
final logger =
	// リリースモードの時だけCrashlyticsに送信する
    kReleaseMode
        ? Roggle.crashlytics(
          printer: CrashlyticsPrinter(
	        /*
            レポートしたい箇所に関しては、logger.e(メッセージ)という形で呼び出す
            例:
			onPressed: () {
				try {
					何かしらの処理
				} on Exception catch (e) {
					logger.e(e);
				}
			}
			*/
            errorLevel: Level.error,
            onError: (event) {
		        // Crashlyticsレポートを送信
		        FirebaseCrashlytics.instance
                  .recordError(exception: event.exception, stack: event.stack);
            },
            onLog: (event) {
	            // CrashlyticsレポートのKeysタブに出力
	            FirebaseCrashlytics.instance.setCustomKey('message', message);
	            // CrashlyticsレポートのLogsタブに出力
	            FirebaseCrashlytics.instance.log(message);
            },
          ),
        )
        : Roggle(),
        );

4. ユーザーIDを設定

デフォルトでデバイスのOS情報やアプリ情報で絞り込みが可能ですが、ユーザーIDを設定することでより検索性を高めることができます。
参考:Firebase Crashlytics のクラッシュ レポートのカスタマイズ - ユーザー ID を設定する

example.dart
FirebaseCrashlytics.instance.setUserIdentifier("12345");

5. iOSでdSYMを自動アップロード

「dSYMの不足」に関するアラートが表示されないように、CrashlyticsにdSYMをアップロードする実行スクリプトを用意する必要があります。

flutterfire configure コマンドを実行するとBuildPhasesにFlutterFire: "flutterfire upload-crashlytics-symbols"が作成されます。

バージョンによって中身が異なることがあるため、公式ドキュメントを参考に実装することをおすすめします。
また、必要に応じで環境分け対応も行います。

参考:Crashlytics ダッシュボードで読み取り可能なクラッシュ レポートを取得する - Apple プラットフォーム

運用

補足したエラーは以下のユースケースで活用します。

  • 定期的なクラッシュレポートの解析と対応
  • 不具合発生時の調査

注意点

送信タイミング

recordFlutterFatalError()で補足するような致命的なエラー以外は、アプリの再起動時に送信されます。
recordError()ではfatal: trueと指定することで即送信が可能です。

難読化

Flutterはビルド時に--obfuscateオプションを使用することで難読化が可能です。
しかし、難読化を行うとスタックトレースも難読化されるため、エラー解析が困難になります。

セキュリティ要件で必要な場合を除き、エラー調査の効率性とデバッグコストを重視し、FirebaseCrashlytics導入時は難読化を行わない方が良いかもしれません。

(´-`).。oO(そもそもアプリで難読化しなくていい設計がベストとは思う

CI/CD

dSYMの自動アップロードを実行するスクリプトを用意していても、正しくアップロードされないことがあるかもしれません。

ローカルでipaファイルをビルドしていれば、archiveからdSYMを取得できますが、
CI/CD環境でビルドしていた場合にはarchiveから取得ができません。

運用によるところではありますが、artifactから取得できるようにするなど考慮ができているとベストだと思います。

補足)
以前はAppStoreConnectのTestFlightからのdSYMをダウンロードできたようですが、現在はできませんでした。
ENABLE_BITCODEYESにすれば取得可能になるみたいですが、Appleの方針的に非推奨なようです。

まとめ

FirebaseCrashlyticsを活用することで、アプリの信頼性や可用性を高めやすくなります。
個人的には目下必要な対応に追われて「定期的なクラッシュレポートの解析と対応」が疎かになってしまいがちなのですが、
品質向上のために時間を確保し改善できるようにしようと思います。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.