تعرف على Firebase من أجل Flutter

1. قبل أن تبدأ

في هذا codelab، سوف تتعلم بعض أساسيات Firebase لخلق الرفرفة تطبيقات الجوال لأجهزة Android و iOS.

المتطلبات الأساسية

يفترض هذا codelab كنت معتادا على الرفرفة، وكنت قد قمت بتثبيت SDK الرفرفة ، و محررا .

ماذا ستنشئ

في مختبر الأكواد هذا ، ستنشئ حدث RSVP وتطبيق دردشة سجل الزوار على Android و iOS والويب و macOS باستخدام Flutter. ستقوم بمصادقة المستخدمين باستخدام مصادقة Firebase ومزامنة البيانات باستخدام Cloud Firestore.

ماذا ستحتاج

يمكنك تشغيل معمل الرموز هذا باستخدام أي من الأجهزة التالية:

بالإضافة إلى ما سبق ، ستحتاج أيضًا إلى:

  • متصفح من اختيارك ، مثل Chrome.
  • وIDE أو محرر نص من اختيارك، مثل الروبوت ستوديو أو كود VS تكوين مع السهام والرفرفة الإضافات.
  • أحدث stable نسخة من الرفرفة (أو beta إذا كنت تتمتع الذين يعيشون على حافة).
  • حساب Google ، مثل حساب gmail ، لإنشاء مشروع Firebase وإدارته.
  • نموذج التعليمات البرمجية لمعمل الرموز. راجع الخطوة التالية لمعرفة كيفية الحصول على الرمز.

2. احصل على نموذج التعليمات البرمجية

لنبدأ بتنزيل الإصدار الأولي لمشروعنا من GitHub.

استنساخ مستودع جيثب من سطر الأوامر:

git clone https://github.com/flutter/codelabs.git flutter-codelabs

بدلا من ذلك، إذا كان لديك المبادرة القطرية جيثب في أداة تثبيت:

gh repo clone flutter/codelabs flutter-codelabs

يجب استنساخ نموذج التعليمات البرمجية في flutter-codelabs الدليل الذي يحتوي على التعليمات البرمجية لمجموعة من codelabs. رمز لهذا codelab في flutter-codelabs/firebase-get-to-know-flutter .

بنية الدليل تحت flutter-codelabs/firebase-get-to-know-flutter هو عبارة عن سلسلة من اللقطات لل، حيث يجب أن تكون في نهاية كل خطوة اسمه. هذه هي الخطوة الثانية ، لذا فإن تحديد موقع الملفات المطابقة أمر سهل مثل:

cd flutter-codelabs/firebase-get-to-know-flutter/step_02

إذا كنت تريد التخطي إلى الأمام ، أو معرفة الشكل الذي يجب أن يبدو عليه شيء بعد خطوة ، فابحث في الدليل المسمى بعد الخطوة التي تهتم بها.

قم باستيراد تطبيق المبتدئين

فتح أو استيراد flutter-codelabs/firebase-get-to-know-flutter/step_02 الدليل إلى IDE المفضل لديك. يحتوي هذا الدليل على رمز البداية لمختبر الرموز الذي يتكون من تطبيق لقاء Flutter غير فعال بعد.

حدد موقع الملفات للعمل عليها

تنتشر التعليمات البرمجية في هذا التطبيق على عدة أدلة. تم تصميم هذا التقسيم في الوظائف لتسهيل العمل ، من خلال تجميع التعليمات البرمجية حسب الوظيفة.

حدد موقع الملفات التالية في المشروع:

  • lib/main.dart : يحتوي هذا الملف على نقطة الدخول الرئيسية والقطعة التطبيق.
  • lib/src/widgets.dart : يحتوي هذا الملف على حفنة من الحاجيات لمساعدة توحيد التصميم من التطبيق. تُستخدم هذه لإنشاء شاشة تطبيق المبتدئين.
  • lib/src/authentication.dart : يحتوي هذا الملف على التنفيذ الجزئي لل FirebaseUI مصادقة مع مجموعة من الحاجيات لخلق تجربة المستخدم تسجيل الدخول للمصادقة البريد الإلكتروني Firebase. لم يتم استخدام هذه الأدوات المصغّرة لتدفق المصادقة في تطبيق المبتدئين ، ولكنك ستدخلها قريبًا.

ستضيف ملفات إضافية حسب الحاجة لإنشاء بقية التطبيق.

مراجعة lib/main.dart ملف

هذا التطبيق يستفيد من google_fonts حزمة لتمكيننا من جعل Roboto الخط الافتراضي في جميع أنحاء التطبيق بالكامل. تمرين للقارئ دوافع هي لاستكشاف fonts.google.com واستخدام الخطوط تكتشف هناك في أجزاء مختلفة من التطبيق.

كنت الاستفادة من الحاجيات المساعد من lib/src/widgets.dart في شكل Header ، Paragraph و IconAndDetail . هذه الحاجيات الحد من فوضى في تخطيط الصفحة وصفه في HomePage من خلال القضاء على تكرار الكود. هذا له فائدة إضافية تتمثل في تمكين الشكل والمظهر المتسقين.

إليك ما يبدو عليه تطبيقك على Android و iOS والويب و macOS:

معاينة التطبيق

3. إنشاء مشروع Firebase وإعداده

يعد عرض معلومات الحدث أمرًا رائعًا لضيوفك ، ولكن مجرد عرض الأحداث ليس مفيدًا جدًا لأي شخص. دعنا نضيف بعض الوظائف الديناميكية لهذا التطبيق. لهذا ، ستحتاج إلى ربط Firebase بتطبيقك. لبدء استخدام Firebase ، ستحتاج إلى إنشاء مشروع Firebase وإعداده.

أنشئ مشروع Firebase

  1. تسجيل الدخول إلى Firebase .
  2. في وحدة تحكم Firebase، انقر فوق إضافة مشروع (أو إنشاء مشروع)، واسمك Firebase مشروع Firebase-الرفرفة-Codelab.

4395e4e67c08043a.png

  1. انقر من خلال خيارات إنشاء المشروع. اقبل شروط Firebase إذا طُلب منك ذلك. تخطي إعداد Google Analytics ، لأنك لن تستخدم Analytics لهذا التطبيق.

