Phát triển cục bộ cho ứng dụng Flutter bằng Bộ công cụ mô phỏng Firebase

1. Trước khi bắt đầu

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách sử dụng Bộ mô phỏng Firebase với Flutter trong quá trình phát triển cục bộ. Bạn sẽ tìm hiểu cách sử dụng tính năng xác thực mật khẩu email thông qua Bộ mô phỏng, cũng như cách đọc và ghi dữ liệu vào trình mô phỏng Firestore. Cuối cùng, bạn sẽ làm việc với việc nhập và xuất dữ liệu qua trình mô phỏng để làm việc với cùng một dữ liệu giả mỗi khi bạn quay lại quá trình phát triển.

Điều kiện tiên quyết

Lớp học lập trình này giả định rằng bạn đã có một số kinh nghiệm về Flutter. Nếu chưa thì bạn nên tìm hiểu những kiến thức cơ bản trước. Bạn có thể tham khảo những đường liên kết sau đây:

Mặc dù bạn cũng cần có một số kinh nghiệm về Firebase, nhưng nếu bạn chưa từng thêm Firebase vào dự án Flutter thì cũng không sao. Nếu bạn chưa hiểu rõ về bảng điều khiển của Firebase hoặc bạn hoàn toàn mới sử dụng Firebase, trước tiên, hãy xem các đường liên kết sau:

Nội dung bạn sẽ tạo

Lớp học lập trình này hướng dẫn bạn cách xây dựng một ứng dụng ghi nhật ký đơn giản. Ứng dụng sẽ có màn hình đăng nhập và màn hình cho phép bạn đọc các mục nhập nhật ký trước đây và tạo mục nhập mới.

cd5c4753bbee8af.png. 8cb4d21f656540bf.png.

Kiến thức bạn sẽ học được

Bạn sẽ tìm hiểu cách bắt đầu sử dụng Firebase, cũng như cách tích hợp và sử dụng bộ công cụ Trình mô phỏng Firebase vào quy trình phát triển Flutter. Các chủ đề sau đây về Firebase sẽ được đề cập:

Xin lưu ý rằng các chủ đề này chỉ được đề cập trong phạm vi yêu cầu để đề cập đến bộ trình mô phỏng Firebase. Lớp học lập trình này tập trung vào việc thêm dự án Firebase vào ứng dụng Flutter và phát triển bằng Bộ mô phỏng Firebase. Sẽ không có các cuộc thảo luận chuyên sâu về Xác thực Firebase hoặc Firestore. Nếu chưa hiểu rõ về các chủ đề này, bạn nên bắt đầu từ Lớp học lập trình Làm quen với Firebase dành cho Flutter.

Bạn cần có

  • Có kiến thức thực hành về Flutter và SDK đã cài đặt
  • Trình soạn thảo văn bản Intellij JetBrains hoặc VS Code
  • Trình duyệt Google Chrome (hoặc mục tiêu phát triển khác mà bạn ưu tiên dùng cho Flutter. Một số lệnh dòng lệnh trong lớp học lập trình này sẽ giả định rằng bạn đang chạy ứng dụng trên Chrome)

2. Tạo và thiết lập dự án Firebase

Việc đầu tiên bạn cần hoàn thành là tạo dự án Firebase trong bảng điều khiển web của Firebase. Phần lớn nội dung trong lớp học lập trình này sẽ tập trung vào Bộ mô phỏng. Bộ công cụ này sử dụng giao diện người dùng chạy cục bộ, nhưng trước tiên, bạn phải thiết lập một dự án Firebase đầy đủ.

Tạo một dự án Firebase

  1. Đăng nhập vào bảng điều khiển của Firebase.
  2. Trong bảng điều khiển của Firebase, hãy nhấp vào Thêm dự án (hoặc Tạo dự án) và nhập tên cho dự án Firebase của bạn (ví dụ: "Firebase-Flutter-Codelab").

fe6aeab3b91965ed.png.

  1. Nhấp vào các lựa chọn tạo dự án. Chấp nhận các điều khoản của Firebase nếu được nhắc. Bỏ qua bước thiết lập Google Analytics vì bạn sẽ không sử dụng Analytics cho ứng dụng này.

