توسعه محلی برای برنامه های Flutter شما با استفاده از Firebase Emulator Suite

1. قبل از شروع

در این کد لبه، نحوه استفاده از Firebase Emulator Suite با Flutter را در طول توسعه محلی یاد خواهید گرفت. نحوه استفاده از احراز هویت رمز عبور ایمیل از طریق Emulator Suite و نحوه خواندن و نوشتن داده ها در شبیه ساز Firestore را خواهید آموخت. در نهایت، شما با وارد کردن و صادر کردن داده ها از شبیه سازها کار خواهید کرد تا هر بار که به برنامه توسعه بازگردید، با همان داده های جعلی کار کنید.

پیش نیازها

این کد لبه فرض می کند که شما تجربه فلاتر دارید. اگر نه، ممکن است بخواهید ابتدا اصول اولیه را یاد بگیرید. لینک های زیر مفید هستند:

شما همچنین باید تجربه Firebase داشته باشید، اما اگر هرگز Firebase را به پروژه Flutter اضافه نکرده باشید، اشکالی ندارد. اگر با کنسول Firebase آشنا نیستید یا کاملاً با Firebase تازه کار هستید، ابتدا پیوندهای زیر را ببینید:

آنچه شما ایجاد خواهید کرد

این کد لبه شما را از طریق ساختن یک اپلیکیشن ساده Journaling راهنمایی می کند. این برنامه دارای یک صفحه ورود به سیستم و یک صفحه است که به شما امکان می دهد ورودی های مجله های گذشته را بخوانید و موارد جدید ایجاد کنید.

cd5c4753bbee8af.png8cb4d21f656540bf.png

چیزی که یاد خواهید گرفت

شما یاد خواهید گرفت که چگونه استفاده از Firebase را شروع کنید، و چگونه مجموعه Firebase Emulator را در گردش کار توسعه Flutter خود ادغام و استفاده کنید. این موضوعات Firebase پوشش داده خواهد شد:

توجه داشته باشید که این موضوعات تا جایی که برای پوشش مجموعه شبیه ساز Firebase لازم است پوشش داده می شوند. این کد لبه روی افزودن یک پروژه Firebase به برنامه Flutter شما و توسعه با استفاده از Firebase Emulator Suite متمرکز است. بحث های عمیقی در مورد احراز هویت Firebase یا Firestore وجود نخواهد داشت. اگر با این موضوعات آشنا نیستید، توصیه می کنیم با آشنایی با Firebase برای Flutter Codelab شروع کنید.

آنچه شما نیاز دارید

  • دانش کاری Flutter و SDK نصب شده است
  • ویرایشگرهای متن Intellij JetBrains یا VS Code
  • مرورگر Google Chrome (یا دیگر هدف توسعه ترجیحی شما برای Flutter. برخی از دستورات ترمینال در این کد لبه فرض می کنند که شما برنامه خود را در Chrome اجرا می کنید)

2. یک پروژه Firebase ایجاد و راه اندازی کنید

اولین کاری که باید انجام دهید ایجاد یک پروژه Firebase در کنسول وب Firebase است. اکثریت قریب به اتفاق این کد لبه بر روی Emulator Suite تمرکز دارد که از یک رابط کاربری محلی در حال اجرا استفاده می کند، اما ابتدا باید یک پروژه Firebase کامل را راه اندازی کنید.

یک پروژه Firebase ایجاد کنید

  1. وارد کنسول Firebase شوید.
  2. در کنسول Firebase، روی افزودن پروژه (یا ایجاد پروژه ) کلیک کنید و نامی برای پروژه Firebase خود وارد کنید (به عنوان مثال، " Firebase-Flutter-Codelab") .

fe6aeab3b91965ed.png

  1. روی گزینه های ایجاد پروژه کلیک کنید. در صورت درخواست، شرایط Firebase را بپذیرید. از تنظیم Google Analytics صرفنظر کنید، زیرا از Analytics برای این برنامه استفاده نخواهید کرد.