b7138cde5f2c7b61.png

لمعرفة المزيد حول مشاريع Firebase، انظر فهم مشاريع Firebase .

يستخدم التطبيق الذي تنشئه العديد من منتجات Firebase المتوفرة لتطبيقات الويب:

  • Firebase مصادقة إلى السماح للمستخدمين تسجيل الدخول إلى التطبيق الخاص بك.
  • سحابة Firestore لحفظ البيانات المهيكلة على السحابة والحصول على إشعار حظة عندما تغييرات البيانات.
  • قواعد الأمن Firebase لتأمين قاعدة البيانات الخاصة بك.

تحتاج بعض هذه المنتجات إلى تكوين خاص أو تحتاج إلى التمكين باستخدام وحدة تحكم Firebase.

تمكين البريد الإلكتروني تسجيل الدخول للمصادقة Firebase

للسماح للمستخدمين تسجيل الدخول إلى التطبيق على شبكة الإنترنت، عليك استخدام البريد الإلكتروني / كلمة المرور تسجيل الدخول طريقة لهذا codelab:

  1. في وحدة تحكم Firebase، توسيع بنية القائمة في لوحة اليسرى.
  2. انقر فوق المصادقة، ومن ثم انقر فوق زر البدء، ثم فوق علامة التبويب تسجيل الدخول-طريقة (أو انقر هنا للذهاب مباشرة إلى الدخول في علامة التبويب طريقة).
  3. انقر فوق بريد إلكتروني / كلمة المرور في تسجيل الدخول مقدمي القائمة، تعيين التبديل إلى وضع التشغيل تمكين، ثم انقر فوق حفظ. 58e3e3e23c2f16a4.png

تفعيل Cloud Firestore

يستخدم تطبيق الويب الغيمة Firestore لحفظ رسائل الدردشة وتلقي رسائل الدردشة الجديدة.

تمكين Cloud Firestore:

  1. في قسم بناء وحدة Firebase، انقر سحابة Firestore.
  2. انقر فوق إنشاء قاعدة البيانات. 99e8429832d23fa3.png
  1. حدد الخيار بدء وضع الاختبار في. اقرأ إخلاء المسؤولية حول قواعد الأمان. يضمن وضع الاختبار أنه يمكنك الكتابة بحرية إلى قاعدة البيانات أثناء التطوير. انقر فوق التالي. 6be00e26c72ea032.png
  1. حدد موقع قاعدة البيانات الخاصة بك (يمكنك فقط استخدام الافتراضي). لاحظ أنه لا يمكن تغيير هذا الموقع لاحقًا. 278656eefcfb0216.png
  2. انقر فوق تمكين.

4. تكوين Firebase

من أجل استخدام Firebase مع Flutter ، عليك اتباع عملية لتهيئة مشروع Flutter للاستفادة من مكتبات FlutterFire بشكل صحيح:

  • أضف تبعيات FlutterFire إلى مشروعك
  • سجل النظام الأساسي المطلوب في مشروع Firebase
  • قم بتنزيل ملف التكوين الخاص بالنظام الأساسي ، وأضفه إلى الكود.

في الدليل المستوى الأعلى من التطبيق الرفرفة الخاص، وهناك دعا الدلائل ios و android . تحتوي هذه الأدلة على ملفات التكوين الخاصة بالنظام الأساسي لنظامي التشغيل iOS و Android ، على التوالي.

تكوين التبعيات

تحتاج إلى إضافة مكتبات FlutterFire لمنتجي Firebase اللذين تستخدمهما في هذا التطبيق - Firebase Auth و Cloud Firestore. قم بتشغيل الأوامر الثلاثة التالية لإضافة التبعيات.

$ flutter pub add firebase_core
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ firebase_core 1.6.0
+ firebase_core_platform_interface 4.0.1
+ firebase_core_web 1.1.0
+ flutter_web_plugins 0.0.0 from sdk flutter
+ js 0.6.3
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 5 dependencies!

و firebase_core هو رمز مشترك المطلوبة لجميع الإضافات Firebase الرفرفة.

$ flutter pub add firebase_auth
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ firebase_auth 3.1.0
+ firebase_auth_platform_interface 6.1.0
+ firebase_auth_web 3.1.0
+ intl 0.17.0
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 4 dependencies!

و firebase_auth يتيح التكامل مع القدرة على مصادقة Firebase ل.

$ flutter pub add cloud_firestore
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ cloud_firestore 2.5.1
+ cloud_firestore_platform_interface 5.4.1
+ cloud_firestore_web 2.4.1
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 3 dependencies!

و cloud_firestore تمكن من الوصول إلى تخزين البيانات سحابة Firestore.

$ flutter pub add provider
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
  matcher 0.12.10 (0.12.11 available)
+ nested 1.0.0
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
+ provider 6.0.0
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 2 dependencies!

أثناء إضافة الحزم المطلوبة ، تحتاج أيضًا إلى تكوين مشاريع iOS و Android و macOS و Web runner لاستخدام Firebase بشكل مناسب. كنت أيضا باستخدام provider حزمة من شأنها أن تمكن فصل منطق الأعمال من منطق العرض.

تكوين iOS

  1. في وحدة التحكم Firebase ، حدد محة عامة عن المشروع في شريط التنقل الأيمن، وانقر على زر دائرة الرقابة الداخلية في ظل تبدأ بإضافة Firebase إلى التطبيق الخاص بك.

يجب أن ترى مربع الحوار التالي:

c42139f18fb9a2ee.png

  1. قيمة هامة لتوفير هي رمز الرزمة دائرة الرقابة الداخلية. تحصل على معرف الحزمة من خلال تنفيذ الخطوات الثلاث التالية.
  1. في أداة سطر الأوامر ، انتقل إلى دليل المستوى الأعلى لتطبيق Flutter.
  2. قم بتشغيل الأمر open ios/Runner.xcworkspace لفتح كسكودي.
  1. في كسكودي، انقر فوق عداء المستوى الأعلى في الجزء الأيمن، ثم حدد عداء تحت أهداف، لإظهار علامة التبويب عام في الجزء الأيسر، كما هو مبين. نسخ قيمة حزمة معرف.