d1fcec48bf251eaa.png.

Để tìm hiểu thêm về các dự án Firebase, hãy xem bài viết Tìm hiểu về các dự án Firebase.

Ứng dụng bạn đang tạo sử dụng 2 sản phẩm Firebase có sẵn cho các ứng dụng Flutter:

  • Xác thực Firebase để cho phép người dùng đăng nhập vào ứng dụng của bạn.
  • Cloud Firestore để lưu dữ liệu có cấu trúc lên đám mây và nhận thông báo tức thì khi dữ liệu thay đổi.

Hai sản phẩm này cần cấu hình đặc biệt hoặc cần được bật bằng bảng điều khiển của Firebase.

Bật Cloud Firestore

Ứng dụng Flutter sử dụng Cloud Firestore để lưu các mục nhật ký.

Bật Cloud Firestore:

  1. Trong mục Build (Tạo) của bảng điều khiển của Firebase, hãy nhấp vào Cloud Firestore.
  2. Nhấp vào Tạo cơ sở dữ liệu. 99e8429832d23fa3.pngS
  3. Chọn tuỳ chọn Bắt đầu ở chế độ thử nghiệm. Đọc tuyên bố từ chối trách nhiệm về các quy tắc bảo mật. Chế độ kiểm thử đảm bảo rằng bạn có thể tự do ghi vào cơ sở dữ liệu trong quá trình phát triển. Nhấp vào Tiếp theo. 6be00e26c72ea032.pngS
  4. Chọn vị trí cho cơ sở dữ liệu của bạn (Bạn có thể dùng vị trí mặc định). Lưu ý rằng bạn không thể thay đổi vị trí này sau đó. 278656eefcfb0216.pngS
  5. Nhấp vào Bật.

3. Thiết lập ứng dụng Flutter

Bạn cần tải mã khởi đầu xuống và cài đặt Firebase CLI trước khi chúng ta bắt đầu.

Lấy mã khởi đầu

Sao chép kho lưu trữ GitHub từ dòng lệnh:

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

Ngoài ra, nếu bạn đã cài đặt công cụ cli của GitHub:

gh repo clone flutter/codelabs flutter-codelabs

Bạn phải sao chép mã mẫu vào thư mục flutter-codelabs, nơi chứa mã dành cho một tập hợp lớp học lập trình. Mã dành cho lớp học lập trình này nằm trong flutter-codelabs/firebase-emulator-suite.

Cấu trúc thư mục trong flutter-codelabs/firebase-emulator-suite bao gồm 2 dự án Flutter. Một thuộc tính được gọi là complete mà bạn có thể tham khảo nếu muốn bỏ qua hoặc tham chiếu chéo mã của riêng bạn. Dự án còn lại có tên là start.

Mã bạn muốn bắt đầu nằm trong thư mục flutter-codelabs/firebase-emulator-suite/start. Mở hoặc nhập thư mục đó vào IDE mà bạn muốn.

cd flutter-codelabs/firebase-emulator-suite/start

Cài đặt Firebase CLI

Firebase CLI cung cấp các công cụ để quản lý dự án Firebase của bạn. Bạn cần phải cài đặt CLI để sử dụng Bộ mô phỏng. Vì vậy, bạn cần cài đặt bộ công cụ này.

Có nhiều cách để cài đặt CLI. Nếu bạn đang sử dụng MacOS hoặc Linux, cách đơn giản nhất là chạy lệnh này trên thiết bị đầu cuối của bạn:

curl -sL https://firebase.tools | bash

Sau khi cài đặt CLI, bạn phải xác thực bằng Firebase.

  1. Đăng nhập vào Firebase bằng Tài khoản Google của bạn bằng cách chạy lệnh sau:
firebase login
  1. Lệnh này kết nối máy cục bộ của bạn với Firebase và cấp cho bạn quyền truy cập vào các dự án Firebase của bạn.
  1. Kiểm tra để đảm bảo CLI đã được cài đặt đúng cách và có quyền truy cập vào tài khoản của bạn bằng cách liệt kê các dự án Firebase của bạn. Chạy lệnh sau:
