Crashlytics
Crashlytics captures real-user crashes, exceptions, and non-fatal errors from your mobile and web apps. It groups similar crashes by stack hash, surfaces affected user counts, and integrates with Slack/Jira/PagerDuty. The free tier is generous, and the cost of NOT having it is finding out your app is broken from the App Store reviews tab.
Wire Crashlytics on Android, iOS, and Flutter
EXAMPLE
// ===== Android (Kotlin) =====
// build.gradle (app):
// implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
// implementation("com.google.firebase:firebase-crashlytics-ktx")
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
Firebase.crashlytics.setUserId(currentUserId() ?: "anon")
Firebase.crashlytics.setCustomKey("build_flavor", BuildConfig.FLAVOR)
Firebase.crashlytics.setCustomKey("experiment", "home_v2")
// Hook your error boundary into Crashlytics
Thread.setDefaultUncaughtExceptionHandler { _, t ->
Firebase.crashlytics.recordException(t)
}
}
}
// Log a non-fatal manually
try { riskyCall() }
catch (e: Throwable) {
Firebase.crashlytics.log("riskyCall failed in checkout")
Firebase.crashlytics.recordException(e)
}
// ===== iOS (Swift) =====
// import FirebaseCrashlytics
// Crashlytics.crashlytics().setUserID(currentUserId() ?? "anon")
// Crashlytics.crashlytics().setCustomValue(BuildConfig.flavor, forKey: "build_flavor")
// do { try riskyCall() }
// catch {
// Crashlytics.crashlytics().log("riskyCall failed in checkout")
// Crashlytics.crashlytics().record(error: error)
// }
// ===== Flutter =====
// pubspec.yaml -> firebase_core, firebase_crashlytics
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// Route Flutter framework errors -> Crashlytics
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;
// Route async / Dart runtime errors -> Crashlytics
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(!kDebugMode);
await FirebaseCrashlytics.instance.setUserIdentifier(currentUserId() ?? 'anon');
runApp(const MyApp());
}
// Wrap risky widgets / async work
Future<void> placeOrder() async {
try {
await api.placeOrder();
} catch (e, st) {
await FirebaseCrashlytics.instance.recordError(e, st,
reason: 'placeOrder failed', fatal: false);
rethrow;
}
}
String? currentUserId() => null;
Future<void> riskyCall() async {}
Why it matters
Set the user id (or an anonymised hash of it) on sign-in. The single biggest jump in Crashlytics usefulness is going from "we have 412 crashes" to "412 crashes affecting 89 users — and here are the user ids", because it lets you reach out for repro and prioritise by the customers actually hurt.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// iOS / Android SDKs auto-report crashes
import crashlytics from '@react-native-firebase/crashlytics';
crashlytics().log('user opened settings');
crashlytics().recordError(new Error('Test crash'));
Try it Yourself »
Discussion
Loading…