9d67acd88c718763.png

  1. العودة إلى الحوار Firebase، لصق نسخ حزمة معرف في حقل ID حزمة دائرة الرقابة الداخلية، وانقر فوق تسجيل التطبيقات.
  1. استمرار في Firebase، اتبع التعليمات لتحميل ملف التكوين GoogleService-Info.plist .
  2. ارجع إلى Xcode. لاحظ أن عداء لديه فرعي يسمى أيضا عداء (كما هو موضح في الصورة السابقة).
  3. اسحب GoogleService-Info.plist ملف (الذي قمت بتحميله فقط) في هذا المجلد عداء.
  4. في مربع الحوار الذي يظهر في كسكودي، انقر فوق إنهاء.
  5. لا تتردد في إغلاق Xcode في هذه المرحلة ، لأنه ليس مطلوبًا للمضي قدمًا.
  6. ارجع إلى وحدة تحكم Firebase. في خطوة الإعداد، انقر فوق التالي، تخطى الخطوات المتبقية، والعودة إلى الصفحة الرئيسية للتعزية Firebase.

لقد انتهيت من تكوين تطبيق Flutter لنظام iOS. لمزيد من التفاصيل، يرجى الاطلاع على وثائق تركيب FlutterFire دائرة الرقابة الداخلية .

تكوين Android

  1. في وحدة التحكم Firebase ، حدد محة عامة عن المشروع في شريط التنقل الأيمن، وانقر على زر الروبوت تحت تبدأ بإضافة Firebase إلى التطبيق الخاص بك.

سترى مربع الحوار التالي: 8254fc299e82f528.png

  1. قيمة هامة لتوفير هو اسم حزمة الروبوت. تحصل على اسم الحزمة عند تنفيذ الخطوتين التاليتين:
  1. في دليل التطبيق الرفرفة، افتح ملف android/app/src/main/AndroidManifest.xml .
  2. في manifest عنصر، والعثور على قيمة سلسلة من package السمة. هذه القيمة هي اسم الحزمة الروبوت (شيء من هذا القبيل com.yourcompany.yourproject ). انسخ هذه القيمة.
  3. في مربع الحوار Firebase، لصق اسم الحزمة المنسوخة في مجال اسم الحزمة الروبوت.
  4. أنت لا تحتاج إلى تصحيح شهادة توقيع SHA-1 لهذا codelab. اترك هذا فارغًا.
  5. انقر فوق تسجيل التطبيقات.
  6. استمرار في Firebase، اتبع التعليمات لتحميل ملف التكوين google-services.json .
  7. الذهاب إلى دليل التطبيق الرفرفة الخاص بك، ونقل google-services.json ملف (الذي قمت بتحميله فقط) في android/app الدليل.
  8. ارجع إلى وحدة تحكم Firebase ، وتخطَ الخطوات المتبقية ، ثم ارجع إلى الصفحة الرئيسية لوحدة تحكم Firebase.
  9. عدل android/build.gradle لإضافة google-services المساعد التبعية:

android / build.gradle

dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.5'  // new
}
  1. عدل android/app/build.gradle لتمكين google-services المساعد:

android / app / build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'  // new
  1. يتطلب Firebase تمكين Multidex ، وإحدى طرق القيام بذلك هي تعيين الحد الأدنى من SDK المدعوم إلى 21 أو أعلى. تعديل ملفك android/app/build.gradle لتحديث minSdkVersion :

android / app / build.gradle

defaultConfig {
    applicationId "com.example.gtk_flutter"
    minSdkVersion 21  // Updated
    targetSdkVersion 30
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
}

لقد انتهيت من تكوين تطبيق Flutter لنظام Android. لمزيد من التفاصيل، يرجى الاطلاع على وثائق تركيب FlutterFire الروبوت .

تكوين للويب

  1. في وحدة التحكم Firebase ، حدد محة عامة عن المشروع في شريط التنقل الأيمن، وانقر على زر ويب ضمن تبدأ بإضافة Firebase إلى التطبيق الخاص بك.

25b14deff9e589ce.png

  1. يعطي هذا التطبيق اسم مستعار، وانقر على زر التطبيق التسجيل. سنترك استضافة Firebase معطلة لهذا البرنامج التعليمي حيث سنقوم بتشغيله محليًا فقط. لا تتردد في قراءة المزيد عن استضافة Firebase هنا. 9c697cc1b309c806.png
  2. تحرير قسم من الجسم الخاص بك web/index.html فيما يلي الملف. تأكد من إضافة firebaseConfig البيانات من الخطوة السابقة.

الويب / index.html

<body>
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('flutter-first-frame', function () {
        navigator.serviceWorker.register('flutter_service_worker.js');
      });
    }
  </script>

  <!-- Add from here -->
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-firestore.js"></script>
  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      // Replace this with your firebaseConfig
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
  </script>
  <!-- to here. -->

  <script src="main.dart.js" type="application/javascript"></script>
</body>

لقد انتهيت من تكوين تطبيق Flutter للويب. لمزيد من التفاصيل، يرجى الاطلاع على وثائق تركيب FlutterFire الويب .

تكوين macOS

خطوات التكوين لنظام macOS مطابقة تقريبًا لنظام iOS. نحن بصدد إعادة استخدام ملف التكوين GoogleService-Info.plist من دائرة الرقابة الداخلية الخطوات أعلاه.

  1. قم بتشغيل الأمر open macos/Runner.xcworkspace لفتح كسكودي.
  1. اسحب GoogleService-Info.plist الملف إلى مجلد فرعي عداء. تم إنشاء هذا في الخطوات تكوين دائرة الرقابة الداخلية أعلاه. c2b9229a605fd738.png
  2. في macos/Runner/DebugProfile.entitlements الملف، إضافة com.apple.security.network.client استحقاق، وتعيينه إلى true . 8bee5665e35d3f34.png
  3. في macos/Runner/Release.entitlements الملف، أيضا إضافة com.apple.security.network.client استحقاق، وتعيينه إلى true . 41e2e23b7928546a.png
  4. لا تتردد في إغلاق Xcode في هذه المرحلة ، لأنه ليس مطلوبًا للمضي قدمًا.