firebase projects:list
  1. Danh sách hiển thị phải giống với các dự án Firebase được liệt kê trong bảng điều khiển của Firebase. Bạn sẽ thấy ít nhất firebase-flutter-codelab.

Cài đặt FlutterFire CLI

FlutterFire CLI được xây dựng dựa trên Firebase CLI, giúp tích hợp dự án Firebase với ứng dụng Flutter một cách dễ dàng hơn.

Trước tiên, hãy cài đặt CLI:

dart pub global activate flutterfire_cli

Hãy đảm bảo bạn đã cài đặt CLI. Chạy lệnh sau trong thư mục dự án Flutter và đảm bảo rằng CLI xuất ra trình đơn trợ giúp.

flutterfire --help

Sử dụng Firebase CLI và FlutterFire CLI để thêm dự án Firebase vào ứng dụng Flutter của bạn

Sau khi cài đặt 2 CLI, bạn có thể thiết lập từng sản phẩm của Firebase (chẳng hạn như Firestore), tải trình mô phỏng xuống và thêm Firebase vào ứng dụng Flutter chỉ bằng một vài lệnh trong dòng lệnh.

Trước tiên, hãy hoàn tất quá trình thiết lập Firebase bằng cách chạy các bước sau:

firebase init

Lệnh này sẽ đưa bạn qua một loạt câu hỏi cần thiết để thiết lập dự án. Các ảnh chụp màn hình dưới đây minh hoạ quy trình:

  1. Khi có lời nhắc chọn tính năng, hãy chọn "Firestore" và "Emulators". (Không có tuỳ chọn Xác thực, vì tuỳ chọn này không sử dụng cấu hình có thể sửa đổi từ các tệp dự án Flutter của bạn.) fe6401d769be8f53.png.
  2. Tiếp theo, hãy chọn "Sử dụng dự án hiện có" khi được nhắc.

f11dcab439e6ac1e.png.

  1. Bây giờ, hãy chọn dự án bạn đã tạo ở bước trước: flutter-firebase-codelab.

3bdc0c6934991c25.pngS

  1. Tiếp theo, bạn sẽ được hỏi một loạt câu hỏi về cách đặt tên tệp sẽ được tạo. Tôi đề xuất nhấn "enter" cho mỗi câu hỏi để chọn câu hỏi mặc định. 9bfa2d507e199c59.pngs
  2. Cuối cùng, bạn cần định cấu hình trình mô phỏng. Chọn Firestore and Authentication từ danh sách, rồi nhấn phím "Enter" cho mỗi câu hỏi về các cổng cụ thể sẽ sử dụng cho mỗi trình mô phỏng. Bạn nên chọn chế độ mặc định là Có khi được hỏi bạn có muốn sử dụng giao diện người dùng của Trình mô phỏng hay không.

Khi kết thúc quy trình, bạn sẽ thấy kết quả giống như ảnh chụp màn hình sau đây.

Quan trọng: Câu trả lời của bạn có thể hơi khác với kết quả của tôi, như trong ảnh chụp màn hình bên dưới, vì câu hỏi cuối cùng sẽ được mặc định là "Không" nếu bạn đã tải trình mô phỏng xuống.

8544e41037637b07.pngS

Định cấu hình FlutterFire

Tiếp theo, bạn có thể sử dụng FlutterFire để tạo mã Dart cần thiết nhằm sử dụng Firebase trong ứng dụng Flutter của mình.

flutterfire configure

Khi lệnh này chạy, bạn sẽ được nhắc chọn dự án Firebase mà bạn muốn sử dụng cũng như nền tảng mà bạn muốn thiết lập. Trong lớp học lập trình này, các ví dụ sử dụng Flutter Web, nhưng bạn có thể thiết lập dự án Firebase để sử dụng tất cả các tuỳ chọn.

Các ảnh chụp màn hình sau đây cho thấy những câu lệnh bạn cần phải trả lời.

619b7aca6dc15472.pngS 301c9534f594f472.pngS