d1fcec48bf251eaa.png

برای کسب اطلاعات بیشتر درباره پروژه‌های Firebase، به درک پروژه‌های Firebase مراجعه کنید.

برنامه‌ای که می‌سازید از دو محصول Firebase استفاده می‌کند که برای برنامه‌های Flutter در دسترس هستند:

  • احراز هویت Firebase به کاربران شما اجازه می دهد به برنامه شما وارد شوند.
  • Cloud Firestore برای ذخیره داده های ساختاریافته در فضای ابری و دریافت اعلان فوری هنگام تغییر داده ها.

این دو محصول نیاز به پیکربندی خاصی دارند یا باید با استفاده از کنسول Firebase فعال شوند.

Cloud Firestore را فعال کنید

برنامه Flutter از Cloud Firestore برای ذخیره ورودی های مجله استفاده می کند.

Cloud Firestore را فعال کنید:

  1. در بخش ساخت کنسول Firebase، روی Cloud Firestore کلیک کنید.
  2. روی ایجاد پایگاه داده کلیک کنید. 99e8429832d23fa3.png
  3. گزینه Start in test mode را انتخاب کنید. سلب مسئولیت در مورد قوانین امنیتی را بخوانید. حالت تست تضمین می کند که شما می توانید آزادانه در طول توسعه در پایگاه داده بنویسید. روی Next کلیک کنید. 6be00e26c72ea032.png
  4. مکان پایگاه داده خود را انتخاب کنید (فقط می توانید از پیش فرض استفاده کنید). توجه داشته باشید که این مکان بعداً قابل تغییر نیست. 278656eefcfb0216.png
  5. روی Enable کلیک کنید.

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 احراز هویت کنید.

  1. با اجرای دستور زیر با استفاده از حساب Google خود وارد Firebase شوید:
firebase login
  1. این دستور ماشین محلی شما را به Firebase متصل می کند و به شما امکان دسترسی به پروژه های Firebase را می دهد.
  1. با فهرست کردن پروژه های Firebase خود، بررسی کنید که CLI به درستی نصب شده است و به حساب شما دسترسی دارد. دستور زیر را اجرا کنید:
firebase projects:list
  1. لیست نمایش داده شده باید مانند پروژه های Firebase لیست شده در کنسول Firebase باشد. شما باید حداقل firebase-flutter-codelab را ببینید.

FlutterFire CLI را نصب کنید

FlutterFire CLI در بالای Firebase CLI ساخته شده است و ادغام یک پروژه Firebase با برنامه Flutter شما را آسان‌تر می‌کند.

ابتدا CLI را نصب کنید:

dart pub global activate flutterfire_cli

مطمئن شوید که CLI نصب شده است. دستور زیر را در دایرکتوری پروژه Flutter اجرا کنید و اطمینان حاصل کنید که CLI منوی Help را خروجی می کند.

flutterfire --help

از Firebase CLI و FlutterFire CLI برای اضافه کردن پروژه Firebase به برنامه Flutter خود استفاده کنید

با نصب دو CLI، می‌توانید محصولات Firebase جداگانه (مانند Firestore) را راه‌اندازی کنید، شبیه‌سازها را دانلود کنید و Firebase را تنها با چند دستور ترمینال به برنامه Flutter خود اضافه کنید.

ابتدا راه اندازی Firebase را با اجرای موارد زیر به پایان برسانید:

firebase init

این دستور شما را از طریق یک سری سوالات مورد نیاز برای راه اندازی پروژه راهنمایی می کند. این اسکرین شات ها جریان را نشان می دهند:

  1. هنگامی که از شما خواسته شد ویژگی ها را انتخاب کنید، "Firestore" و "Emulators" را انتخاب کنید. (هیچ گزینه Authentication وجود ندارد، زیرا از پیکربندی قابل تغییر از فایل های پروژه Flutter شما استفاده نمی کند.) fe6401d769be8f53.png
  2. بعد، وقتی از شما خواسته شد، «استفاده از پروژه موجود» را انتخاب کنید.

