Firebase Crashlytics — الإبلاغ عن الأخطاء والتشخيص
Firebase Crashlytics — الإبلاغ عن الأخطاء والتشخيص
التطبيقات في بيئة الإنتاج تتعطّل. الفرق بين تطبيق احترافي وآخر هاوٍ يكمن في مدى سرعة اكتشافك للمشكلة، وحجم السياق المتاح لديك، وسرعة إصلاحها. Firebase Crashlytics هو أداة إبلاغ عن الأعطال خفيفة الوزن وفورية، تجمّع المشكلات حسب السبب الجذري، وتبرز الأكثر تأثيراً، وتمنحك مسار التتبع الكامل — مفاتيح مخصصة ورسائل سجل وتتبع المكدس — اللازم لإعادة إنتاج المشكلة وحلها.
إضافة الاعتمادية
أضف firebase_crashlytics إلى pubspec.yaml إلى جانب حزمة Firebase الأساسية:
# pubspec.yaml
dependencies:
firebase_core: ^3.6.0
firebase_crashlytics: ^4.1.3
نفّذ flutter pub get وتأكد من استدعاء Firebase.initializeApp() في main() قبل أي استخدام آخر لـ Firebase.
google-services.json وإضافة Gradle لخدمات Google. على iOS يتطلب GoogleService-Info.plist. كلاهما يُنزَّل من وحدة تحكم Firebase عند تسجيل تطبيقك.ربط معالجات الأخطاء الفادحة وغير الفادحة
الخطوة الأهم هي توجيه جميع الاستثناءات غير المعالجة — من Flutter، ومن المعزل Dart، ومن خيوط المنصة — إلى Crashlytics. افعل ذلك مرة واحدة في main():
import 'dart:async';
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 'firebase_options.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// تمرير جميع أخطاء Flutter غير المعالجة إلى Crashlytics.
FlutterError.onError =
FirebaseCrashlytics.instance.recordFlutterFatalError;
// تمرير جميع الأخطاء غير المتزامنة من المعزل الجذري
// (مثل الأخطاء المُلقاة داخل runApp أو سلاسل Future).
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true; // إعادة true يُخمد معالج الأخطاء الافتراضي
};
// تشغيل التطبيق.
runApp(const MyApp());
}
FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(!kDebugMode) مباشرةً بعد initializeApp.تسجيل الأخطاء غير الفادحة
لا تُوقف كل خطأ التطبيق. انتهاء مهلة الشبكة، وفشل تحليل JSON، والاستثناءات المعالجة — كلها تستحق التتبع كأحداث غير فادحة. استدعِ recordError مع fatal: false (القيمة الافتراضية) داخل كتل catch:
Future<void> loadUserProfile(String uid) async {
try {
final doc = await FirebaseFirestore.instance
.collection('users')
.doc(uid)
.get();
if (!doc.exists) throw Exception('User $uid not found');
_profile = UserProfile.fromMap(doc.data()!);
} catch (e, stack) {
// غير فادح: يمكن للواجهة عرض بديل، لكننا لا نزال نريد تقريراً.
await FirebaseCrashlytics.instance.recordError(
e,
stack,
reason: 'loadUserProfile failed for uid=$uid',
fatal: false,
);
_profile = UserProfile.empty();
}
}
المفاتيح المخصصة ورسائل السجل
كثيراً ما تفتقر تتبعات المكدس الخام إلى السياق اللازم لإعادة إنتاج العطل. يتيح لك Crashlytics إرفاق ما يصل إلى 64 زوجاً من المفاتيح والقيم المخصصة وكتابة مخزن سجل دائري (آخر 64 كيلوبايت) يُضمَّن في كل تقرير:
// إرفاق بيانات وصفية بمفاتيح وقيم (تُحدَّث مع تغير حالة التطبيق).
await FirebaseCrashlytics.instance.setCustomKey('user_role', 'premium');
await FirebaseCrashlytics.instance.setCustomKey('subscription_tier', 3);
await FirebaseCrashlytics.instance.setCustomKey('locale', 'ar_SA');
// كتابة فتات خبز مؤقتة إلى مخزن السجل.
FirebaseCrashlytics.instance.log('Navigated to checkout screen');
FirebaseCrashlytics.instance.log('Applied coupon: SAVE20');
FirebaseCrashlytics.instance.log('Payment provider: Stripe');
// تعريف المستخدم اختيارياً (استخدم معرفاً مبهماً، لا بيانات شخصية).
await FirebaseCrashlytics.instance.setUserIdentifier('user_8f3a91b');
تشغيل عطل اختباري
بعد ربط كل شيء، أرسل عطلاً اختبارياً للتحقق من صحة المسار قبل الإصدار:
// أضف زراً مؤقتاً أثناء التطوير فقط.
// احذفه قبل الإصدار للإنتاج.
ElevatedButton(
onPressed: () => FirebaseCrashlytics.instance.crash(),
child: const Text('Test Crash'),
),
أغلق التطبيق قسراً وأعد تشغيله. في غضون دقائق يظهر العطل في وحدة تحكم Firebase ضمن Crashlytics > Issues.
قراءة التقارير في وحدة تحكم Firebase
تعرض كل صفحة مشكلة في Crashlytics:
- تتبع المكدس — مُزال عنه التعتيم (إذا رفعت dSYMs أو تعيينات ProGuard)
- المفاتيح المخصصة — لقطة أزواج المفاتيح والقيم لحظة العطل
- السجلات — آخر 64 كيلوبايت من فتات الخبز المؤدية إلى العطل
- معلومات الجهاز ونظام التشغيل — الطراز، إصدار النظام، الذاكرة، الاتجاه
- بيانات الجلسة — إصدار التطبيق، المقدمة/الخلفية، نسبة المستخدمين الخاليين من الأعطال
الخلاصة
يحوّل Firebase Crashlytics الأعطال الغامضة إلى تشخيصات قابلة للتنفيذ. قائمة التكامل هي: أضف الحزمة، استدعِ initializeApp، اربط FlutterError.onError وPlatformDispatcher.instance.onError بـ recordFlutterFatalError / recordError، أثرِ التقارير بمفاتيح مخصصة وفتات خبز من السجل، وراقب وحدة تحكم Firebase. بهذا الإعداد سيُبلَّغ فريقك بالانتكاسات في غضون دقائق لا أيام.