لقد انتهيت من تكوين تطبيق Flutter لنظام التشغيل macOS. لمزيد من التفاصيل، يرجى الاطلاع على وثائق تركيب FlutterFire ماك ، و دعم لسطح المكتب والرفرفة الصفحة.

5. إضافة تسجيل دخول المستخدم (RSVP)

والآن بعد أن قمت بإضافتها Firebase إلى التطبيق، يمكنك إعداد زر RSVP أن سجلات الأشخاص الذين يستخدمون مصادقة Firebase . بالنسبة لنظام التشغيل Android الأصلي ، ونظام التشغيل iOS الأصلي ، والويب ، توجد حزم FirebaseUI Auth سابقة الإنشاء ، ولكن بالنسبة إلى Flutter ، ستحتاج إلى بناء هذه الإمكانية.

تضمن المشروع الذي قمت باسترداده في الخطوة 2 مجموعة من الأدوات التي تنفذ واجهة المستخدم لمعظم تدفق المصادقة. ستنفذ منطق الأعمال لدمج مصادقة Firebase في التطبيق.

منطق الأعمال مع المزود

كنت تسير على استخدام provider حزمة لجعل كائن حالة التطبيق مركزية تتوفر في جميع أنحاء شجرة التطبيق من الحاجيات الرفرفة. في البداية، تعديل الواردات في الجزء العلوي من lib/main.dart :

lib / main.dart

import 'package:firebase_core/firebase_core.dart'; // new
import 'package:firebase_auth/firebase_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';           // new

import 'src/authentication.dart';                  // new
import 'src/widgets.dart';

ل import خطوط إدخال Firebase الأساسية وأصيل، سحب في provider حزمة الذي تستخدمه لجعل الكائن حالة التطبيق متاح من خلال شجرة القطعة، وتشمل الحاجيات المصادقة من lib/src .

هذا الكائن حالة التطبيق، ApplicationState ، واثنين من المسؤوليات الرئيسية لهذه الخطوة، ولكن سوف تكسب مسؤوليات إضافية كما يمكنك إضافة المزيد من القدرات لتطبيق في خطوات لاحقة. إن المسؤولية الأولى هي لتهيئة مكتبة Firebase مع دعوة Firebase.initializeApp() ، ثم هناك طريقة التعامل مع تدفق الترخيص. إضافة الطبقة التالية إلى نهاية lib/main.dart :

lib / main.dart

class ApplicationState extends ChangeNotifier {
  ApplicationState() {
    init();
  }

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
      } else {
        _loginState = ApplicationLoginState.loggedOut;
      }
      notifyListeners();
    });
  }

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  void startLoginFlow() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void verifyEmail(
    String email,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      var methods =
          await FirebaseAuth.instance.fetchSignInMethodsForEmail(email);
      if (methods.contains('password')) {
        _loginState = ApplicationLoginState.password;
      } else {
        _loginState = ApplicationLoginState.register;
      }
      _email = email;
      notifyListeners();
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signInWithEmailAndPassword(
    String email,
    String password,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void cancelRegistration() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void registerAccount(String email, String displayName, String password,
      void Function(FirebaseAuthException e) errorCallback) async {
    try {
      var credential = await FirebaseAuth.instance
          .createUserWithEmailAndPassword(email: email, password: password);
      await credential.user!.updateProfile(displayName: displayName);
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signOut() {
    FirebaseAuth.instance.signOut();
  }
}

تجدر الإشارة إلى بعض النقاط الرئيسية في هذا الفصل. يبدأ المستخدم في التشغيل بدون مصادقة ، ويعرض التطبيق نموذجًا يطلب عنوان البريد الإلكتروني للمستخدم ، اعتمادًا على ما إذا كان عنوان البريد الإلكتروني هذا موجودًا في الملف ، سيطلب التطبيق إما تسجيل المستخدم ، أو يطلب كلمة المرور الخاصة به ، ثم يفترض أن كل شيء يعمل ، المستخدم تمت المصادقة عليه.

وتجدر الإشارة إلى أن هذا ليس تنفيذًا كاملاً لتدفق FirebaseUI Auth ، لأنه لا يتعامل مع حالة مستخدم لديه حساب حالي يواجه مشكلة في تسجيل الدخول. ويُترك تنفيذ هذه الإمكانية الإضافية كتدريب لـ القارئ المتحمس.

دمج تدفق المصادقة

الآن أن لديك بداية حالة التطبيق حان الوقت لسلك حالة التطبيق في التهيئة التطبيق وإضافة تدفق التوثيق في HomePage . تحديث نقطة الدخول الرئيسية لدمج حالة التطبيق عبر provider الحزمة:

lib / main.dart

void main() {
  // Modify from here
  runApp(
    ChangeNotifierProvider(
      create: (context) => ApplicationState(),
      builder: (context, _) => App(),
    ),
  );
  // to here.
}

التعديل إلى main وظيفة يجعل حزمة مزود المسؤولة عن instantiating الكائن حالة التطبيق باستخدام ChangeNotifierProvider القطعة. كنت تستخدم هذه الفئة مزود محددة لأن الكائن حالة التطبيق يمتد ChangeNotifier وهذا يتيح لل provider حزمة لمعرفة متى لإعادة الحاجيات التابعة. وأخيرا، دمج حالة التطبيق مع Authentication من خلال تحديث HomePage الصورة build الأسلوب:

lib / main.dart

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          // Add from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          // to here
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
        ],
      ),
    );
  }
}

إنشاء مثيل Authentication القطعة، والتفاف عليه في Consumer القطعة. القطعة المستهلك بالطريقة المعتادة أن provider حزمة يمكن استخدامها لإعادة بناء جزء من شجرة عندما يتغير حالة التطبيق. و Authentication القطعة هو UI المصادقة الذي سيتم الآن اختبار.

اختبار تدفق المصادقة

cdf2d25e436bd48d.png

هذه هي بداية تدفق المصادقة ، حيث يمكن للمستخدم النقر على زر RSVP لبدء نموذج البريد الإلكتروني.

2a2cd6d69d172369.png

عند إدخال البريد الإلكتروني ، يؤكد النظام ما إذا كان المستخدم مسجلاً بالفعل ، وفي هذه الحالة يُطلب من المستخدم إدخال كلمة مرور ، بدلاً من ذلك إذا لم يكن المستخدم مسجلاً ، ثم يمر عبر نموذج التسجيل.

e5e65065dba36b54.png

تأكد من تجربة إدخال كلمة مرور قصيرة (أقل من ستة أحرف) للتحقق من تدفق معالجة الأخطاء. إذا تم تسجيل المستخدم ، فسيرى بدلاً من ذلك كلمة المرور.

fbb3ea35fb4f67a.png

في هذه الصفحة تأكد من إدخال كلمات مرور غير صحيحة للتحقق من معالجة الخطأ في هذه الصفحة. أخيرًا ، بمجرد تسجيل دخول المستخدم ، سترى تجربة تسجيل الدخول التي تتيح للمستخدم إمكانية تسجيل الخروج مرة أخرى.

4ed811a25b0cf816.png

وبهذا تكون قد نفذت تدفق المصادقة. تهاني!

6. اكتب رسائل إلى Cloud Firestore

إن معرفة أن المستخدمين قادمون أمر رائع ، ولكن دعنا نمنح الضيوف شيئًا آخر يفعلونه في التطبيق. ماذا لو تركوا رسائل في سجل الزوار؟ يمكنهم مشاركة سبب حماسهم للمجيء أو من يأملون في مقابلته.

لتخزين رسائل الدردشة يمكن للمستخدمين الكتابة في التطبيق، عليك استخدام سحابة Firestore .

نموذج البيانات

Cloud Firestore هي قاعدة بيانات NoSQL ، ويتم تقسيم البيانات المخزنة في قاعدة البيانات إلى مجموعات ومستندات وحقول ومجموعات فرعية. سوف تخزين كل رسالة للدردشة بوصفها وثيقة في مجموعة المستوى الأعلى يسمى guestbook .

7c20dc8424bb1d84.png

أضف رسائل إلى Firestore

في هذا القسم ، ستضيف وظيفة للمستخدمين لكتابة رسائل جديدة إلى قاعدة البيانات. أولاً ، تقوم بإضافة عناصر واجهة المستخدم (حقل النموذج وزر الإرسال) ، ثم تضيف الرمز الذي يربط هذه العناصر بقاعدة البيانات.

أولا، إضافة الواردات لل cloud_firestore حزمة و dart:async .

lib / main.dart

import 'dart:async';                                    // new
import 'package:cloud_firestore/cloud_firestore.dart';  // new
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import 'src/authentication.dart';
import 'src/widgets.dart';

لبناء عناصر واجهة المستخدم من حقل الرسالة وزر الإرسال، إضافة جليل جديد القطعة GuestBook في الجزء السفلي من lib/main.dart .

lib / main.dart

class GuestBook extends StatefulWidget {
  GuestBook({required this.addMessage});
  final FutureOr<void> Function(String message) addMessage;

  @override
  _GuestBookState createState() => _GuestBookState();
}

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Form(
        key: _formKey,
        child: Row(
          children: [
            Expanded(
              child: TextFormField(
                controller: _controller,
                decoration: const InputDecoration(
                  hintText: 'Leave a message',
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Enter your message to continue';
                  }
                  return null;
                },
              ),
            ),
            SizedBox(width: 8),
            StyledButton(
              onPressed: () async {
                if (_formKey.currentState!.validate()) {
                  await widget.addMessage(_controller.text);
                  _controller.clear();
                }
              },
              child: Row(
                children: [
                  Icon(Icons.send),
                  SizedBox(width: 4),
                  Text('SEND'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

هناك نقطتان من النقاط المثيرة للاهتمام هنا. أولاً ، أنت تقوم بإنشاء مثيل لنموذج حتى يتمكن upi من التحقق من صحة الرسالة التي تحتوي بالفعل على بعض المحتوى ، وإظهار رسالة خطأ للمستخدم إذا لم يكن هناك أي منها. الطريق إلى التحقق من صحة النموذج ينطوي على الوصول إلى الدولة النموذج خلف النموذج، ولهذا كنت تستخدم GlobalKey . لمزيد من المعلومات حول مفاتيح، وكيفية استخدامها، يرجى الاطلاع على الرفرفة القطع 101 حلقة "متى استخدم مفاتيح" .

لاحظ أيضا الطريقة التي يتم بها وضع الحاجيات بها، لديك Row ، مع TextFormField و StyledButton ، والذي يتضمن في حد ذاته Row . لاحظ أيضا TextFormField ومن لف في Expanded القطعة، وهذا قوات TextFormField لتولي أي مساحة إضافية في الصف. من أجل فهم أفضل لماذا هذا هو المطلوب، يرجى قراءة من خلال القيود فهم .

الآن بعد أن أصبح لديك عنصر واجهة مستخدم يمكّن المستخدم من إدخال بعض النص لإضافته إلى سجل الزوار ، فأنت بحاجة إلى الحصول عليه على الشاشة. للقيام بذلك، تحرير الجسم من HomePage لإضافة السطرين التاليين في الجزء السفلي من ListView الصورة الأطفال:

Header("What we'll be doing"),
Paragraph(
  'Join us for a day full of Firebase Workshops and Pizza!',
),
// Add the following two lines.
Header('Discussion'),
GuestBook(addMessage: (String message) => print(message)),

في حين أن هذا يكفي لعرض الأداة ، إلا أنه لا يكفي القيام بأي شيء مفيد. ستقوم بتحديث هذا الرمز قريبًا لجعله فعالاً.

معاينة التطبيق

ويمكن للمستخدم النقر على زر SEND يؤدي التعليمات البرمجية المتكررة أدناه. وتضيف محتويات حقل إدخال رسالة إلى guestbook مجموعة من قاعدة البيانات. على وجه التحديد، و addMessageToGuestBook يضيف طريقة محتوى الرسالة إلى مستند جديد (مع المعرف الذي تم إنشاؤه تلقائيا) إلى guestbook المجموعة.

لاحظ أن FirebaseAuth.instance.currentUser.uid هو إشارة إلى المعرف الفريد الذي تم إنشاؤه تلقائيا أن مصادقة Firebase يعطي لجميع المستخدمين المسجلين.

جعل تغيير آخر إلى lib/main.dart الملف. إضافة addMessageToGuestBook الأسلوب. ستقوم بتوصيل واجهة المستخدم وهذه القدرة معًا في الخطوة التالية.

lib / main.dart

class ApplicationState extends ChangeNotifier {

  // Current content of ApplicationState elided ...

  // Add from here
  Future<DocumentReference> addMessageToGuestBook(String message) {
    if (_loginState != ApplicationLoginState.loggedIn) {
      throw Exception('Must be logged in');
    }

    return FirebaseFirestore.instance.collection('guestbook').add(<String, dynamic>{
      'text': message,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
      'name': FirebaseAuth.instance.currentUser!.displayName,
      'userId': FirebaseAuth.instance.currentUser!.uid,
    });
  }
  // To here
}

توصيل واجهة المستخدم بقاعدة البيانات

لديك واجهة مستخدم حيث يمكن للمستخدم إدخال النص الذي يريد إضافته إلى سجل الزوار ، ولديك الرمز لإضافة الإدخال إلى Cloud Firestore. الآن كل ما عليك فعله هو توصيل الاثنين معًا. في lib/main.dart إجراء التغيير التالي إلى HomePage القطعة.

lib / main.dart

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
          // Modify from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (appState.loginState == ApplicationLoginState.loggedIn) ...[
                  Header('Discussion'),
                  GuestBook(
                    addMessage: (String message) =>
                        appState.addMessageToGuestBook(message),
                  ),
                ],
              ],
            ),
          ),
          // To here.
        ],
      ),
    );
  }
}

لقد استبدلت السطرين اللذين أضفتهما مرة أخرى في بداية هذه الخطوة بالتنفيذ الكامل. كنت مرة أخرى باستخدام Consumer<ApplicationState> لجعل حالة التطبيق متاح لجزء من شجرة كنت التقديم. يمكّنك هذا من الرد على شخص يدخل رسالة في واجهة المستخدم ، ونشرها في قاعدة البيانات. في القسم التالي ، ستختبر ما إذا كانت الرسائل المضافة قد تم نشرها في قاعدة البيانات.

اختبار إرسال الرسائل

  1. تأكد من تسجيل الدخول إلى التطبيق.
  2. أدخل رسالة مثل "يا هناك!"، ثم انقر فوق إرسال.

يؤدي هذا الإجراء إلى كتابة الرسالة إلى قاعدة بيانات Cloud Firestore. ومع ذلك ، لن ترى الرسالة بعد في تطبيق Flutter الفعلي لأنك لا تزال بحاجة إلى تنفيذ استرداد البيانات. ستفعل ذلك في الخطوة التالية.

ولكن يمكنك رؤية الرسالة المضافة حديثًا في وحدة تحكم Firebase.

في وحدة تحكم Firebase، في لوحة أجهزة القياس قاعدة البيانات ، يجب أن تشاهد guestbook جمع مع رسالتك المضافة حديثا. إذا واصلت إرسال الرسائل ، فستحتوي مجموعة دفتر الزوار على العديد من المستندات ، مثل هذا:

وحدة تحكم Firebase

713870af0b3b63c.png

7. قراءة الرسائل

من الجميل أن يتمكن الضيوف من كتابة رسائل إلى قاعدة البيانات ، لكن لا يمكنهم رؤيتها في التطبيق حتى الآن. دعونا نصلح ذلك!

مزامنة الرسائل

لعرض الرسائل ، ستحتاج إلى إضافة مستمعين يتم تشغيلهم عند تغيير البيانات ثم إنشاء عنصر واجهة مستخدم يعرض رسائل جديدة. ستضيف رمزًا إلى حالة التطبيق التي تستمع إلى الرسائل المضافة حديثًا من التطبيق.

فقط فوق GuestBook القطعة الطبقة القيمة التالية. يعرض هذا الفصل عرضًا منظمًا للبيانات التي تخزنها في Cloud Firestore.

lib / main.dart

class GuestBookMessage {
  GuestBookMessage({required this.name, required this.message});
  final String name;
  final String message;
}

في قسم ApplicationState حيث يمكنك تحديد الدولة وحاصل، إضافة خطوط جديدة التالية:

lib / main.dart

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  // Add from here
  StreamSubscription<QuerySnapshot>? _guestBookSubscription;
  List<GuestBookMessage> _guestBookMessages = [];
  List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
  // to here.

وأخيرا، في القسم تهيئة ApplicationState ، إضافة ما يلي إلى الاشتراك في استعلام عبر مجموعة وثائق عند تسجيل دخول المستخدم في، وإلغاء الاشتراك عندما تسجيل الخروج.

lib / main.dart

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        // Add from here
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // to here.
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        // Add from here
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        // to here.
      }
      notifyListeners();
    });
  }

هذا القسم هو المهم، وهنا هو المكان الذي بناء استعلام على guestbook جمع ومعالجة بالاكتتاب والغاء الاشتراك في هذه المجموعة. كنت استمع الى تيار، حيث يمكنك إعادة بناء ذاكرة التخزين المؤقت المحلية من الرسائل في guestbook جمع، وأيضا تخزين إشارة إلى هذا الاشتراك حتى تتمكن من إلغاء الاشتراك من ذلك في وقت لاحق. هناك الكثير مما يحدث هنا ، ومن الجدير قضاء بعض الوقت في مصحح الأخطاء لفحص ما يحدث عند الحصول على نموذج عقلي أوضح.

لمزيد من المعلومات، راجع وثائق سحابة Firestore .

في GuestBook القطعة تحتاج إلى ربط هذه الدولة تغيير واجهة المستخدم. يمكنك تعديل الأداة عن طريق إضافة قائمة بالرسائل كجزء من تكوينها.

lib / main.dart

class GuestBook extends StatefulWidget {
  // Modify the following line
  GuestBook({required this.addMessage, required this.messages});
  final FutureOr<void> Function(String message) addMessage;
  final List<GuestBookMessage> messages; // new