f11dcab439e6ac1e.png

  1. اکنون پروژه ای را که در مرحله قبل ایجاد کرده اید انتخاب کنید: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. در مرحله بعد، از شما یک سری سوالات در مورد نامگذاری فایل هایی که تولید می شوند پرسیده می شود. پیشنهاد می‌کنم برای انتخاب سؤال پیش‌فرض، «Enter» را فشار دهید. 9bfa2d507e199c59.png
  2. در نهایت، باید شبیه سازها را پیکربندی کنید. Firestore and Authentication را از لیست انتخاب کنید و سپس "Enter" را برای هر سوال در مورد پورت های خاص برای استفاده برای هر شبیه ساز فشار دهید. وقتی از شما پرسیده می شود که آیا می خواهید از رابط کاربری شبیه ساز استفاده کنید، باید حالت پیش فرض، بله را انتخاب کنید.

در پایان فرآیند، باید خروجی ای را مشاهده کنید که شبیه تصویر زیر است.

مهم : خروجی شما ممکن است کمی متفاوت از من باشد، همانطور که در تصویر زیر مشاهده می شود، زیرا اگر شبیه سازها را قبلا دانلود کرده باشید، سوال نهایی به طور پیش فرض روی "نه" خواهد بود.

8544e41037637b07.png

FlutterFire را پیکربندی کنید

در مرحله بعد، می توانید از FlutterFire برای تولید کد Dart مورد نیاز برای استفاده از Firebase در برنامه Flutter خود استفاده کنید.

flutterfire configure

هنگامی که این دستور اجرا می شود، از شما خواسته می شود که از کدام پروژه Firebase استفاده کنید و کدام پلتفرم را می خواهید تنظیم کنید. در این کد لبه، نمونه ها از Flutter Web استفاده می کنند، اما می توانید پروژه Firebase خود را برای استفاده از همه گزینه ها تنظیم کنید.

اسکرین شات های زیر درخواست هایی را نشان می دهند که باید به آنها پاسخ دهید.

619b7aca6dc15472.png301c9534f594f472.png

این اسکرین شات خروجی را در پایان فرآیند نشان می دهد. اگر با Firebase آشنا باشید، متوجه خواهید شد که نیازی به ایجاد اپلیکیشن در کنسول ندارید و FlutterFire CLI این کار را برای شما انجام داده است.

12199a85ade30459.png

بسته های Firebase را به برنامه Flutter اضافه کنید

مرحله نهایی راه اندازی این است که بسته های Firebase مربوطه را به پروژه 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.

اصلی.دارت

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

این دستور شبیه سازها را بوت می کند و پورت های لوکال هاست را نشان می دهد که می توانیم با آنها تعامل داشته باشیم. هنگامی که آن دستور را اجرا می کنید، باید خروجی مشابه این را ببینید:

bb7181eb70829606.png

این خروجی به شما می گوید که کدام شبیه سازها در حال اجرا هستند و برای دیدن شبیه سازها می توانید به کجا بروید. ابتدا، رابط کاربری شبیه ساز را در localhost:4000 بررسی کنید.

11563f4c7216de81.png

این صفحه اصلی رابط کاربری شبیه ساز محلی است. تمام شبیه سازهای موجود را فهرست می کند و هر کدام با برچسب وضعیت روشن یا خاموش هستند.

5. شبیه ساز Firebase Auth

اولین شبیه‌سازی که از آن استفاده می‌کنید، شبیه‌ساز Authentication است. با شبیه‌ساز Auth با کلیک کردن روی «برو به شبیه‌ساز» در کارت تأیید هویت در رابط کاربری شروع کنید، و صفحه‌ای را مشاهده خواهید کرد که شبیه به این است:

3c1bfded40733189.png

