From 02021b540eca19a1e58be28fca31c62ee0e6e17f Mon Sep 17 00:00:00 2001 From: airkjw Date: Thu, 18 Jun 2026 11:17:27 +0900 Subject: [PATCH] feat(crashlytics): report release crashes to Firebase Crashlytics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Routes Flutter framework errors (FlutterError.onError) and uncaught async/platform errors (PlatformDispatcher.onError) to Crashlytics, but only in release builds — debug keeps its red error screens and console traces, and collection is disabled via setCrashlyticsCollectionEnabled (kReleaseMode) so development crashes never reach the dashboard. Adds the Crashlytics Gradle plugin alongside the existing google-services FlutterFire config. iOS dSYM upload run script still to be added in Xcode (symbolication only; crash capture works without it). Co-Authored-By: Claude Opus 4.8 (1M context) --- android/app/build.gradle.kts | 1 + android/settings.gradle.kts | 1 + lib/main.dart | 16 ++++++++++++++++ pubspec.lock | 32 ++++++++++++++++++++++++-------- pubspec.yaml | 1 + 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 21a3806..9597073 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -5,6 +5,7 @@ plugins { id("com.android.application") // START: FlutterFire Configuration id("com.google.gms.google-services") + id("com.google.firebase.crashlytics") // END: FlutterFire Configuration id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index e2e6ffb..87ff57d 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -22,6 +22,7 @@ plugins { id("com.android.application") version "8.9.1" apply false // START: FlutterFire Configuration id("com.google.gms.google-services") version("4.4.4") apply false + id("com.google.firebase.crashlytics") version("3.0.3") apply false // END: FlutterFire Configuration id("org.jetbrains.kotlin.android") version "2.1.0" apply false } diff --git a/lib/main.dart b/lib/main.dart index b807241..0e505da 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -43,6 +44,21 @@ Future main() async { analytics = AnalyticsService( kReleaseMode ? FirebaseAnalyticsBackend() : DebugAnalyticsBackend(), ); + + // Crashlytics: collect from release builds only (so debug keeps its red + // error screens and console traces, and development crashes never reach + // the production dashboard). In release, route both Flutter framework + // errors and uncaught async/platform errors to Crashlytics. + await FirebaseCrashlytics.instance + .setCrashlyticsCollectionEnabled(kReleaseMode); + if (kReleaseMode) { + FlutterError.onError = + FirebaseCrashlytics.instance.recordFlutterFatalError; + PlatformDispatcher.instance.onError = (error, stack) { + FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); + return true; + }; + } } catch (e) { debugPrint('Firebase init failed, analytics disabled: $e'); analytics = AnalyticsService(DebugAnalyticsBackend()); diff --git a/pubspec.lock b/pubspec.lock index 0f8928d..04548c8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "0d1f0adfabbab9f46a1a80ce84a4d8b852b6e4dbf53ce413b30e0cf7d3631b71" + sha256: "78f98c1f9c4dbbd22c2bb7b7f17c4a5c06150e8b2cb791a0947979ad0d3dabd5" url: "https://pub.dev" source: hosted - version: "1.3.72" + version: "1.3.73" analyzer: dependency: transitive description: @@ -253,26 +253,42 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: ec46a100a560d3bd5f97f2d89ba7492cb09b6dd0a4a28753d1258f360d6bd9f9 + sha256: d2625088d8f8836a7a74a7eb94a5372d70ad88382602ba2dcc02805c294d0d16 url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.11.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: "4a120366dbf7d5a8ee9438978530b664b855728fb8dcc3a201017660817e555b" + sha256: "913e7c96ef83a80ad7e1c3f8a059167b3de23b5d5e07fa3ed8f11abe24de98b6" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.1.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "5ad1be848692ec148f2d6a8ad2a3838cb852ea5f3c9e6479a7afce479e1854f8" + sha256: "30ba3ae56f5beb2cea836033201570612c911661889f815eca73b6056c7b55bf" url: "https://pub.dev" source: hosted - version: "3.8.0" + version: "3.9.0" + firebase_crashlytics: + dependency: "direct main" + description: + name: firebase_crashlytics + sha256: "2d9c791abef1cfd66c2572f5a4e172aa9f43476961af49742b1511dd327611df" + url: "https://pub.dev" + source: hosted + version: "5.2.4" + firebase_crashlytics_platform_interface: + dependency: transitive + description: + name: firebase_crashlytics_platform_interface + sha256: cbedfe34081c4ad5c4e0558165383d4fa6b8fd70ae6e696190aad345adbb346c + url: "https://pub.dev" + source: hosted + version: "3.8.24" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5c4b9f3..17f1cae 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,6 +48,7 @@ dependencies: in_app_purchase: ^3.2.3 app_tracking_transparency: ^2.0.7 in_app_review: ^2.0.12 + firebase_crashlytics: ^5.2.4 dev_dependencies: flutter_test: