الفصل الثاني عشر: التكامل مع Firebase Chapter 12: Firebase Integration
كيف نستخدم سحابة Google لتقوية التطبيق وتعقب الأخطاء والوصول للمستخدمين أينما كانوا.
فيربيز مش مجرد قاعدة بيانات، هي منظومة كاملة بتساعدنا في MRE CashBook بـ 3 حاجات أساسية:
معرفة لو التطبيق "كرش" (Crashed) عند حد من المستخدمين فوراً عن طريق Crashlytics.
إرسال إشعارات فورية (Push Notifications) لجذب المستخدمين للعودة للتطبيق باستخدام FCM.
إدارة آلاف المستخدمين وإرسال رسائل جماعية بسهولة بدون استهلاك موارد الموبايل.
يوضح الرسم التالي كيف يتفاعل التطبيق مع خدمات Firebase المختلفة:
التكامل ده بيتم في طبقة الـ Core بتاع التطبيق عشان يغطي جميع الـ Features في نفس الوقت.
واحدة من أكبر المشاكل في الأندرويد هي غياب خدمات جوجل (GMS) على بعض الأجهزة. لو حاولنا نشغل Firebase بدون حذر، التطبيق ممكن "يهنج" تماماً.
Future<void> initFirebase() async {
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
).timeout(
const Duration(seconds: 3),
onTimeout: () => throw TimeoutException('Firebase unreachable'),
);
// إعداد الـ Crashlytics في وضع الـ Release فقط
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(kReleaseMode);
} catch (e) {
AppLogger.error("Firebase init failed, but continuing app launch.");
}
}
بدل ما نعتمد على كلام المستخدم الشفهي "التطبيق قفل"، Crashlytics بتبعت لنا الـ Stack Trace كامل.
| Log Type | Description |
|---|---|
| Fatal | الأخطاء اللي بتخلي الأبلكيشن يقفل تماماً (Native Crashes). |
| Non-Fatal | الأخطاء اللي بنمسكها بالـ Try-Catch وبنبعتها يدوي. |
| Logs | سلسلة أحداث المستخدم (Breadcrumbs) قبل ما الكراش يحصل. |
نصيحة: إحنا بنستخدم FirebaseCrashlytics.instance.recordFlutterError(details) في الـ FlutterError.onError عشان نمسك أي خطأ يحصل في الـ UI بشكل تلقائي.
الإشعارات في MRE CashBook بتشتغل على 3 مستويات بناءً على حالة التطبيق:
بنستخدم onMessage.listen وبنظهر In-app notification أو Banner مخصص.
بنستخدم onBackgroundMessage (ولازم يكون Static Function) عشان السيستم يظهره.
بنستخدم getInitialMessage عشان نعرف لو المستخدم دخل التطبيق عن طريق إشعار.
Entry Point: الـ Background Handler لازم يكون واخد الـ Annotation دي: @pragma('vm:entry-point') عشان الـ Dart VM يقدر يشوفه من برا التطبيق.
الإشعار مش مجرد رسالة، هو ممكن يوجه المستخدم لشاشة معينة (مثلاً شاشة إضافة معاملة جديدة).
// Handling notification click
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
if (message.data['screen'] == 'add_transaction') {
navigator.pushNamed('/add');
}
});
ده بيزود الـ Interactive Rate بتاع التطبيق وبيخلي المستخدم يوصل لهدفه أسرع.
كل جهاز له "عنوان بريدي" فريد في فيربيز اسمه Token. إحنا بنحتاج العنوان ده عشان نبعت رسالة للجهاز ده بالذات.
// Get the token for this device
String? token = await FirebaseMessaging.instance.getToken();
print("Device Token: $token");
PRO TIP: التوكين بيتغير لو المستخدم مسح الداتا أو عمل Reset للموبايل. لازم دايماً نحدثه في السيرفر عندنا باستخدام onTokenRefresh.
أجهزة هواوي الحديثة مفهاش خدمات جوجل، وعشان كدة فيربيز مش هيشتغل عليها (Out of the box). كيف يتعامل MRE CashBook؟
بدل ما نضايق المستخدم برسالة خطأ، التطبيق بيكمل "صامت" وبيلغي ميزات السحاب تلقائياً.
التطبيق مبنى إنه يكون "Native First"، يعني الأساس (الداتابيز، الحسابات) مش محتاج إنترنت ولا فيربيز عشان يشتغل.
زمان كان لازم نحط ملفات JSON و Plist في فولدرات Native. دلوقتي، الـ FlutterFire CLI بيعملنا ملف Dart فيه كل الإعدادات لكل المنصات (Android, iOS, Web).
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyA...',
appId: '1:123456789:android:...',
messagingSenderId: '123456789',
projectId: 'mre-cashbook',
);
ده بيخلي الـ Source Control (Git) أنظف، وبنقدر نغير الـ Config بسهولة من مكان واحد.
أشهر المشاكل اللي بتقابل المطورين مع فيربيز وحلها:
الإشعارات والـ Phone Auth مش بيشتغلوا لو الـ SHA-1 بتاع الـ KeyStore مش متسجل في Firebase Console.
حتى مع ملف الـ Dart الجديد، الأندرويد بيحتاج "Plugin" في الـ build.gradle عشان يفهم التكامل ده.
حلها دايماً هو مسح الـ Build القديم:
flutter clean && flutter pub get
سياسة MRE CashBook صارمة جداً فيما يخص البيانات:
لا نرسل بيانات المستخدم: إحنا بنستخدم فيربيز للـ Metadata فقط. يعني بنعرف إن فيه كراش حصل، بس مش بنعرف إيه الأرقام اللي كانت مكتوبة في الداتابيز بتاعتك. خصوصيتك 100% محلية.
أيضاً، إحنا بنشفر الـ User ID المبعوت للـ Crashlytics بـ UUID عشوائي عشان محدش يقدر يربط الخطأ بشخص معين.
| Term | Meaning (AR) |
|---|---|
| FCM | خدمة إرسال الإشعارات السحابية. |
| Stack Trace | تقرير تقني بيبين تسلسل الكود اللي أدى للخطأ. |
| Deep Link | رابط بيفتح شاشة معينة داخل التطبيق مباشرة. |
| GMS | خدمات جوجل للهواتف (Google Mobile Services). |
| Payload | البيانات الإضافية المخفية جوه الإشعار. |
الإشعارات في أندرويد 13+ و iOS بتحتاج موافقة صريحة من المستخدم. إحنا بنطلبها بذكاء:
NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
} else {
print('User declined or has not accepted permission');
}
إحنا بنستخدم Analytics عشان نعرف الأجزاء اللي مش مستخدمة ونحسنها، مش عشان نراقب خصوصيتك.
// Example: Log report generation
await FirebaseAnalytics.instance.logEvent(
name: 'generate_report',
parameters: {'type': 'monthly'},
);
عشان نضمن أقصى درجة من الأمان، بنتبع القواعد دي:
لا بيانات حساسة: لا يتم إرسال أي أرقام ومعاملات مالية لـ Firebase Analytics.
API Key Restrictions: مفاتيح الـ API محددة لتطبيقاتنا فقط عن طريق الـ Package Name والـ Bundle ID.
Data Retention: تقارير الكراشات بتتمسح تلقائياً بعد فترة 90 يوم لضمان الخصوصية.
| Component | Strategic Value |
|---|---|
| Crashlytics | Zero-day bug detection and fixing. |
| FCM | High user retention via smart alerts. |
| Safe Init | Universal device compatibility (GMS/HMS). |
| Config | Centralized platform management. |
دمج فيربيز بيحول تطبيقنا من مجرد كود محلي إلى تجربة مستخدم سحابية ناضجة، بتقدر تتعامل مع المشاكل وتتواصل مع المستخدمين باحترافية.