تكامل Firebase

أداة FlutterFire CLI وخيارات Firebase

15 دقيقة الدرس 2 من 13

أداة FlutterFire CLI وخيارات Firebase

نسخ مفاتيح API ومعرّفات المشاريع وقيم الإعداد يدوياً من وحدة تحكم Firebase إلى تطبيق Flutter أمر عرضة للأخطاء ومرهق. تحلّ أداة FlutterFire CLI هذه المشكلة من خلال إنشاء ملف firebase_options.dart تلقائياً، يحتوي على كائن FirebaseOptions مكتوب بدقة لكل منصة مستهدفة. ما عليك سوى توجيه الأداة إلى مشروع Firebase وستتولى هي الجزء الأصعب.

تثبيت FlutterFire CLI

FlutterFire CLI هي أداة سطر أوامر مبنية بـ Dart ومنشورة على pub.dev. ثبّتها عالمياً إلى جانب Firebase CLI:

تثبيت أدوات سطر الأوامر

# تثبيت (أو تحديث) Firebase CLI عبر npm
npm install -g firebase-tools

# تسجيل الدخول إلى Firebase
firebase login

# تثبيت FlutterFire CLI عالمياً
dart pub global activate flutterfire_cli

# التحقق من التثبيت
flutterfire --version
ملاحظة: تأكد من أن ~/.pub-cache/bin موجود في متغير البيئة PATH لكي يكون أمر flutterfire متاحاً عالمياً. على macOS/Linux، أضف export PATH="$PATH":"$HOME/.pub-cache/bin" إلى ملف إعداد الـ shell الخاص بك (.zshrc أو .bashrc).

تشغيل flutterfire configure

انتقل إلى جذر مشروع Flutter الخاص بك (حيث يوجد pubspec.yaml) وشغّل:

إنشاء firebase_options.dart

# الوضع التفاعلي — يطلب منك اختيار مشروع Firebase والمنصات
flutterfire configure

# الوضع غير التفاعلي — تحديد المشروع والمنصات صراحةً
flutterfire configure \
  --project=my-app-prod \
  --platforms=android,ios,web

ستقوم الأداة بـ:

  • جلب إعداد مشروع Firebase من Firebase API
  • تسجيل تطبيقك لكل منصة محددة (Android، iOS، Web، macOS) إن لم تكن مسجلة مسبقاً
  • تنزيل google-services.json (Android) وGoogleService-Info.plist (iOS) في المجلدات الأصلية الصحيحة
  • إنشاء lib/firebase_options.dart الذي يحتوي على كلاس DefaultFirebaseOptions
نصيحة: أعد تشغيل flutterfire configure في أي وقت تضيف فيه منصة جديدة أو تغيّر خدمات Firebase. تعيد الأداة كتابة firebase_options.dart والملفات الأصلية بأمان دون المساس بمنطق Dart الخاص بك.

تشريح ملف firebase_options.dart

الملف المُنشأ يصدّر كلاس DefaultFirebaseOptions مع دالة ثابتة currentPlatform. تعيد هذه الدالة كائن FirebaseOptions الصحيح عند وقت التشغيل بناءً على defaultTargetPlatform:

ملف firebase_options.dart المُنشأ (مبسَّط)

// ملف أُنشئ بواسطة FlutterFire CLI — لا تعدّله يدوياً.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
    show defaultTargetPlatform, kIsWeb, TargetPlatform;

class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (kIsWeb) {
      return web;
    }
    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        return android;
      case TargetPlatform.iOS:
        return ios;
      case TargetPlatform.macOS:
        return macos;
      default:
        throw UnsupportedError(
          'DefaultFirebaseOptions are not supported for this platform.',
        );
    }
  }

  static const FirebaseOptions android = FirebaseOptions(
    apiKey: 'AIzaSy....',
    appId: '1:123456789:android:abcdef',
    messagingSenderId: '123456789',
    projectId: 'my-app-prod',
    storageBucket: 'my-app-prod.appspot.com',
  );

  static const FirebaseOptions ios = FirebaseOptions(
    apiKey: 'AIzaSy....',
    appId: '1:123456789:ios:abcdef',
    messagingSenderId: '123456789',
    projectId: 'my-app-prod',
    storageBucket: 'my-app-prod.appspot.com',
    iosClientId: 'com.example.myapp',
    iosBundleId: 'com.example.myapp',
  );

  static const FirebaseOptions web = FirebaseOptions(
    apiKey: 'AIzaSy....',
    appId: '1:123456789:web:abcdef',
    messagingSenderId: '123456789',
    projectId: 'my-app-prod',
    storageBucket: 'my-app-prod.appspot.com',
    authDomain: 'my-app-prod.firebaseapp.com',
    measurementId: 'G-XXXXXXXX',
  );
}