Ảnh chụp màn hình này cho thấy kết quả ở cuối quy trình. Nếu đã quen dùng Firebase, bạn sẽ nhận thấy rằng bạn không cần phải tạo ứng dụng trong bảng điều khiển, và FlutterFire CLI đã làm việc này cho bạn.

12199a85ade30459.pngS

Thêm các gói Firebase vào ứng dụng Flutter

Bước thiết lập cuối cùng là thêm các gói Firebase có liên quan vào dự án Flutter của bạn. Trong cửa sổ dòng lệnh, hãy đảm bảo bạn đang ở thư mục gốc của dự án Flutter tại flutter-codelabs/firebase-emulator-suite/start. Sau đó, chạy ba lệnh sau:

flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add cloud_firestore

Đây là các gói duy nhất bạn sẽ sử dụng trong ứng dụng này.

4. Bật trình mô phỏng Firebase

Cho đến nay, ứng dụng Flutter và dự án Firebase của bạn đã được thiết lập để có thể sử dụng trình mô phỏng, nhưng bạn vẫn cần phải yêu cầu mã Flutter định tuyến lại các yêu cầu Firebase gửi đi đến các cổng cục bộ.

Trước tiên, hãy thêm mã khởi chạy Firebase và mã thiết lập trình mô phỏng vào hàm main trong 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());
}

Một vài dòng mã đầu tiên khởi chạy Firebase. Thông thường, nếu đang làm việc với Firebase trong một ứng dụng Flutter, bạn nên bắt đầu bằng cách gọi WidgetsFlutterBinding.ensureInitializedFirebase.initializeApp.

Theo đó, đoạn mã bắt đầu bằng dòng if (kDebugMode) sẽ yêu cầu ứng dụng của bạn nhắm mục tiêu đến trình mô phỏng thay vì dự án Firebase chính thức. kDebugMode đảm bảo rằng việc nhắm mục tiêu trình mô phỏng sẽ chỉ xảy ra nếu bạn đang ở trong môi trường phát triển. Vì kDebugMode là một giá trị không đổi nên trình biên dịch Dart biết sẽ xóa hoàn toàn khối mã đó ở chế độ phát hành.

Khởi động trình mô phỏng

Bạn nên khởi động trình mô phỏng trước khi khởi động ứng dụng Flutter. Trước tiên, hãy khởi động trình mô phỏng bằng cách chạy lệnh này trong cửa sổ dòng lệnh:

firebase emulators:start

Lệnh này sẽ khởi động trình mô phỏng và hiển thị các cổng cục bộ mà chúng ta có thể tương tác với các trình mô phỏng đó. Khi chạy lệnh đó, bạn sẽ thấy kết quả tương tự như sau:

bb7181eb70829606.pngS

Kết quả này cho bạn biết trình mô phỏng nào đang chạy và nơi bạn có thể xem trình mô phỏng. Trước tiên, hãy xem giao diện người dùng của trình mô phỏng tại localhost:4000.

11563f4c7216de81.pngs

Đây là trang chủ dành cho giao diện người dùng của trình mô phỏng cục bộ. Cửa sổ này liệt kê tất cả trình mô phỏng hiện có và mỗi trình mô phỏng được gắn nhãn trạng thái bật hoặc tắt.

5. Trình mô phỏng xác thực Firebase

Trình mô phỏng đầu tiên bạn sẽ sử dụng là Trình mô phỏng xác thực. Bắt đầu với trình mô phỏng xác thực bằng cách nhấp vào "Go to emulator" (Chuyển đến trình mô phỏng) trên thẻ Xác thực trong giao diện người dùng và bạn sẽ thấy một trang giống như sau:

3c1bfded40733189.pngS

Trang này có các điểm tương đồng với trang bảng điều khiển web Xác thực. Bảng điều khiển này có một bảng liệt kê những người dùng như bảng điều khiển trực tuyến, đồng thời cho phép bạn thêm người dùng theo cách thủ công. Một điểm khác biệt lớn ở đây là phương thức xác thực duy nhất có trên trình mô phỏng là thông qua Email và Mật khẩu. Điều này là đủ để phát triển cục bộ.

