Không thể ngồi cạnh từng người dùng, nên app cần một crash reporting SDK (Firebase Crashlytics, Sentry) gom crash về một dashboard: nhóm theo stack trace, đếm số người dùng bị ảnh hưởng, lọc theo phiên bản app/OS/thiết bị.
Trong Flutter phải bắt hai nguồn lỗi: lỗi trong framework và lỗi async ngoài framework:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// Errors thrown inside the Flutter framework
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;
// Uncaught async errors outside the framework
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
runApp(const MyApp());
}Để stack trace đọc được:
- iOS cần upload dSYM (plugin tự thêm build phase).
- Build với --obfuscate --split-debug-info thì phải upload symbols: firebase crashlytics:symbols:upload --app=<APP_ID> build/symbols.
- React Native: upload source map lên Sentry để giải mã JS bundle đã minify. Crashlytics không nhận source map JS — stack trace JS phải tự giải mã bằng metro-symbolicate.
Chỉ số cần theo dõi: crash-free users, lỗi mới hoặc tái phát sau bản phát hành, và lỗi non-fatal (ghi bằng recordError trong catch — ví dụ API trả dữ liệu sai định dạng). Gắn custom key (màn hình, user ID ẩn danh) để tái hiện nhanh hơn.
Lưu ý: kết hợp với staged rollout — thấy crash-free users giảm ở 5% người dùng đầu tiên thì dừng rollout trước khi lan ra toàn bộ.