  @override
  _GuestBookState createState() => _GuestBookState();
}

وبعد ذلك، علينا أن نفضح هذا التكوين الجديد في _GuestBookState عن طريق تعديل build الأسلوب كما يلي.

lib / main.dart

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  // Modify from here
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // to here.
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Form(
            key: _formKey,
            child: Row(
              children: [
                Expanded(
                  child: TextFormField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'Leave a message',
                    ),
                    validator: (value) {
                      if (value == null || value.isEmpty) {
                        return 'Enter your message to continue';
                      }
                      return null;
                    },
                  ),
                ),
                SizedBox(width: 8),
                StyledButton(
                  onPressed: () async {
                    if (_formKey.currentState!.validate()) {
                      await widget.addMessage(_controller.text);
                      _controller.clear();
                    }
                  },
                  child: Row(
                    children: [
                      Icon(Icons.send),
                      SizedBox(width: 4),
                      Text('SEND'),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
        // Modify from here
        SizedBox(height: 8),
        for (var message in widget.messages)
          Paragraph('${message.name}: ${message.message}'),
        SizedBox(height: 8),
        // to here.
      ],
    );
  }
}

كنت التفاف المحتوى السابق من طريقة بناء مع Column القطعة، وبعد ذلك في ذيل Column الصورة أطفال إضافة لجمع لتوليد جديدة Paragraph لكل رسالة في قائمة الرسائل.

وأخيرا، تحتاج الآن لتحديث جسد HomePage لبناء صحيح GuestBook مع جديدة messages المعلمة.

lib / main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages, // new
        ),
      ],
    ],
  ),
),

اختبار مزامنة الرسائل

يقوم Cloud Firestore تلقائيًا وعلى الفور بمزامنة البيانات مع العملاء المشتركين في قاعدة البيانات.

  1. يجب أن يتم عرض الرسائل التي قمت بإنشائها مسبقًا في قاعدة البيانات في التطبيق. لا تتردد في كتابة رسائل جديدة ؛ يجب أن تظهر على الفور.
  2. إذا فتحت مساحة العمل الخاصة بك في نوافذ أو علامات تبويب متعددة ، فستتم مزامنة الرسائل في الوقت الفعلي عبر علامات التبويب.
  3. (اختياري) يمكنك محاولة يدويا حذف أو تعديل أو إضافة الرسائل الجديدة مباشرة في قسم قاعدة البيانات من وحدة التحكم Firebase. يجب أن تظهر أي تغييرات في واجهة المستخدم.

تهانينا! أنت تقرأ مستندات Cloud Firestore في تطبيقك!

مراجعة ص التطبيق

8. قم بإعداد قواعد الأمان الأساسية

لقد قمت في البداية بإعداد Cloud Firestore لاستخدام وضع الاختبار ، مما يعني أن قاعدة البيانات الخاصة بك مفتوحة للقراءة والكتابة. ومع ذلك ، يجب عليك استخدام وضع الاختبار فقط خلال المراحل المبكرة جدًا من التطوير. كأفضل ممارسة ، يجب عليك إعداد قواعد أمان لقاعدة البيانات الخاصة بك أثناء تطوير تطبيقك. يجب أن يكون الأمان جزءًا لا يتجزأ من بنية التطبيق وسلوكه.

تسمح لك قواعد الأمان بالتحكم في الوصول إلى المستندات والمجموعات الموجودة في قاعدة البيانات الخاصة بك. تسمح لك بنية القواعد المرنة بإنشاء قواعد تطابق أي شيء بدءًا من جميع عمليات الكتابة إلى قاعدة البيانات بأكملها وحتى العمليات في مستند معين.

يمكنك كتابة قواعد أمان لـ Cloud Firestore في وحدة تحكم Firebase:

  1. في تطوير القسم وحدة Firebase، وانقر فوق قاعدة البيانات، ثم حدد علامة التبويب قواعد (أو انقر هنا للذهاب مباشرة إلى علامة التبويب قواعد).
  2. يجب أن تشاهد قواعد الأمان الافتراضية التالية ، جنبًا إلى جنب مع تحذير حول كون القواعد عامة.

7767a2d2e64e7275.png

تحديد المجموعات

أولاً ، حدد المجموعات التي يكتب التطبيق البيانات إليها.

في match /databases/{database}/documents ، وتحديد المجموعة التي تريد تأمين:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
     // You'll add rules here in the next step.
  }
}

أضف قواعد الأمان

نظرًا لأنك استخدمت UID للمصادقة كحقل في كل مستند في دفتر الزوار ، يمكنك الحصول على UID للمصادقة والتحقق من أن أي شخص يحاول الكتابة إلى المستند لديه UID مطابق.

أضف قواعد القراءة والكتابة إلى مجموعة القواعد الخاصة بك كما هو موضح أدناه:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
        if request.auth.uid == request.resource.data.userId;
    }
  }
}

الآن ، بالنسبة إلى دفتر الزوار ، يمكن فقط للمستخدمين الذين سجلوا الدخول قراءة الرسائل (أي رسالة!) ، ولكن مؤلف الرسالة فقط هو من يمكنه تحرير الرسالة.

أضف قواعد التحقق من الصحة

أضف التحقق من صحة البيانات للتأكد من أن جميع الحقول المتوقعة موجودة في المستند:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
      if request.auth.uid == request.resource.data.userId
          && "name" in request.resource.data
          && "text" in request.resource.data
          && "timestamp" in request.resource.data;
    }
  }
}

9. خطوة إضافية: تدرب على ما تعلمته

سجل حالة الرد على دعوة الحضور

في الوقت الحالي ، يتيح تطبيقك للأشخاص بدء الدردشة إذا كانوا مهتمين بالحدث. أيضًا ، الطريقة الوحيدة التي تعرف بها ما إذا كان شخص ما سيأتي هي نشره في الدردشة. دعنا ننظم ونجعل الناس يعرفون عدد الأشخاص القادمين.