Tiếp theo, bạn sẽ thực hiện quy trình thêm người dùng vào trình mô phỏng xác thực Firebase, sau đó đăng nhập người dùng đó thông qua giao diện người dùng Flutter.

Thêm người dùng

Nhấp vào nút "Thêm người dùng" và điền thông tin sau vào biểu mẫu:

  • Tên hiển thị: Dấu gạch ngang
  • Email: dash@email.com
  • Mật khẩu: dấu gạch ngang

Gửi biểu mẫu và bạn sẽ thấy bảng hiện bao gồm một người dùng. Bây giờ, bạn có thể cập nhật mã để đăng nhập bằng người dùng đó.

log_out_view.dart

Mã duy nhất trong tiện ích LoggedOutView cần được cập nhật nằm trong lệnh gọi lại được kích hoạt khi người dùng nhấn vào nút đăng nhập. Cập nhật mã để có dạng như sau:

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'),
          ),
        ),
      ],
    ),
   ),
  );
 }
}

Mã đã cập nhật sẽ thay thế các chuỗi TODO bằng email và mật khẩu mà bạn đã tạo trong trình mô phỏng xác thực. Và trong dòng tiếp theo, dòng if(true) đã được thay thế bằng mã kiểm tra xem state.user có rỗng hay không. Mã trong AppClass làm sáng tỏ hơn về vấn đề này.

app_state.dart

Hai phần của mã trong AppState cần được cập nhật. Trước tiên, hãy cung cấp cho thành viên lớp AppState.user loại User trong gói firebase_auth, thay vì loại Object.

Tiếp theo, hãy điền vào phương thức AppState.login như minh hoạ dưới đây:

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!');
   }
 } 
 // ...
}

Định nghĩa kiểu cho người dùng hiện là User?. Lớp User đó đến từ tính năng Xác thực Firebase và cung cấp thông tin cần thiết, chẳng hạn như User.displayName, sẽ được thảo luận sau.

Đây là mã cơ bản cần thiết để đăng nhập người dùng bằng email và mật khẩu trong tính năng Xác thực Firebase. Phương thức này thực hiện lệnh gọi đến FirebaseAuth để đăng nhập. Thao tác này sẽ trả về đối tượng Future<UserCredential>. Khi tương lai hoàn tất, mã này sẽ kiểm tra xem có User đi kèm với UserCredential hay không. Nếu có một người dùng trên đối tượng thông tin xác thực thì người dùng đó đã đăng nhập thành công và có thể đặt thuộc tính AppState.user. Nếu không có, thì tức là đã xảy ra lỗi và mã đã được in.

Lưu ý rằng dòng mã duy nhất trong phương thức này dành riêng cho ứng dụng này (chứ không phải mã FirebaseAuth chung) là lệnh gọi đến phương thức _listenForEntries. Nội dung này sẽ được đề cập trong bước tiếp theo.

VIỆC CẦN LÀM: Biểu tượng hành động – Tải lại ứng dụng của bạn, sau đó nhấn nút Đăng nhập khi ứng dụng hiển thị. Việc này sẽ khiến ứng dụng điều hướng đến một trang có nội dung "Chào mừng bạn quay lại!" ở trên cùng. Tính năng xác thực phải hoạt động vì chế độ này cho phép bạn chuyển đến trang này, nhưng bạn cần thực hiện một cập nhật nhỏ đối với logged_in_view.dart để tên thật của người dùng xuất hiện.

log_in_view.dart

