1. قبل أن تبدأ
في هذا الدرس التطبيقي حول التعليمات البرمجية، ستتعلم كيفية استخدام Firebase Emulator Suite مع Flutter أثناء التطوير المحلي. ستتعلم كيفية استخدام مصادقة كلمة المرور للبريد الإلكتروني عبر Emulator Suite، وكيفية قراءة البيانات وكتابتها في محاكي Firestore. أخيرًا، ستعمل على استيراد وتصدير البيانات من المحاكيات، للعمل بنفس البيانات المزيفة في كل مرة تعود فيها إلى التطوير.
المتطلبات الأساسية
يفترض هذا الدرس التطبيقي حول البرمجة أن لديك بعض الخبرة في Flutter. إذا لم يكن الأمر كذلك، فقد ترغب في تعلم الأساسيات أولاً. الروابط التالية مفيدة:
- قم بجولة في إطار عمل Flutter Widget
- جرب تطبيق Write Your First Flutter، الجزء الأول من التدريب البرمجي
يجب أن تتمتع أيضًا ببعض الخبرة في Firebase، لكن لا بأس إذا لم تقم مطلقًا بإضافة Firebase إلى مشروع Flutter. إذا لم تكن معتادًا على وحدة تحكم Firebase، أو كنت جديدًا تمامًا على Firebase تمامًا، فاطلع على الروابط التالية أولاً:
ما سوف تقوم بإنشائه
يرشدك هذا الدرس التطبيقي حول البرمجة إلى إنشاء تطبيق يوميات بسيط. سيحتوي التطبيق على شاشة تسجيل دخول، وشاشة تسمح لك بقراءة إدخالات دفتر اليومية السابقة وإنشاء إدخالات جديدة.
ما ستتعلمه
ستتعلم كيفية البدء في استخدام Firebase، وكيفية دمج مجموعة Firebase Emulator واستخدامها في سير عمل تطوير Flutter. سيتم تناول موضوعات Firebase هذه:
لاحظ أنه يتم تناول هذه المواضيع بقدر ما تكون مطلوبة لتغطية مجموعة محاكي Firebase. يركز هذا الدرس التدريبي على البرمجة على إضافة مشروع Firebase إلى تطبيق Flutter، والتطوير باستخدام Firebase Emulator Suite. لن تكون هناك مناقشات متعمقة حول مصادقة Firebase أو Firestore. إذا لم تكن على دراية بهذه المواضيع، فنوصي بالبدء بالبرنامج التدريبي للتعرف على Firebase for Flutter .
ماذا ستحتاج
- معرفة عملية بـ Flutter وتثبيت SDK
- محررات النصوص Intellij JetBrains أو VS Code
- متصفح Google Chrome (أو هدف التطوير المفضل لديك الآخر لـ Flutter. ستفترض بعض الأوامر الطرفية في هذا الدرس التطبيقي حول التعليمات البرمجية أنك تقوم بتشغيل تطبيقك على Chrome)
2. إنشاء وإعداد مشروع Firebase
المهمة الأولى التي ستحتاج إلى إكمالها هي إنشاء مشروع Firebase في وحدة تحكم الويب الخاصة بـ Firebase. ستركز الغالبية العظمى من دروس التعليمات البرمجية هذه على Emulator Suite، الذي يستخدم واجهة مستخدم تعمل محليًا، ولكن يتعين عليك إعداد مشروع Firebase كامل أولاً.
إنشاء مشروع Firebase
- قم بتسجيل الدخول إلى وحدة تحكم Firebase.
- في وحدة تحكم Firebase، انقر على "إضافة مشروع " (أو إنشاء مشروع )، وأدخل اسمًا لمشروع Firebase (على سبيل المثال، " Firebase-Flutter-Codelab") .
- انقر فوق خيارات إنشاء المشروع. اقبل شروط Firebase إذا طُلب منك ذلك. تخطي إعداد Google Analytics، لأنك لن تستخدم Analytics لهذا التطبيق.
لمعرفة المزيد حول مشاريع Firebase، راجع فهم مشاريع Firebase .
يستخدم التطبيق الذي تقوم بإنشائه اثنين من منتجات Firebase المتوفرة لتطبيقات Flutter:
- مصادقة Firebase للسماح للمستخدمين بتسجيل الدخول إلى تطبيقك.
- Cloud Firestore لحفظ البيانات المنظمة على السحابة وتلقي إشعار فوري عند تغيير البيانات.
يحتاج هذان المنتجان إلى تكوين خاص أو يجب تمكينهما باستخدام وحدة تحكم Firebase.
تمكين سحابة Firestore
يستخدم تطبيق Flutter Cloud Firestore لحفظ إدخالات دفتر اليومية.
تمكين Cloud Firestore:
- في قسم الإنشاء بوحدة تحكم Firebase، انقر فوق Cloud Firestore .
- انقر فوق إنشاء قاعدة بيانات .
- حدد خيار البدء في وضع الاختبار . اقرأ إخلاء المسؤولية حول قواعد الأمان. يضمن وضع الاختبار إمكانية الكتابة بحرية إلى قاعدة البيانات أثناء التطوير. انقر فوق {التالي .
- حدد موقع قاعدة البيانات الخاصة بك (يمكنك فقط استخدام الموقع الافتراضي). لاحظ أنه لا يمكن تغيير هذا الموقع لاحقًا.
- انقر فوق تمكين .
3. قم بإعداد تطبيق Flutter
ستحتاج إلى تنزيل رمز البدء وتثبيت Firebase CLI قبل أن نبدأ.
احصل على رمز البداية
انسخ مستودع GitHub من سطر الأوامر:
git clone https://github.com/flutter/codelabs.git flutter-codelabs
بدلاً من ذلك، إذا قمت بتثبيت أداة cli الخاصة بـ GitHub :
gh repo clone flutter/codelabs flutter-codelabs
يجب استنساخ نموذج التعليمات البرمجية في دليل flutter-codelabs
، الذي يحتوي على التعليمات البرمجية لمجموعة من Codelabs. الكود الخاص بهذا الدرس التطبيقي موجود في flutter-codelabs/firebase-emulator-suite
.
بنية الدليل ضمن flutter-codelabs/firebase-emulator-suite
عبارة عن مشروعين Flutter. أحدهما يُسمى complete
، والذي يمكنك الرجوع إليه إذا كنت تريد التخطي للأمام، أو إجراء إحالة مرجعية للتعليمات البرمجية الخاصة بك. المشروع الآخر يسمى start
.
الكود الذي تريد البدء به موجود في الدليل flutter-codelabs/firebase-emulator-suite/start
. افتح هذا الدليل أو قم باستيراده إلى IDE المفضل لديك.
cd flutter-codelabs/firebase-emulator-suite/start
قم بتثبيت Firebase CLI
يوفر Firebase CLI أدوات لإدارة مشاريع Firebase الخاصة بك. يلزم وجود واجهة سطر الأوامر (CLI) لاستخدام Emulator Suite، لذا ستحتاج إلى تثبيتها.
هناك مجموعة متنوعة من الطرق لتثبيت CLI. إن أبسط طريقة، إذا كنت تستخدم MacOS أو Linux، هي تشغيل هذا الأمر من جهازك الطرفي:
curl -sL https://firebase.tools | bash
بعد تثبيت واجهة سطر الأوامر (CLI)، يجب عليك المصادقة باستخدام Firebase.
- قم بتسجيل الدخول إلى Firebase باستخدام حساب Google الخاص بك عن طريق تشغيل الأمر التالي:
firebase login
- يقوم هذا الأمر بتوصيل جهازك المحلي بـ Firebase ويمنحك حق الوصول إلى مشاريع Firebase الخاصة بك.
- اختبر ما إذا تم تثبيت واجهة سطر الأوامر (CLI) بشكل صحيح وإمكانية الوصول إلى حسابك من خلال إدراج مشاريع Firebase الخاصة بك. قم بتشغيل الأمر التالي:
firebase projects:list
- يجب أن تكون القائمة المعروضة مماثلة لمشاريع Firebase المدرجة في وحدة تحكم Firebase . يجب أن تشاهد على الأقل Firebase-flutter-codelab.
قم بتثبيت FlutterFire CLI
تم إنشاء FlutterFire CLI أعلى Firebase CLI، وهو يجعل دمج مشروع Firebase مع تطبيق Flutter أسهل.
أولاً، قم بتثبيت واجهة سطر الأوامر (CLI):
dart pub global activate flutterfire_cli
تأكد من تثبيت CLI. قم بتشغيل الأمر التالي داخل دليل مشروع Flutter وتأكد من قيام CLI بإخراج قائمة المساعدة.
flutterfire --help
استخدم Firebase CLI وFlutterFire CLI لإضافة مشروع Firebase إلى تطبيق Flutter
من خلال تثبيت اثنين من واجهات سطر الأوامر (CLI)، يمكنك إعداد منتجات Firebase فردية (مثل Firestore)، وتنزيل المحاكيات، وإضافة Firebase إلى تطبيق Flutter الخاص بك من خلال بضعة أوامر طرفية فقط.
أولاً، قم بإنهاء إعداد Firebase عن طريق تشغيل ما يلي:
firebase init
سيقودك هذا الأمر عبر سلسلة من الأسئلة اللازمة لإعداد مشروعك. تُظهر لقطات الشاشة هذه التدفق:
- عندما يُطلب منك تحديد الميزات، حدد "Firestore" و"المحاكيات". (لا يوجد خيار مصادقة، لأنه لا يستخدم التكوين الذي يمكن تعديله من ملفات مشروع Flutter الخاصة بك.)
- بعد ذلك، حدد "استخدام مشروع موجود" عندما يُطلب منك ذلك.
- الآن، حدد المشروع الذي قمت بإنشائه في خطوة سابقة: Flutter-firebase-codelab.
- بعد ذلك، سيتم طرح سلسلة من الأسئلة عليك حول تسمية الملفات التي سيتم إنشاؤها. أقترح الضغط على "أدخل" لكل سؤال لتحديد الإعداد الافتراضي.
- وأخيرا، سوف تحتاج إلى تكوين المحاكيات. حدد Firestore and Authentication من القائمة، ثم اضغط على "Enter" لكل سؤال حول المنافذ المحددة التي سيتم استخدامها لكل محاكي. يجب عليك تحديد الإعداد الافتراضي، نعم، عند سؤالك عما إذا كنت تريد استخدام Emulator UI.
في نهاية العملية، يجب أن تشاهد نتيجة تبدو مثل لقطة الشاشة التالية.
هام : قد يكون ناتجك مختلفًا قليلاً عن مخرجي، كما هو موضح في لقطة الشاشة أدناه، لأن السؤال الأخير سيكون افتراضيًا على "لا" إذا كنت قد قمت بالفعل بتنزيل المحاكيات.
تكوين FlutterFire
بعد ذلك، يمكنك استخدام FlutterFire لإنشاء رمز Dart المطلوب لاستخدام Firebase في تطبيق Flutter.
flutterfire configure
عند تشغيل هذا الأمر، سيُطلب منك تحديد مشروع Firebase الذي تريد استخدامه، والأنظمة الأساسية التي تريد إعدادها. في هذا الدرس التطبيقي حول التعليمات البرمجية، تستخدم الأمثلة Flutter Web، ولكن يمكنك إعداد مشروع Firebase الخاص بك لاستخدام جميع الخيارات.
تعرض لقطات الشاشة التالية المطالبات التي ستحتاج إلى الإجابة عليها.
تعرض لقطة الشاشة هذه المخرجات في نهاية العملية. إذا كنت على دراية بـ Firebase، ستلاحظ أنه لم يكن عليك إنشاء تطبيقات في وحدة التحكم، وأن FlutterFire CLI قامت بذلك نيابةً عنك.
أضف حزم Firebase إلى تطبيق Flutter
خطوة الإعداد النهائية هي إضافة حزم Firebase ذات الصلة إلى مشروع Flutter الخاص بك. في الوحدة الطرفية، تأكد من أنك في جذر مشروع Flutter على Flutter flutter-codelabs/firebase-emulator-suite/start
. ثم قم بتشغيل الأوامر الثلاثة التالية:
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add cloud_firestore
هذه هي الحزم الوحيدة التي ستستخدمها في هذا التطبيق.
4. تمكين محاكيات Firebase
حتى الآن، تم إعداد تطبيق Flutter ومشروع Firebase الخاص بك لتتمكن من استخدام المحاكيات، ولكن لا تزال بحاجة إلى إخبار كود Flutter لإعادة توجيه طلبات Firebase الصادرة إلى المنافذ المحلية.
أولاً، أضف رمز تهيئة Firebase ورمز إعداد المحاكي إلى الوظيفة main
في main.dart.
main.dart
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'app_state.dart'; import 'firebase_options.dart'; import 'logged_in_view.dart'; import 'logged_out_view.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); if (kDebugMode) { try { FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080); await FirebaseAuth.instance.useAuthEmulator('localhost', 9099); } catch (e) { // ignore: avoid_print print(e); } } runApp(MyApp()); }
تعمل الأسطر القليلة الأولى من التعليمات البرمجية على تهيئة Firebase. بشكل عام تقريبًا، إذا كنت تعمل مع Firebase في تطبيق Flutter، فأنت تريد البدء عن طريق الاتصال بـ WidgetsFlutterBinding.ensureInitialized
و Firebase.initializeApp
.
بعد ذلك، الكود الذي يبدأ بالسطر if (kDebugMode)
يخبر تطبيقك باستهداف المحاكيات بدلاً من مشروع Firebase الإنتاجي. يضمن kDebugMode
أن استهداف المحاكيات لن يحدث إلا إذا كنت في بيئة تطوير. نظرًا لأن kDebugMode
هي قيمة ثابتة، يعرف مترجم Dart أنه يجب عليه إزالة كتلة التعليمات البرمجية هذه تمامًا في وضع الإصدار.
بدء تشغيل المحاكيات
يجب عليك تشغيل برامج المحاكاة قبل تشغيل تطبيق Flutter. أولاً، قم بتشغيل المحاكيات عن طريق تشغيل هذا في الوحدة الطرفية:
firebase emulators:start
يعمل هذا الأمر على تشغيل المحاكيات، ويكشف عن منافذ المضيف المحلي التي يمكننا التفاعل معها. عند تشغيل هذا الأمر، يجب أن ترى مخرجات مشابهة لما يلي:
يخبرك هذا الإخراج عن المحاكيات قيد التشغيل، وأين يمكنك الذهاب لرؤية المحاكيات. أولاً، تحقق من واجهة مستخدم المحاكي على localhost:4000
.
هذه هي الصفحة الرئيسية لواجهة مستخدم المحاكي المحلي. فهو يسرد جميع المحاكيات المتاحة، ويتم تصنيف كل واحدة منها بالحالة قيد التشغيل أو الإيقاف.
5. محاكي Firebase Auth
المحاكي الأول الذي ستستخدمه هو محاكي المصادقة. ابدأ باستخدام محاكي المصادقة بالنقر فوق "الانتقال إلى المحاكي" الموجود على بطاقة المصادقة في واجهة المستخدم، وسترى صفحة تبدو كالتالي:
تحتوي هذه الصفحة على أوجه تشابه مع صفحة وحدة تحكم ويب Auth. يحتوي على جدول يسرد المستخدمين مثل وحدة التحكم عبر الإنترنت، ويسمح لك بإضافة مستخدمين يدويًا. أحد الاختلافات الكبيرة هنا هو أن خيار طريقة المصادقة الوحيد المتاح على المحاكيات هو عبر البريد الإلكتروني وكلمة المرور. وهذا يكفي للتنمية المحلية.
بعد ذلك، ستتعرف على عملية إضافة مستخدم إلى محاكي Firebase Auth، ثم تسجيل دخول هذا المستخدم عبر Flutter UI.
إضافة مستخدم
انقر فوق الزر "إضافة مستخدم"، واملأ النموذج بهذه المعلومات:
- اسم العرض: داش
- البريد الإلكتروني: Dash@email.com
- كلمة المرور: كلمة المرور
قم بإرسال النموذج، وسترى أن الجدول يتضمن الآن مستخدمًا. يمكنك الآن تحديث الرمز لتسجيل الدخول مع هذا المستخدم.
logged_out_view.dart
الكود الوحيد في عنصر واجهة مستخدم LoggedOutView
الذي يجب تحديثه موجود في رد الاتصال الذي يتم تشغيله عندما يضغط المستخدم على زر تسجيل الدخول. قم بتحديث الكود ليبدو كالتالي:
class LoggedOutView extends StatelessWidget { final AppState state; const LoggedOutView({super.key, required this.state}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Firebase Emulator Suite Codelab'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Please log in', style: Theme.of(context).textTheme.displaySmall, ), Padding( padding: const EdgeInsets.all(8.0), child: ElevatedButton( onPressed: () async { await state.logIn('dash@email.com', 'dashword').then((_) { if (state.user != null) { context.go('/'); } }); }, child: const Text('Log In'), ), ), ], ), ), ); } }
يستبدل الكود المحدث سلاسل TODO
بالبريد الإلكتروني وكلمة المرور اللذين قمت بإنشائهما في محاكي المصادقة. وفي السطر التالي، تم استبدال سطر if(true)
بكود يتحقق مما إذا كان state.user
خاليًا. يلقي الكود الموجود في AppClass
مزيدًا من الضوء على هذا الأمر.
app_state.dart
يجب تحديث جزأين من التعليمات البرمجية في AppState
. أولاً، امنح عضو الفصل AppState.user النوع User
من حزمة firebase_auth
، بدلاً من النوع Object
.
ثانيًا، قم بملء طريقة AppState.login
كما هو موضح أدناه:
import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'entry.dart'; class AppState { AppState() { _entriesStreamController = StreamController.broadcast(onListen: () { _entriesStreamController.add([ Entry( date: '10/09/2022', text: lorem, title: '[Example] My Journal Entry', ) ]); }); } User? user; // <-- changed variable type Stream<List<Entry>> get entries => _entriesStreamController.stream; late final StreamController<List<Entry>> _entriesStreamController; Future<void> logIn(String email, String password) async { final credential = await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); if (credential.user != null) { user = credential.user!; _listenForEntries(); } else { print('no user!'); } } // ... }
تعريف النوع للمستخدم هو الآن User?
. تأتي فئة User
هذه من Firebase Auth، وتوفر المعلومات المطلوبة مثل User.displayName
، والتي تمت مناقشتها قليلًا.
هذا هو الرمز الأساسي المطلوب لتسجيل دخول المستخدم باستخدام البريد الإلكتروني وكلمة المرور في Firebase Auth. فهو يقوم باستدعاء FirebaseAuth لتسجيل الدخول، مما يؤدي إلى إرجاع كائن Future<UserCredential>
. عند اكتمال المستقبل، يتحقق هذا الرمز مما إذا كان هناك User
مرتبط بـ UserCredential
. إذا كان هناك مستخدم في كائن بيانات الاعتماد، فهذا يعني أن المستخدم قد قام بتسجيل الدخول بنجاح، ويمكن تعيين خاصية AppState.user
. إذا لم يكن هناك، فهذا يعني أنه حدث خطأ، وتمت طباعته.
لاحظ أن السطر الوحيد من التعليمات البرمجية في هذه الطريقة الخاص بهذا التطبيق (بدلاً من كود FirebaseAuth العام) هو استدعاء الأسلوب _listenForEntries
، والذي سيتم تناوله في الخطوة التالية.
المهام: رمز الإجراء - أعد تحميل تطبيقك، ثم اضغط على زر تسجيل الدخول عندما يتم عرضه. يؤدي هذا إلى انتقال التطبيق إلى صفحة تقول "مرحبًا بعودتك أيها الشخص!" في القمة. يجب أن تكون المصادقة تعمل، لأنها تسمح لك بالانتقال إلى هذه الصفحة، ولكن يجب إجراء تحديث بسيط على logged_in_view.dart
لعرض الاسم الفعلي للمستخدم.
logged_in_view.dart
قم بتغيير السطر الأول في طريقة LoggedInView.build
:
class LoggedInView extends StatelessWidget { final AppState state; LoggedInView({super.key, required this.state}); final PageController _controller = PageController(initialPage: 1); @override Widget build(BuildContext context) { final name = state.user!.displayName ?? 'No Name'; return Scaffold( // ...
الآن، يلتقط هذا السطر displayName
من خاصية User
على كائن AppState
. تم تعيين displayName
هذا في المحاكي عندما قمت بتعريف المستخدم الأول الخاص بك. يجب أن يعرض تطبيقك الآن "مرحبًا بعودتك، داش!" عند تسجيل الدخول، بدلاً من TODO
.
6. قراءة البيانات وكتابتها في محاكي Firestore
أولاً، تحقق من محاكي Firestore. في الصفحة الرئيسية لواجهة مستخدم Emulator ( localhost:4000
)، انقر فوق "الانتقال إلى المحاكي" على بطاقة Firestore. يجب أن تبدو هذه:
محاكي:
وحدة تحكم Firebase:
إذا كانت لديك أي خبرة مع Firestore، ستلاحظ أن هذه الصفحة تبدو مشابهة لصفحة Firestore الخاصة بوحدة تحكم Firebase. هناك بعض الاختلافات الملحوظة، رغم ذلك.
- يمكنك مسح جميع البيانات بنقرة زر واحدة. قد يكون هذا أمرًا خطيرًا بالنسبة لبيانات الإنتاج، ولكنه مفيد للتكرار السريع! إذا كنت تعمل على مشروع جديد وتغير نموذج البيانات الخاص بك، فمن السهل مسحه.
- هناك علامة التبويب "الطلبات". تتيح لك علامة التبويب هذه مشاهدة الطلبات الواردة المقدمة إلى هذا المحاكي. سأناقش علامة التبويب هذه بمزيد من التفاصيل بعد قليل.
- لا توجد علامات تبويب للقواعد أو الفهارس أو الاستخدام. هناك أداة (تتم مناقشتها في القسم التالي) تساعد في كتابة قواعد الأمان، لكن لا يمكنك تعيين قواعد الأمان للمحاكي المحلي.
لتلخيص هذه القائمة، يوفر هذا الإصدار من Firestore المزيد من الأدوات المفيدة أثناء التطوير، ويزيل الأدوات المطلوبة في الإنتاج.
الكتابة إلى Firestore
قبل مناقشة علامة التبويب "الطلبات" في المحاكي، قم أولاً بتقديم طلب. وهذا يتطلب تحديثات التعليمات البرمجية. ابدأ بتوصيل النموذج الموجود في التطبيق لكتابة مجلة جديدة Entry
to Firestore.
التدفق عالي المستوى لإرسال Entry
هو:
- يقوم المستخدم بملء النموذج والضغط على زر
Submit
- تستدعي واجهة المستخدم
AppState.writeEntryToFirebase
- يضيف
AppState.writeEntryToFirebase
إدخالاً إلى Firebase
لا يلزم تغيير أي من التعليمات البرمجية الموجودة في الخطوة 1 أو 2. سيتم إضافة الكود الوحيد الذي يجب إضافته للخطوة 3 في فئة AppState
. قم بإجراء التغيير التالي على AppState.writeEntryToFirebase
.
app_state.dart
import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'entry.dart'; class AppState { AppState() { _entriesStreamController = StreamController.broadcast(onListen: () { _entriesStreamController.add([ Entry( date: '10/09/2022', text: lorem, title: '[Example] My Journal Entry', ) ]); }); } User? user; Stream<List<Entry>> get entries => _entriesStreamController.stream; late final StreamController<List<Entry>> _entriesStreamController; Future<void> logIn(String email, String password) async { final credential = await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); if (credential.user != null) { user = credential.user!; _listenForEntries(); } else { print('no user!'); } } void writeEntryToFirebase(Entry entry) { FirebaseFirestore.instance.collection('Entries').add(<String, String>{ 'title': entry.title, 'date': entry.date.toString(), 'text': entry.text, }); } // ... }
يلتقط الكود الموجود في طريقة writeEntryToFirebase مرجعًا إلى المجموعة المسماة "Entries" في Firestore. ثم يقوم بإضافة إدخال جديد، والذي يجب أن يكون من النوع Map<String, String>
.
في هذه الحالة، لم تكن مجموعة "الإدخالات" في Firestore موجودة، لذلك أنشأ Firestore واحدة.
مع إضافة هذا الرمز، قم بإعادة تحميل تطبيقك أو إعادة تشغيله، وقم بتسجيل الدخول، وانتقل إلى طريقة العرض EntryForm
. يمكنك ملء النموذج بأي Strings
تريدها. (سيأخذ حقل "التاريخ" أي سلسلة، حيث تم تبسيطه في هذا الدرس التطبيقي حول التعليمات البرمجية. ولا يتمتع بتحقق قوي أو يهتم بكائنات DateTime
بأي شكل من الأشكال.)
اضغط على إرسال في النموذج. لن يحدث أي شيء في التطبيق، ولكن يمكنك رؤية إدخالك الجديد في واجهة مستخدم المحاكي.
علامة تبويب الطلبات في محاكي Firestore
في واجهة المستخدم، انتقل إلى محاكي Firestore، وانظر إلى علامة التبويب "البيانات". يجب أن ترى أن هناك الآن مجموعة في جذر قاعدة البيانات الخاصة بك تسمى "الإدخالات". يجب أن يحتوي ذلك على مستند يحتوي على نفس المعلومات التي أدخلتها في النموذج.
يؤكد ذلك أن AppState.writeEntryToFirestore
يعمل، ويمكنك الآن استكشاف الطلب بشكل أكبر في علامة التبويب "الطلبات". انقر فوق علامة التبويب هذه الآن.
طلبات محاكي Firestore
هنا، يجب أن تشاهد قائمة تبدو مشابهة لهذه:
يمكنك النقر فوق أي من عناصر القائمة هذه والاطلاع على قدر كبير من المعلومات المفيدة. انقر فوق عنصر القائمة CREATE
الذي يتوافق مع طلبك لإنشاء إدخال دفتر يومية جديد. سيظهر لك جدول جديد يبدو كالتالي:
كما ذكرنا سابقًا، يوفر محاكي Firestore أدوات لتطوير قواعد أمان تطبيقك. يُظهر هذا العرض بالضبط السطر الموجود في قواعد الأمان لديك والذي مرره هذا الطلب (أو فشل، إذا كان الأمر كذلك). في تطبيق أكثر قوة، يمكن أن تنمو قواعد الأمان وتخضع لعمليات فحص ترخيص متعددة. يتم استخدام طريقة العرض هذه للمساعدة في كتابة قواعد التفويض وتصحيح الأخطاء فيها.
كما يوفر أيضًا طريقة سهلة لفحص كل جزء من هذا الطلب، بما في ذلك البيانات التعريفية وبيانات المصادقة. تُستخدم هذه البيانات لكتابة قواعد ترخيص معقدة.
القراءة من Firestore
يستخدم Firestore مزامنة البيانات لدفع البيانات المحدثة إلى الأجهزة المتصلة. في Flutter code، يمكنك الاستماع (أو الاشتراك) إلى مجموعات ومستندات Firestore، وسيتم إخطار الكود الخاص بك في أي وقت تتغير فيه البيانات. في هذا التطبيق، يتم الاستماع إلى تحديثات Firestore بالطريقة التي تسمى AppState._listenForEntries
.
يعمل هذا الكود جنبًا إلى جنب مع StreamController
و Stream
المسمى AppState._entriesStreamController
و AppState.entries
، على التوالي. هذا الرمز مكتوب بالفعل، كما هو الحال مع كل التعليمات البرمجية المطلوبة في واجهة المستخدم لعرض البيانات من Firestore.
قم بتحديث طريقة _listenForEntries
لمطابقة الكود أدناه:
app_state.dart
import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'entry.dart'; class AppState { AppState() { _entriesStreamController = StreamController.broadcast(onListen: () { _entriesStreamController.add([ Entry( date: '10/09/2022', text: lorem, title: '[Example] My Journal Entry', ) ]); }); } User? user; Stream<List<Entry>> get entries => _entriesStreamController.stream; late final StreamController<List<Entry>> _entriesStreamController; Future<void> logIn(String email, String password) async { final credential = await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); if (credential.user != null) { user = credential.user!; _listenForEntries(); } else { print('no user!'); } } void writeEntryToFirebase(Entry entry) { FirebaseFirestore.instance.collection('Entries').add(<String, String>{ 'title': entry.title, 'date': entry.date.toString(), 'text': entry.text, }); } void _listenForEntries() { FirebaseFirestore.instance .collection('Entries') .snapshots() .listen((event) { final entries = event.docs.map((doc) { final data = doc.data(); return Entry( date: data['date'] as String, text: data['text'] as String, title: data['title'] as String, ); }).toList(); _entriesStreamController.add(entries); }); } // ... }
يستمع هذا الرمز إلى مجموعة "الإدخالات" في Firestore. عندما يقوم Firestore بإعلام هذا العميل بوجود بيانات جديدة، فإنه يمرر تلك البيانات ويقوم الكود الموجود في _listenForEntries
بتغيير جميع المستندات الفرعية الخاصة به إلى كائن يمكن لتطبيقنا استخدامه ( Entry
). ثم يضيف هذه الإدخالات إلى StreamController
المسمى _entriesStreamController
(الذي تستمع إليه واجهة المستخدم). هذا الرمز هو التحديث الوحيد المطلوب.
أخيرًا، تذكر أن التابع AppState.logIn
يقوم باستدعاء _listenForEntries
، والذي يبدأ عملية الاستماع بعد قيام المستخدم بتسجيل الدخول.
// ... Future<void> logIn(String email, String password) async { final credential = await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); if (credential.user != null) { user = credential.user!; _listenForEntries(); } else { print('no user!'); } } // ...
الآن قم بتشغيل التطبيق. يجب أن تبدو هذه:
7. تصدير واستيراد البيانات إلى المحاكي
تدعم محاكيات Firebase استيراد البيانات وتصديرها. يتيح لك استخدام عمليات الاستيراد والتصدير مواصلة التطوير بنفس البيانات عندما تأخذ استراحة من التطوير ثم تستأنفه. يمكنك أيضًا إرسال ملفات البيانات إلى git، وسيكون لدى المطورين الآخرين الذين تعمل معهم نفس البيانات للعمل معها.
تصدير بيانات المحاكي
أولاً، قم بتصدير بيانات المحاكي الموجودة لديك بالفعل. بينما لا تزال المحاكيات قيد التشغيل، افتح نافذة طرفية جديدة، وأدخل الأمر التالي:
firebase emulators:export ./emulators_data
.emulators_data
عبارة عن وسيطة تخبر Firebase بمكان تصدير البيانات. إذا كان الدليل غير موجود، فسيتم إنشاؤه. يمكنك استخدام أي اسم تريده لهذا الدليل.
عند تشغيل هذا الأمر، سترى هذا الإخراج في الوحدة الطرفية حيث قمت بتشغيل الأمر:
i Found running emulator hub for project flutter-firebase-codelab-d6b79 at http://localhost:4400 i Creating export directory /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data i Exporting data to: /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data ✔ Export complete
وإذا قمت بالتبديل إلى النافذة الطرفية التي تعمل فيها المحاكيات، فسترى هذا الإخراج:
i emulators: Received export request. Exporting data to /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data. ✔ emulators: Export complete.
وأخيرًا، إذا نظرت إلى دليل المشروع الخاص بك، فيجب أن ترى دليلًا يسمى ./emulators_data
، والذي يحتوي على ملفات JSON
، من بين ملفات البيانات الوصفية الأخرى، مع البيانات التي قمت بحفظها.
استيراد بيانات المحاكي
والآن، يمكنك استيراد تلك البيانات كجزء من سير عمل التطوير الخاص بك، والبدء من حيث توقفت.
أولاً، قم بإيقاف المحاكيات إذا كانت قيد التشغيل بالضغط على CTRL+C
في جهازك الطرفي.
بعد ذلك، قم بتشغيل الأمر emulators:start
الذي رأيته بالفعل، ولكن مع علامة تخبره بالبيانات التي سيتم استيرادها:
firebase emulators:start --import ./emulators_data
عند تشغيل المحاكيات، انتقل إلى واجهة مستخدم المحاكي على localhost:4000
، وسترى نفس البيانات التي كنت تعمل معها سابقًا.
تصدير البيانات تلقائيًا عند إغلاق المحاكيات
يمكنك أيضًا تصدير البيانات تلقائيًا عند إنهاء المحاكيات، بدلاً من تذكر تصدير البيانات في نهاية كل جلسة تطوير.
عند بدء تشغيل المحاكيات، قم بتشغيل أمر emulators:start
مع علامتين إضافيتين.
firebase emulators:start --import ./emulators_data --export-on-exit
هاهو! سيتم الآن حفظ بياناتك وإعادة تحميلها في كل مرة تعمل فيها مع المحاكيات لهذا المشروع. يمكنك أيضًا تحديد دليل مختلف كوسيطة –export-on-exit flag
، ولكنه سيكون افتراضيًا للدليل الذي تم تمريره إلى –import
.
يمكنك استخدام أي مجموعة من هذه الخيارات أيضًا. هذه هي الملاحظة من المستندات : يمكن تحديد دليل التصدير بهذه العلامة: firebase emulators:start --export-on-exit=./saved-data
. إذا تم استخدام --import
، فإن مسار التصدير الافتراضي هو نفسه؛ على سبيل المثال: firebase emulators:start --import=./data-path --export-on-exit
. وأخيرًا، إذا رغبت في ذلك، قم بتمرير مسارات دليل مختلفة إلى علامتي --import
و --export-on-exit
.
8. تهانينا!
لقد أكملت الإعداد والتشغيل باستخدام محاكي Firebase وFlutter. يمكنك العثور على الكود المكتمل لهذا Codelab في الدليل "الكامل" على github: Flutter Codelabs
ما قمنا بتغطيته
- إعداد تطبيق Flutter لاستخدام Firebase
- إعداد مشروع Firebase
- فلاترفيري سطر الأوامر
- Firebase CLI
- محاكي مصادقة Firebase
- محاكي Firebase Firestore
- استيراد وتصدير بيانات المحاكي
الخطوات التالية
- تعرف على المزيد حول استخدام Firestore والمصادقة في Flutter: تعرف على Firebase for Flutter Codelab
- استكشف أدوات Firebase الأخرى التي تقدم برامج محاكاة:
- سحابة التخزين
- وظائف السحابة
- قاعدة بيانات الوقت الحقيقي
- استكشف FlutterFire UI لإضافة مصادقة Google بسرعة إلى تطبيقك.
يتعلم أكثر
- موقع Firebase: firebase.google.com
- موقع الرفرفة: Flutter.dev
- أدوات FlutterFire Firebase Flutter: firebase.flutter.dev
- قناة فايربايس على اليوتيوب
- قناة فلاتر على اليوتيوب
سباركي فخور بك!