این صفحه شباهت هایی به صفحه کنسول وب Auth دارد. این دارای جدولی است که کاربران را مانند کنسول آنلاین لیست می کند و به شما امکان می دهد به صورت دستی کاربران را اضافه کنید. یک تفاوت بزرگ در اینجا این است که تنها گزینه روش احراز هویت موجود در شبیه سازها از طریق ایمیل و رمز عبور است. این برای توسعه محلی کافی است.

در مرحله بعد، فرآیند افزودن یک کاربر به شبیه ساز Firebase Auth و سپس ورود آن کاربر از طریق Flutter UI را طی خواهید کرد.

یک کاربر اضافه کنید

روی دکمه "افزودن کاربر" کلیک کنید و فرم را با این اطلاعات پر کنید:

  • نام نمایشی: Dash
  • ایمیل: 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 را با ایمیل و رمز عبوری که در شبیه ساز auth ایجاد کرده اید، جایگزین می کند. و در خط بعدی، خط if(true) با کدی جایگزین شده است که بررسی می کند که آیا state.user null است یا خیر. کد موجود در 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 است که در مرحله بعد به آن پرداخته خواهد شد.

TODO: Action Icon – برنامه خود را مجدداً بارگیری کنید و سپس دکمه ورود را هنگام رندر فشار دهید. این باعث می‌شود که برنامه به صفحه‌ای بروید که می‌گوید "به بازگشت خوش آمدید، شخص!" در بالا احراز هویت باید کار کند، زیرا به شما امکان می‌دهد به این صفحه بروید، اما برای نمایش نام واقعی کاربر باید یک به‌روزرسانی جزئی در logged_in_view.dart انجام شود.

loged_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 UI ( localhost:4000 )، روی "Go to emulator" در کارت Firestore کلیک کنید. باید به این شکل باشد:

شبیه ساز:

791fce7dc137910a.png

کنسول Firebase:

e0dde9aea34af050.png

اگر تجربه ای با Firestore دارید، متوجه خواهید شد که این صفحه شبیه به صفحه Firestore کنسول Firebase است. اگرچه چند تفاوت قابل توجه وجود دارد.

  1. شما می توانید تمام داده ها را با ضربه زدن یک دکمه پاک کنید. این برای داده های تولید خطرناک است، اما برای تکرار سریع مفید است! اگر روی پروژه جدیدی کار می کنید و مدل داده شما تغییر می کند، پاک کردن آن آسان است.
  2. یک برگه "درخواست ها" وجود دارد. این تب به شما اجازه می دهد تا درخواست های دریافتی ارسال شده به این شبیه ساز را مشاهده کنید. من در مورد این برگه با جزئیات بیشتر صحبت خواهم کرد.
  3. هیچ برگه ای برای قوانین، شاخص ها یا استفاده وجود ندارد. ابزاری وجود دارد (که در بخش بعدی بحث شد) که به نوشتن قوانین امنیتی کمک می کند، اما نمی توانید قوانین امنیتی را برای شبیه ساز محلی تنظیم کنید.

به طور خلاصه، این نسخه از Firestore ابزارهای مفید بیشتری در طول توسعه ارائه می دهد و ابزارهایی را که در تولید مورد نیاز هستند حذف می کند.

برای Firestor بنویسید

قبل از بحث در مورد برگه «درخواست‌ها» در شبیه‌ساز، ابتدا یک درخواست ارائه دهید. این به به روز رسانی کد نیاز دارد. برای نوشتن یک ژورنال جدید Entry to Firestore با سیم کشی فرم در برنامه شروع کنید.

جریان سطح بالا برای ارسال یک Entry :

  1. کاربر فرم را پر می کند و دکمه Submit فشار می دهد
  2. رابط کاربری AppState.writeEntryToFirebase را فراخوانی می کند
  3. 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> باشد.

در این مورد، مجموعه "Entries" در Firestore وجود نداشت، بنابراین Firestore یکی را ایجاد کرد.

با اضافه شدن آن کد، برنامه خود را دوباره بارگیری یا راه اندازی مجدد کنید، وارد شوید و به نمای EntryForm بروید. می توانید فرم را با هر Strings که می خواهید پر کنید. (فیلد Date هر رشته ای را می گیرد، همانطور که برای این کد لبه ساده شده است. به هیچ وجه اعتبارسنجی قوی یا اهمیتی به اشیاء DateTime ندارد.)