Thay đổi dòng đầu tiên trong phương thức 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(
 // ...

Lúc này, dòng này sẽ lấy displayName từ thuộc tính User trên đối tượng AppState. displayName này được đặt trong trình mô phỏng khi bạn xác định người dùng lần đầu. Lúc này, ứng dụng sẽ hiển thị thông báo "Chào mừng bạn trở lại, Dash!" khi bạn đăng nhập, thay vì TODO.

6. Đọc và ghi dữ liệu vào trình mô phỏng Firestore

Trước tiên, hãy kiểm tra trình mô phỏng Firestore. Trên trang chủ Giao diện người dùng của Trình mô phỏng (localhost:4000), hãy nhấp vào "Go to emulator" (Chuyển đến trình mô phỏng) trên thẻ Firestore. Ứng dụng sẽ hiển thị như sau:

Trình mô phỏng:

791fce7dc137910a.png.

Bảng điều khiển của Firebase:

e0dde9aea34af050.pngS

Nếu đã có kinh nghiệm với Firestore, bạn sẽ thấy rằng trang này trông giống với trang trên bảng điều khiển của Firebase. Tuy nhiên, có một vài khác biệt đáng chú ý.

  1. Bạn có thể xoá mọi dữ liệu chỉ bằng một lần nhấn. Điều này sẽ nguy hiểm đối với dữ liệu thực tế nhưng rất hữu ích để lặp lại nhanh chóng! Nếu đang thực hiện một dự án mới và mô hình dữ liệu của bạn thay đổi, thì việc này rất dễ dàng.
  2. Có một "Yêu cầu" . Thẻ này cho phép bạn xem các yêu cầu được gửi đến trình mô phỏng này. Tôi sẽ thảo luận chi tiết hơn về thẻ này.
  3. Không có thẻ nào cho Quy tắc, Chỉ mục hoặc Cách sử dụng. Có một công cụ (sẽ thảo luận trong phần tiếp theo) giúp ghi các quy tắc bảo mật, nhưng bạn không thể đặt quy tắc bảo mật cho trình mô phỏng cục bộ.

Tóm lại, phiên bản Firestore này cung cấp nhiều công cụ hữu ích hơn trong quá trình phát triển, đồng thời loại bỏ các công cụ cần thiết cho phiên bản chính thức.

Ghi vào Firestore

Trước khi thảo luận về "Yêu cầu" trong trình mô phỏng, trước tiên hãy tạo một yêu cầu. Bạn cần cập nhật mã. Bắt đầu bằng cách kết nối biểu mẫu trong ứng dụng để ghi một nhật ký mới Entry vào Firestore.

Quy trình cấp cao để gửi Entry là:

  1. Người dùng điền thông tin vào biểu mẫu và nhấn nút Submit
  2. Giao diện người dùng gọi AppState.writeEntryToFirebase
  3. AppState.writeEntryToFirebase thêm một mục vào Firebase

Không cần thay đổi mã nào trong bước 1 hoặc 2. Mã duy nhất cần thêm cho bước 3 sẽ được thêm vào lớp AppState. Thực hiện thay đổi sau đối với 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,
   });
 }
 // ...
}

Mã trong phương thức writeEntryToFirebase lấy thông tin tham chiếu đến tập hợp có tên là "Entries" trong Firestore. Sau đó, thao tác này sẽ thêm một mục mới thuộc kiểu Map<String, String>.

Trong trường hợp này, "Tác phẩm dự thi" bộ sưu tập trong Firestore không tồn tại, vì vậy Firestore đã tạo một bộ sưu tập.

Sau khi thêm mã đó, hãy tải lại hoặc khởi động lại ứng dụng, đăng nhập và chuyển đến chế độ xem EntryForm. Bạn có thể điền bất kỳ Strings nào bạn muốn vào biểu mẫu. (Trường Ngày sẽ lấy chuỗi bất kỳ, vì lớp này đã được đơn giản hoá trong lớp học lập trình này. Lớp này không xác thực hoặc quan tâm đến các đối tượng DateTime theo bất kỳ cách nào.)

Nhấn vào gửi trên biểu mẫu. Không có gì xảy ra trong ứng dụng, nhưng bạn có thể xem mục mới trong giao diện người dùng của trình mô phỏng.

Thẻ Yêu cầu trong trình mô phỏng Firestore

Trong giao diện người dùng, hãy chuyển đến trình mô phỏng Firestore rồi xem mục "Dữ liệu" . Bạn sẽ thấy hiện có một Bộ sưu tập ở gốc cơ sở dữ liệu có tên là "Nhóm dự thi". Bạn cần có một tài liệu chứa chính thông tin mà bạn đã nhập vào biểu mẫu.

a978fb34fb8a83da.png.

