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 Firebase Emulator Suite 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 bằng email và mật khẩu thông qua Emulator Suite, 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 từ các trình mô phỏng, để làm việc với cùng một dữ liệu giả mạo mỗi khi 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ó kinh nghiệm sử dụng Flutter. Nếu không, trước tiên bạn nên tìm hiểu những kiến thức cơ bản. Các đường liên kết sau đây sẽ hữu ích:
- Tìm hiểu Khung tiện ích Flutter
- Hãy thử lớp học lập trình Viết ứng dụng Flutter đầu tiên, phần 1
Bạn cũng nên có kinh nghiệm sử dụng Firebase, nhưng không sao nếu bạn chưa từng thêm Firebase vào một dự án Flutter. Nếu bạn chưa quen với bảng điều khiển Firebase hoặc 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 tạo một ứng dụng Nhật ký đơn giản. Ứng dụng sẽ có một màn hình đăng nhập và một màn hình cho phép bạn đọc các mục nhật ký trước đây và tạo các mục nhật ký mới.
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ộ Trình mô phỏng Firebase trong quy trình phát triển Flutter. Chúng tôi sẽ đề cập đến các chủ đề sau đây về Firebase:
Xin lưu ý rằng những chủ đề này được đề cập trong phạm vi cần thiết để đề 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 một dự án Firebase vào ứng dụng Flutter và phát triển bằng Firebase Emulator Suite. Sẽ không có các cuộc thảo luận chuyên sâu về Firebase Authentication hoặc Firestore. Nếu chưa quen thuộc với những chủ đề này, bạn nên bắt đầu với Lớp học lập trình Tìm hiểu về Firebase cho Flutter.
Bạn cần có
- Có kiến thức về Flutter và đã cài đặt SDK
- Trình chỉnh sửa 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 mà bạn ưu tiên khác cho Flutter. Một số lệnh trên thiết bị đầu cuối 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
Nhiệm vụ đầu tiên bạn cần hoàn thành là tạo một dự án Firebase trong bảng điều khiển web của Firebase. Phần lớn nội dung của lớp học lập trình này sẽ tập trung vào Emulator Suite (Bộ công cụ 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 hoàn chỉnh.
Tạo một dự án Firebase
- Đăng nhập vào bảng điều khiển của Firebase bằng Tài khoản Google của bạn.
- Nhấp vào nút này để tạo một dự án mới, rồi nhập tên dự án (ví dụ:
Firebase-Flutter-Codelab
).
- Nhấp vào Tiếp tục.
- Nếu được nhắc, hãy xem xét và chấp nhận các điều khoản của Firebase, rồi nhấp vào Tiếp tục.
- (Không bắt buộc) Bật tính năng hỗ trợ của AI trong bảng điều khiển của Firebase (còn gọi là "Gemini trong Firebase").
- Đối với lớp học lập trình này, bạn không cần Google Analytics, vì vậy hãy tắt lựa chọn Google Analytics.
- Nhấp vào Tạo dự án, đợi dự án được cấp phép rồi nhấp vào Tiếp tục.
Để 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.
Thiết lập các sản phẩm của 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 trê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ó cấu hình đặc biệt hoặc cần được bật bằng cách sử dụ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:
- Trong mục Tạo của bảng điều khiển Firebase, hãy nhấp vào Cloud Firestore.
- Nhấp vào Tạo cơ sở dữ liệu.
- 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ế độ thử nghiệm đảm bảo bạn có thể tự do ghi lên cơ sở dữ liệu trong quá trình phát triển. Nhấp vào Tiếp theo.
- Chọn vị trí cho cơ sở dữ liệu của bạn (Bạn chỉ cần sử dụng vị trí mặc định). Xin lưu ý rằng bạn không thể thay đổi vị trí này sau khi đã chọn.
- 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 Giao diện dòng lệnh (CLI) của Firebase trước khi bắt đầu.
Lấy đoạn 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 nên sao chép mã mẫu vào thư mục flutter-codelabs
. Thư mục này chứa mã cho một bộ sưu tập các lớp học lập trình. Mã 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 là complete
, 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 mình. Dự án còn lại có tên là start
.
Mã 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 dùng.
cd flutter-codelabs/firebase-emulator-suite/start
Cài đặt Giao diện dòng lệnh (CLI) của Firebase
Firebase CLI cung cấp các công cụ để quản lý dự án Firebase. Bạn cần cài đặt CLI để sử dụng Emulator Suite.
Có nhiều cách để cài đặt CLI. Cách đơn giản nhất (nếu bạn đang dùng MacOS hoặc Linux) là chạy lệnh này từ thiết bị đầu cuối:
curl -sL https://firebase.tools | bash
Sau khi cài đặt CLI, bạn phải xác thực bằng Firebase.
- Đă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
- 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.
- 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. Chạy lệnh sau:
firebase projects:list
- Danh sách hiển thị phải giống với các dự án Firebase có 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 và giúp bạn dễ dàng tích hợp dự án Firebase với ứng dụng Flutter.
Trước tiên, hãy cài đặt CLI:
dart pub global activate flutterfire_cli
Đả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 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
Sau khi cài đặt 2 giao diện dòng lệnh này, 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 trên thiết bị đầu cuối.
Trước tiên, hãy hoàn tất việc thiết lập Firebase bằng cách chạy lệnh sau:
firebase init
Lệnh này sẽ hướng dẫn bạn trả lời 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 này cho thấy quy trình:
- Khi được nhắc chọn các tính năng, hãy chọn "Firestore" và "Trình mô phỏng". (Không có lựa chọn Xác thực vì lựa 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.)
- Tiếp theo, hãy chọn "Sử dụng dự án hiện có" khi được nhắc.
- Bây giờ, hãy chọn dự án bạn đã tạo ở bước trước: flutter-firebase-codelab.
- Tiếp theo, bạn sẽ được hỏi một loạt câu hỏi về việc đặt tên cho các tệp sẽ được tạo. Bạn nên nhấn phím "enter" cho mỗi câu hỏi để chọn giá trị mặc định.
- Cuối cùng, bạn cần định cấu hình trình mô phỏng. Chọn Firestore và Xác thực trong danh sách, rồi nhấn "Enter" cho từng câu hỏi về các cổng cụ thể cần dùng cho mỗi trình mô phỏng. Bạn nên chọn mặc định là Có khi được hỏi liệu bạn có muốn sử dụng Giao diện người dùng trình mô phỏng hay không.
Khi quá trình kết thúc, bạn sẽ thấy một kết quả như trong ảnh chụp màn hình sau.
Lưu ý quan trọng: Kết quả của bạn có thể hơi khác so 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ẽ mặc định là "Không" nếu bạn đã tải trình mô phỏng xuống.
Định cấu hình FlutterFire
Tiếp theo, bạn có thể dùng FlutterFire để tạo mã Dart cần thiết nhằm sử dụng Firebase trong ứng dụng Flutter.
flutterfire configure
Khi chạy lệnh này, bạn sẽ được nhắc chọn dự án Firebase mà bạn muốn sử dụng và 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 lựa chọn.
Các ảnh chụp màn hình sau đây cho thấy những câu hỏi bạn cần trả lời.
Ảnh chụp màn hình này cho thấy kết quả đầu ra ở cuối quy trình. Nếu đã quen thuộc với Firebase, bạn sẽ nhận thấy rằng bạn không phải tạo ứng dụng trong bảng điều khiển và FlutterFire CLI đã thực hiện việc này cho bạn.
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 thiết bị đầu cuối, hãy đảm bảo bạn đang ở gốc của dự án Flutter tại flutter-codelabs/firebase-emulator-suite/start
. Sau đó, hãy chạy 3 lệnh sau:
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add cloud_firestore
Đây là những gói duy nhất mà bạn 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 các trình mô phỏng, nhưng bạn vẫn cần yêu cầu mã Flutter định tuyến lại các yêu cầu Firebase đ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 sẽ khởi động Firebase. Hầu như ở mọi nơi, 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.ensureInitialized
và Firebase.initializeApp
.
Sau đó, đoạn mã bắt đầu bằng dòng if (kDebugMode)
sẽ hướng dẫn ứng dụng của bạn nhắm đến các trình mô phỏng thay vì một dự án Firebase phát hành công khai. kDebugMode
đảm bảo rằng việc nhắm đến các 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ị hằng số, nên trình biên dịch Dart biết cách xoá 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 sau trong thiết bị đầu cuối:
firebase emulators:start
Lệnh này sẽ khởi động trình mô phỏng và hiển thị các cổng máy chủ cục bộ mà chúng ta có thể tương tác. Khi chạy lệnh đó, bạn sẽ thấy kết quả tương tự như sau:
Đầu ra này cho biết những trình mô phỏng đang chạy và nơi bạn có thể truy cập để xem các 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
.
Đây là trang chủ của giao diện người dùng trình mô phỏng cục bộ. Thao tác này liệt kê tất cả trình mô phỏng có sẵn và mỗi trình mô phỏng đều được gắn nhãn trạng thái bật hoặc tắt.
5. Trình mô phỏng Firebase Auth
Trình mô phỏng đầu tiên mà bạn sẽ sử dụng là trình mô phỏng Xác thực. Bắt đầu bằng trình mô phỏng Auth bằng cách nhấp vào "Go to emulator" (Chuyển đến trình mô phỏng) trên thẻ Authentication (Xác thực) trong giao diện người dùng. Bạn sẽ thấy một trang có dạng như sau:
Trang này có điểm tương đồng với trang Bảng điều khiển web Auth. Ứng dụng này có một bảng liệt kê người dùng giống như bảng trên bảng điều khiển trực tuyến và 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à đủ cho quá trình 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 Firebase Auth, 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" rồi điền thông tin sau vào biểu mẫu:
- Tên hiển thị: Dash
- Email: dash@email.com
- Mật khẩu: dashword
Gửi biểu mẫu và bạn sẽ thấy bảng hiện có một người dùng. Giờ đây, bạn có thể cập nhật mã để đăng nhập bằng người dùng đó.
logged_out_view.dart
Đoạn mã duy nhất trong tiện ích LoggedOutView
cần được cập nhật là 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à ở dòng tiếp theo, dòng if(true)
đã được thay thế bằng mã kiểm tra xem state.user
có giá trị rỗng hay không. Mã trong AppClass
sẽ làm rõ hơn về vấn đề này.
app_state.dart
Bạn cần cập nhật 2 phần của mã trong AppState
. Trước tiên, hãy đặt cho thành viên lớp AppState.user kiểu User
từ gói firebase_auth
, thay vì kiểu Object
.
Thứ hai, hãy điền vào phương thức AppState.login
như minh hoạ bên dưới:
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 về loại cho người dùng hiện là User?
. Lớp User
đó đến từ Firebase Auth và cung cấp thông tin cần thiết 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 Xác thực Firebase. Thao tác này sẽ gọi FirebaseAuth để đăng nhập, thao tác này sẽ trả về một đối tượng Future<UserCredential>
. Khi tương lai hoàn tất, mã này sẽ kiểm tra xem có User
nào được đính kèm vào UserCredential
hay không. Nếu có người dùng trên đối tượng thông tin đăng nhập, thì tức là người dùng đã đăng nhập thành công và bạn có thể đặt thuộc tính AppState.user
. Nếu không, tức là đã xảy ra lỗi và lỗi đó sẽ được in.
Xin 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 (thay vì mã FirebaseAuth chung) là lệnh gọi đến phương thức _listenForEntries
. Chúng ta sẽ đề cập đến phương thức này trong bước tiếp theo.
TODO: Action Icon – Reload your app, and then press the Login button when it renders. Điều này khiến ứng dụng chuyển đến một trang có nội dung "Chào mừng bạn quay trở lại, Người dùng!" ở trên cùng. Quá trình xác thực phải hoạt động vì quá trình 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 bản cập nhật nhỏ cho logged_in_view.dart
để hiển thị tên thực tế của người dùng.
logged_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( // ...
Giờ đâ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 đầu tiên. Giờ đây, ứng dụng của bạn sẽ hiển thị "Chào mừng bạn quay 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 xem trình mô phỏng Firestore. Trên trang chủ Giao diện người dùng trình mô phỏng (localhost:4000
), hãy nhấp vào "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:
Bảng điều khiển của Firebase:
Nếu đã từng sử dụng Firestore, bạn sẽ nhận thấy trang này trông tương tự như trang Firestore trên bảng điều khiển của Firebase. Tuy nhiên, có một số điểm khác biệt đáng chú ý.
- Bạn có thể xoá tất cả dữ liệu chỉ bằng một nút nhấn. Điều này có thể gây nguy hiểm cho dữ liệu sản xuất, nhưng lại hữu ích cho việc lặp lại nhanh chóng! Nếu bạn đ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ì bạn có thể dễ dàng xoá dữ liệu.
- Có thẻ "Yêu cầu". Thẻ này cho phép bạn xem các yêu cầu đến đượ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 trong phần tiếp theo.
- Không có thẻ nào cho Quy tắc, Chỉ mục hoặc Mức sử dụng. Có một công cụ (sẽ được thảo luận trong phần tiếp theo) giúp viết 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 và loại bỏ những công cụ cần thiết trong quá trình sản xuất.
Ghi vào Firestore
Trước khi thảo luận về thẻ "Requests" (Yêu cầu) trong trình mô phỏng, trước tiên hãy thực hiện một yêu cầu. Việc này yêu cầu 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.
Sau đây là quy trình cấp cao để gửi Entry
:
- Người dùng điền thông tin vào biểu mẫu và nhấn vào nút
Submit
- Giao diện người dùng gọi
AppState.writeEntryToFirebase
AppState.writeEntryToFirebase
thêm một mục vào Firebase
Bạn 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 một tham chiếu đến bộ sưu tập có tên là "Entries" trong Firestore. Sau đó, nó sẽ thêm một mục mới, cần phải thuộc loại Map<String, String>
.
Trong trường hợp này, bộ sưu tập "Entries" trong Firestore không tồn tại, nên Firestore đã tạo một bộ sưu tập.
Sau khi thêm mã đó, hãy tải lại nhanh 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 vào biểu mẫu bằng bất kỳ Strings
nào bạn muốn. (Trường Ngày sẽ nhận bất kỳ Chuỗi nào, vì trường này đã được đơn giản hoá cho lớp học lập trình này. Nó không có quy trình xác thực nghiêm ngặt hoặc quan tâm đến các đối tượng DateTime
theo bất kỳ cách nào.)
Nhấn vào nút 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ể thấy mục mới của mình trong giao diện người dùng 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 thẻ "Dữ liệu". Bạn sẽ thấy rằng hiện có một Bộ sưu tập ở gốc cơ sở dữ liệu của bạn có tên là "Entries". Bạn nên có một tài liệu chứa thông tin giống như thông tin bạn đã nhập vào biểu mẫu.
Điều này xác nhận rằng AppState.writeEntryToFirestore
đã hoạt động và giờ đây, bạn có thể khám phá thêm yêu cầu trong thẻ Yêu cầu. Nhấp vào thẻ đó ngay.
Yêu cầu về trình mô phỏng Firestore
Tại đây, bạn sẽ thấy một danh sách tương tự như sau:
Bạn có thể nhấp vào bất kỳ mục nào trong danh sách đó và xem khá nhiều thông tin hữu ích. Nhấp vào mục CREATE
trong danh sách tương ứng với yêu cầu của bạn để tạo một bút toán nhật ký mới. Bạn sẽ thấy một bảng mới có dạng như sau:
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 biết chính xác dòng nào trong quy tắc bảo mật mà yêu cầu này đã vượt qua (hoặc không vượt qua, nếu đó là trường hợp). 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 quy trình kiểm tra uỷ quyền. Chế độ xem này được dùng để hỗ trợ việc viết và gỡ lỗi các quy tắc uỷ quyền đó.
Ngoài ra, công cụ này còn cung cấp một cách dễ dàng để kiểm tra mọi 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 để truyền dữ liệu mới cập nhật đến các thiết bị được kết nối. Trong mã Flutter, bạn có thể theo dõi (hoặc đăng ký) các bộ sưu tập và tài liệu trên Firestore, đồng thời 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, việc theo dõi nội dung cập nhật của Firestore được thực hiện trong phương thức có tên là AppState._listenForEntries
.
Đoạn mã này hoạt động cùng với StreamController
và Stream
có tên lần lượt là AppState._entriesStreamController
và AppState.entries
. Mã đó đã được viết, cũ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
sao cho khớp với mã bên dưới:
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); }); } // ... }
Đoạn mã này theo dõi bộ sưu tập "Entries" trong Firestore. Khi Firestore 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ả các tài liệu con của dữ liệu đó thành một đối tượng mà ứng dụng của chúng ta có thể sử dụng (Entry
). Sau đó, Firestore sẽ thêm những mục đó vào StreamController
có tên là _entriesStreamController
(mà giao diện người dùng đang theo dõi). Đây là bản cập nhật duy nhất bắt buộc.
Cuối cùng, hãy nhớ rằng phương thức AppState.logIn
sẽ gọi đến _listenForEntries
, bắt đầu quy 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ẽ có dạng như sau:
7. Xuất và nhập dữ liệu vào trình mô phỏng
Các trình mô phỏng Firebase hỗ trợ nhập và xuất dữ liệu. Việc sử dụng tính năng nhập và xuất cho phép bạn tiếp tục phát triển với cùng một dữ liệu khi bạn tạm dừng rồi tiếp tục phát triển. Bạn cũng có thể cam kết tệp dữ liệu với git và những nhà phát triển khác mà bạn đang làm việc cùng 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 trình mô phỏng mà bạn đã có. Trong khi các 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 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 dòng lệnh 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
Nếu chuyển sang cửa sổ thiết bị đầu cuối nơi các 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 xem trong thư mục dự án, bạn sẽ thấy một thư mục có tên là ./emulators_data
. Thư mục này chứa các tệp JSON
, cùng với các tệp siêu dữ liệu khác, có dữ liệu mà 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 đó trong 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 các trình mô phỏng nếu chúng đang chạy bằng cách nhấn CTRL+C
trong thiết bị đầu cuối.
Tiếp theo, hãy chạy lệnh emulators:start
mà bạn đã thấy, nhưng có một cờ cho biết dữ liệu cần nhập:
firebase emulators:start --import ./emulators_data
Khi trình mô phỏng hoạt động, hãy chuyển đến giao diện người dùng trình mô phỏng tại localhost:4000
và bạn sẽ thấy dữ liệu giống như dữ liệu bạn đã từng làm việ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 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
bằng 2 cờ bổ sung.
firebase emulators:start --import ./emulators_data --export-on-exit
Voila! Giờ đây, 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 các 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 truyề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ú trong tài liệu: Bạn 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 dùng --import
, đường dẫn xuất sẽ mặc định là đường dẫn tương tự; 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
và --export-on-exit
.
8. Xin chúc mừng!
Bạn đã hoàn thành khoá học Bắt đầu sử dụ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 thư mục "complete" trên GitHub: Flutter Codelabs
Nội dung đã đề cập
- Thiết lập một ứng dụng Flutter để sử dụng Firebase
- Thiết lập dự án Firebase
- FlutterFire 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 về cách sử dụng Firestore và Xác thực trong Flutter: Tìm hiểu về Firebase cho Lớp học lập trình Flutter
- Khám phá các công cụ khác của Firebase có cung cấp trình mô phỏng:
- Cloud Storage
- Cloud Functions
- Cơ sở dữ liệu theo thời gian thực
- Khám phá FlutterFire UI để nhanh chóng thêm Google Authentication vào ứng dụng của bạn.
Tìm hiểu thêm
- Trang web của Firebase: firebase.google.com
- Trang web Flutter: flutter.dev
- Tiện ích FlutterFire Firebase Flutter: firebase.flutter.dev
- Kênh YouTube của Firebase
- Kênh YouTube của Flutter
Sparky tự hào về bạn!