ارسال را در فرم فشار دهید. هیچ اتفاقی در برنامه نمی افتد، اما می توانید ورودی جدید خود را در رابط کاربری شبیه ساز ببینید.

تب درخواست ها در شبیه ساز Firestore

در رابط کاربری، به شبیه ساز Firestore بروید و به برگه «داده» نگاه کنید. باید ببینید که اکنون یک مجموعه در ریشه پایگاه داده شما وجود دارد به نام "Entries". باید سندی داشته باشد که حاوی همان اطلاعاتی باشد که شما در فرم وارد کرده اید.

a978fb34fb8a83da.png

این تأیید می کند که AppState.writeEntryToFirestore کار می کرد، و اکنون می توانید درخواست را در برگه Requests بررسی کنید. اکنون روی آن برگه کلیک کنید.

درخواست های شبیه ساز Firestore

در اینجا، باید لیستی را مشاهده کنید که شبیه به این است:

f0b37f0341639035.png

می‌توانید روی هر یک از موارد فهرست کلیک کنید و اطلاعات مفیدی را مشاهده کنید. بر روی آیتم CREATE لیست که با درخواست شما برای ایجاد یک مدخل مجله جدید مطابقت دارد، کلیک کنید. جدول جدیدی را می بینید که به شکل زیر است:

385d62152e99aad4.png

همانطور که گفته شد، شبیه ساز Firestore ابزارهایی را برای توسعه قوانین امنیتی برنامه شما فراهم می کند. این نما دقیقاً نشان می دهد که این درخواست از چه خطی در قوانین امنیتی شما عبور کرده است (اگر چنین بود). در یک برنامه قوی تر، قوانین امنیتی می تواند رشد کند و چندین بررسی مجوز داشته باشد. این نما برای کمک به نوشتن و رفع اشکال آن قوانین مجوز استفاده می شود.

همچنین یک راه آسان برای بازرسی هر بخش از این درخواست، از جمله ابرداده و داده‌های احراز هویت ارائه می‌کند. این داده ها برای نوشتن قوانین پیچیده مجوز استفاده می شود.

خواندن از Firestor

Firestore از همگام سازی داده ها برای ارسال داده های به روز شده به دستگاه های متصل استفاده می کند. در کد فلاتر، می‌توانید به مجموعه‌ها و اسناد Firestore گوش دهید (یا مشترک شوید) و هر زمان که داده‌ها تغییر کنند، کد شما مطلع می‌شود. در این برنامه، گوش دادن به به‌روزرسانی‌های Firestore به روشی به نام AppState._listenForEntries انجام می‌شود.

این کد به ترتیب با StreamController و Stream به نام AppState._entriesStreamController و AppState.entries کار می کند. آن کد از قبل نوشته شده است، همانطور که تمام کدهای مورد نیاز در UI برای نمایش داده ها از 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);
   });
 }
 // ...
}

این کد به مجموعه "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!');
 }
}
// ...

حالا برنامه را اجرا کنید. باید به این شکل باشد:

b8a31c7a8900331.gif

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. تبریک!

شما Get up and running را با شبیه ساز Firebase و Flutter کامل کرده اید. شما می توانید کد تکمیل شده برای این Codelab را در فهرست "کامل" در github پیدا کنید: Flutter Codelabs

آنچه را پوشش داده ایم

  • راه اندازی یک برنامه Flutter برای استفاده از Firebase
  • راه اندازی پروژه Firebase
  • FlutterFire CLI
  • Firebase CLI
  • شبیه ساز Firebase Authentication
  • شبیه ساز Firebase Firestore
  • واردات و صادرات داده های شبیه ساز

مراحل بعدی

بیشتر بدانید

اسپارکی به شما افتخار می کند!

2a0ad195769368b1.gif