Điều đó xác nhận rằng AppState.writeEntryToFirestore đã hoạt động và giờ đây, bạn có thể khám phá thêm về yêu cầu này trong thẻ Yêu cầu. Nhấp vào thẻ đó ngay.

Yêu cầu trình mô phỏng Firestore

Tại đây, bạn sẽ thấy một danh sách có dạng như sau:

f0b37f0341639035.pngS

Bạn có thể nhấp vào bất kỳ mục nào trong số đó và xem khá nhiều thông tin hữu ích. Nhấp vào mục trong danh sách CREATE tương ứng với yêu cầu tạo một mục nhập nhật ký mới. Bạn sẽ thấy một bảng mới trông giống như sau:

385d62152e99aad4.pngs

Như đã đề cập, trình mô phỏng Firestore cung cấp các công cụ để phát triển quy tắc bảo mật của ứng dụng. Chế độ xem này cho thấy chính xác dòng nào trong quy tắc bảo mật của bạn mà yêu cầu này đã vượt qua (hoặc không thành công, nếu trường hợp đó xảy ra). Trong một ứng dụng mạnh mẽ hơn, Quy tắc bảo mật có thể phát triển và có nhiều lần kiểm tra uỷ quyền. Chế độ xem này dùng để giúp viết và gỡ lỗi các quy tắc uỷ quyền đó.

API này cũng giúp bạn dễ dàng kiểm tra từng phần của yêu cầu này, bao gồm cả siêu dữ liệu và dữ liệu xác thực. Dữ liệu này được dùng để viết các quy tắc uỷ quyền phức tạp.

Đọc từ Firestore

Firestore sử dụng tính năng đồng bộ hoá dữ liệu để đẩy dữ liệu đã cập nhật sang các thiết bị đã kết nối. Trong mã Flutter, bạn có thể nghe (hoặc đăng ký) các bộ sưu tập và tài liệu của Firestore. Mã của bạn sẽ được thông báo bất cứ khi nào dữ liệu thay đổi. Trong ứng dụng này, quá trình theo dõi các bản cập nhật trên Firestore được thực hiện trong phương thức có tên là AppState._listenForEntries.

Mã này hoạt động cùng với StreamControllerStream có tên lần lượt là AppState._entriesStreamControllerAppState.entries. Mã đó đã được viết, giống như tất cả mã cần thiết trong giao diện người dùng để hiển thị dữ liệu từ Firestore.

Cập nhật phương thức _listenForEntries để khớp với mã dưới đây:

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);
   });
 }
 // ...
}

Mã này xử lý "Người dự thi" trong Firestore. Khi thông báo cho ứng dụng này rằng có dữ liệu mới, Firestore sẽ chuyển dữ liệu đó và mã trong _listenForEntries sẽ thay đổi tất cả tài liệu con thành một đối tượng mà ứng dụng của chúng ta có thể sử dụng (Entry). Sau đó, thao tác này sẽ thêm các mục nhập đó vào StreamController có tên là _entriesStreamController (giao diện người dùng đang theo dõi). Mã này là bản cập nhật duy nhất cần thiết.

Cuối cùng, hãy nhớ lại rằng phương thức AppState.logIn thực hiện lệnh gọi đến _listenForEntries. Lệnh gọi này sẽ bắt đầu quá trình nghe sau khi người dùng đăng nhập.

// ...
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!');
 }
}
// ...

Bây giờ, hãy chạy ứng dụng. Ứng dụng sẽ hiển thị như sau:

b8a31c7a8900331.gif

7. Xuất và nhập dữ liệu vào trình mô phỏng

Trình mô phỏng Firebase hỗ trợ tính năng nhập và xuất dữ liệu. Khi sử dụng tính năng nhập và xuất, bạn có thể tiếp tục phát triển ứng dụng bằng chính dữ liệu đó khi tạm dừng phát triển rồi tiếp tục. Bạn cũng có thể chuyển các tệp dữ liệu vào git và các nhà phát triển khác mà bạn đang hợp tác sẽ có cùng dữ liệu để làm việc.

Xuất dữ liệu trình mô phỏng