تهيئة Firebase في main.dart

بعد إنشاء firebase_options.dart، تهيئة Firebase في تطبيقك تصبح استدعاءً واحداً. استخدم دائماً await داخل دالة main غير متزامنة قبل تشغيل شجرة الودجات:

ربط Firebase.initializeApp() في main.dart

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'firebase_options.dart';

Future<void> main() async {
  // التأكد من جاهزية محرك Flutter قبل استدعاء الإضافات الأصلية
  WidgetsFlutterBinding.ensureInitialized();

  // تمرير الخيارات الخاصة بالمنصة من الملف المُنشأ
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  runApp(const MyApp());
}
تحذير: لا تستدعِ Firebase.initializeApp() أبداً بدون await. الاستدعاء التزامني يُعيد Future لا يُحلّ أبداً، لذا فإن كل استدعاء Firebase لاحق (Firestore، Auth، إلخ) سيرمي FirebaseException برسالة "No Firebase App has been created."

إدارة بيئات التطوير والإنتاج

من أنماط الإنتاج الشائعة الاحتفاظ بمشروعَي Firebase منفصلَين — أحدهما للتطوير والآخر للإنتاج — كل منهما بمفاتيح API وقواعد بيانات وحاويات تخزين خاصة به. تدعم أداة FlutterFire CLI هذا النمط عبر علامة --project مدمجة مع نكهات بناء Dart:

إنشاء خيارات لبيئات متعددة

# إنشاء خيارات مشروع التطوير في ملف مُسمّى
flutterfire configure \
  --project=my-app-dev \
  --out=lib/firebase_options_dev.dart \
  --yes

# إنشاء خيارات مشروع الإنتاج في ملف منفصل
flutterfire configure \
  --project=my-app-prod \
  --out=lib/firebase_options_prod.dart \
  --yes

ثم اختر ملف الخيارات الصحيح عند بدء التشغيل باستخدام ثابت وقت الترجمة أو نكهة Dart:

التبديل بين مشروعَي Firebase حسب النكهة

// main_dev.dart  — نقطة الدخول لنكهة "dev"
import 'firebase_options_dev.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp(environment: 'development'));
}

// main_prod.dart  — نقطة الدخول لنكهة "prod"
import 'firebase_options_prod.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp(environment: 'production'));
}
نصيحة: أضف lib/firebase_options*.dart إلى ملف .gitignore إذا كانت مفاتيح Firebase API حساسة. بالنسبة للمشاريع مفتوحة المصدر، مفاتيح Firebase Web API ليست سرية (هي تعرّف المشروع، لا تصادق عليه — قواعد أمان Firebase هي حارسك الحقيقي)، لكن مفاتيح الخادم (JSON حساب الخدمة) يجب ألا تُودَع في git أبداً.

الخلاصة

FlutterFire CLI هي الطريقة الموصى بها رسمياً لتوصيل تطبيق Flutter بـ Firebase. تشغيل flutterfire configure يُنشئ كلاس DefaultFirebaseOptions مكتوباً بدقة مع إعداد خاص بكل منصة. استدعاء Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform) في دالة main غير متزامنة يُشغّل كل خدمات Firebase قبل تشغيل شجرة الودجات. لإعدادات متعددة البيئات، أنشئ ملفات خيارات منفصلة للتطوير والإنتاج واختر الملف المناسب عبر نكهات Dart أو نقاط دخول مستقلة في وقت الترجمة.