ستضيف بعض الإمكانيات الجديدة إلى حالة التطبيق. الأول هو قدرة المستخدم الذي قام بتسجيل الدخول على الترشيح إذا كان يحضر أم لا. القدرة الثانية هي عداد لعدد الأشخاص الذين يحضرون بالفعل.

في lib/main.dart ، إضافة ما يلي إلى قسم accessors لتمكين رمز UI للتفاعل مع هذه الدولة:

lib / main.dart

int _attendees = 0;
int get attendees => _attendees;

Attending _attending = Attending.unknown;
StreamSubscription<DocumentSnapshot>? _attendingSubscription;
Attending get attending => _attending;
set attending(Attending attending) {
  final userDoc = FirebaseFirestore.instance
      .collection('attendees')
      .doc(FirebaseAuth.instance.currentUser!.uid);
  if (attending == Attending.yes) {
    userDoc.set({'attending': true});
  } else {
    userDoc.set({'attending': false});
  }
}

تحديث ApplicationState الصورة init الأسلوب كما يلي:

lib / main.dart

  Future<void> init() async {
    await Firebase.initializeApp();

    // Add from here
    FirebaseFirestore.instance
        .collection('attendees')
        .where('attending', isEqualTo: true)
        .snapshots()
        .listen((snapshot) {
      _attendees = snapshot.docs.length;
      notifyListeners();
    });
    // To here

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // Add from here
        _attendingSubscription = FirebaseFirestore.instance
            .collection('attendees')
            .doc(user.uid)
            .snapshots()
            .listen((snapshot) {
          if (snapshot.data() != null) {
            if (snapshot.data()!['attending']) {
              _attending = Attending.yes;
            } else {
              _attending = Attending.no;
            }
          } else {
            _attending = Attending.unknown;
          }
          notifyListeners();
        });
        // to here
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        _attendingSubscription?.cancel(); // new
      }
      notifyListeners();
    });
  }

يضيف ما ورد أعلاه استعلامًا مشتركًا دائمًا لمعرفة عدد الحاضرين ، واستعلامًا ثانيًا يكون نشطًا فقط أثناء تسجيل دخول المستخدم لمعرفة ما إذا كان المستخدم سيحضر أم لا. المقبل، إضافة التعداد التالية بعد GuestBookMessage إعلان:

lib / main.dart

enum Attending { yes, no, unknown }

أنت الآن بصدد تحديد أداة جديدة تعمل مثل أزرار الاختيار القديمة. يبدأ في حالة غير محددة ، مع عدم تحديد "نعم" أو "لا" ، ولكن بمجرد أن يحدد المستخدم ما إذا كان سيحضر أم لا ، فإنك تعرض هذا الخيار مميزًا بزر معبأ ، ويتراجع الخيار الآخر مع عرض مسطح.

lib / main.dart

class YesNoSelection extends StatelessWidget {
  const YesNoSelection({required this.state, required this.onSelection});
  final Attending state;
  final void Function(Attending selection) onSelection;

  @override
  Widget build(BuildContext context) {
    switch (state) {
      case Attending.yes:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              TextButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      case Attending.no:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              TextButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      default:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              StyledButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              StyledButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
    }
  }
}

بعد ذلك، تحتاج إلى تحديث HomePage الصورة طريقة البناء للاستفادة من YesNoSelection ، مما يمكن من قاموا بتسجيل الدخول إلى ترشيح اذا كانوا يحضرون. ستعرض أيضًا عدد الحاضرين لهذا الحدث.

lib / main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Add from here
      if (appState.attendees >= 2)
        Paragraph('${appState.attendees} people going')
      else if (appState.attendees == 1)
        Paragraph('1 person going')
      else
        Paragraph('No one going'),
      // To here.
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        // Add from here
        YesNoSelection(
          state: appState.attending,
          onSelection: (attending) => appState.attending = attending,
        ),
        // To here.
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages,
        ),
      ],
    ],
  ),
),

أضف القواعد

نظرًا لأن لديك بالفعل بعض القواعد التي تم إعدادها ، فسيتم رفض البيانات الجديدة التي تضيفها باستخدام الأزرار. سوف تحتاج إلى تحديث القواعد للسماح بإضافة إلى attendees جمع.

ل attendees جمع، منذ كنت تستخدم مصادقة UID مثل اسم المستند، يمكنك الاستيلاء عليها والتحقق من أن مقدم على uid هو نفس الوثيقة التي تقوم بكتابتها. ستسمح للجميع بقراءة قائمة الحضور (نظرًا لعدم وجود بيانات خاصة هناك) ، ولكن يجب أن يتمكن المنشئ فقط من تحديثها.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

أضف قواعد التحقق من الصحة

أضف التحقق من صحة البيانات للتأكد من أن جميع الحقول المتوقعة موجودة في المستند:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId
          && "attending" in request.resource.data;

    }
  }
}

(اختياري) يمكنك الآن عرض نتائج النقر على الأزرار. انتقل إلى لوحة معلومات Cloud Firestore في وحدة تحكم Firebase.

معاينة التطبيق

10. مبروك!

لقد استخدمت Firebase لإنشاء تطبيق ويب تفاعلي في الوقت الفعلي!

ما غطينا

  • مصادقة Firebase
  • سحابة Firestore
  • قواعد أمان Firebase

الخطوات التالية

  • هل تريد معرفة المزيد عن منتجات Firebase الأخرى؟ ربما تريد تخزين ملفات الصور التي يقوم المستخدمون بتحميلها؟ أو إرسال إخطارات إلى المستخدمين لديك؟ تحقق من وثائق Firebase . هل تريد معرفة المزيد حول مكونات Flutter الإضافية لـ Firebase؟ تحقق من FlutterFire لمزيد من المعلومات.
  • هل تريد معرفة المزيد عن Cloud Firestore؟ ربما تريد التعرف على المجموعات الفرعية والمعاملات؟ رئيس لأكثر من codelab الويب الغيمة Firestore لcodelab أن يذهب إلى عمق أكثر على سحابة Firestore. أو تحقق من هذه السلسلة يوتيوب للتعرف على الغيمة Firestore !

يتعلم أكثر

كيف سار الأمر؟

نحن نحب ملاحظاتك! يرجى ملء (جدا) شكل قصيرة هنا .