Trước tiên, hãy xuất dữ liệu của trình mô phỏng bạn đã có. Trong khi trình mô phỏng vẫn đang chạy, hãy mở một cửa sổ dòng lệnh mới rồi nhập lệnh sau:

firebase emulators:export ./emulators_data

.emulators_data là một đối số, cho Firebase biết nơi cần xuất dữ liệu. Nếu thư mục không tồn tại, thư mục sẽ được tạo. Bạn có thể sử dụng bất kỳ tên nào bạn muốn cho thư mục đó.

Khi chạy lệnh này, bạn sẽ thấy kết quả sau trong thiết bị đầu cuối nơi bạn đã chạy lệnh:

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

Và nếu chuyển sang cửa sổ dòng lệnh nơi trình mô phỏng đang chạy, bạn sẽ thấy kết quả sau:

i  emulators: Received export request. Exporting data to /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data.
✔  emulators: Export complete.

Cuối cùng, nếu nhìn vào thư mục dự án, bạn sẽ thấy một thư mục có tên là ./emulators_data, chứa JSON tệp và các tệp siêu dữ liệu khác, cùng với dữ liệu bạn đã lưu.

Nhập dữ liệu trình mô phỏng

Giờ đây, bạn có thể nhập dữ liệu đó như một phần của quy trình phát triển và bắt đầu từ nơi bạn đã dừng lại.

Trước tiên, hãy dừng trình mô phỏng nếu chúng đang chạy bằng cách nhấn phím CTRL+C trên thiết bị đầu cuối.

Tiếp theo, hãy chạy lệnh emulators:start mà bạn đã thấy, nhưng với một cờ cho biết cần nhập dữ liệu nào:

firebase emulators:start --import ./emulators_data

Khi trình mô phỏng được tải lên, hãy chuyển đến giao diện người dùng của trình mô phỏng tại localhost:4000 và bạn sẽ thấy chính dữ liệu mà mình đã làm việc trước đó.

Tự động xuất dữ liệu khi đóng trình mô phỏng

Bạn cũng có thể tự động xuất dữ liệu khi thoát khỏi trình mô phỏng, thay vì phải nhớ xuất dữ liệu vào cuối mỗi phiên phát triển.

Khi bạn khởi động trình mô phỏng, hãy chạy lệnh emulators:start với 2 cờ bổ sung.

firebase emulators:start --import ./emulators_data --export-on-exit

Thế là xong! Bây giờ, dữ liệu của bạn sẽ được lưu và tải lại mỗi khi bạn làm việc với trình mô phỏng cho dự án này. Bạn cũng có thể chỉ định một thư mục khác làm đối số cho –export-on-exit flag, nhưng thư mục này sẽ mặc định là thư mục được chuyển đến –import.

Bạn cũng có thể sử dụng kết hợp các lựa chọn này theo cách bất kỳ. Đây là ghi chú từ tài liệu: Có thể chỉ định thư mục xuất bằng cờ này: firebase emulators:start --export-on-exit=./saved-data. Nếu bạn sử dụng --import, đường dẫn xuất sẽ được đặt theo mặc định; ví dụ: firebase emulators:start --import=./data-path --export-on-exit. Cuối cùng, nếu muốn, hãy truyền các đường dẫn thư mục khác nhau đến cờ --import--export-on-exit.

8. Xin chúc mừng!

Bạn đã hoàn tất quy trình Thiết lập và chạy bằng trình mô phỏng Firebase và Flutter. Bạn có thể tìm thấy mã đã hoàn chỉnh cho Lớp học lập trình này trong tệp "hoàn chỉnh" thư mục trên github: Flutter Codelabs

Nội dung đã đề cập

  • Thiết lập một ứng dụng Flutter để dùng Firebase
  • Thiết lập dự án Firebase
  • FlutterFire Giao diện dòng lệnh (CLI)
  • Giao diện dòng lệnh (CLI) của Firebase
  • Trình mô phỏng Xác thực Firebase
  • Trình mô phỏng Firebase Firestore
  • Nhập và xuất dữ liệu trình mô phỏng

Các bước tiếp theo

Tìm hiểu thêm

Sparky tự hào về bạn!

2a0ad195769368b1.gif