1. ก่อนเริ่มต้น
ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีใช้ Firebase Emulator Suite กับ Flutter ในระหว่างการพัฒนาในเครื่อง คุณจะได้เรียนรู้วิธีใช้การตรวจสอบสิทธิ์ด้วยอีเมลและรหัสผ่านผ่านชุดโปรแกรมจำลอง รวมถึงวิธีอ่านและเขียนข้อมูลไปยังโปรแกรมจำลอง Firestore สุดท้าย คุณจะต้องนำเข้าและส่งออกข้อมูลจากโปรแกรมจำลองเพื่อใช้ข้อมูลจำลองเดียวกันทุกครั้งที่กลับมาพัฒนา
ข้อกำหนดเบื้องต้น
Codelab นี้ถือว่าคุณมีประสบการณ์การใช้งาน Flutter มาบ้างแล้ว หากยังไม่เคยใช้ คุณอาจต้องเรียนรู้พื้นฐานก่อน ลิงก์ต่อไปนี้มีประโยชน์
นอกจากนี้ คุณควรมีประสบการณ์การใช้งาน Firebase ด้วย แต่ไม่เป็นไรหากคุณไม่เคยเพิ่ม Firebase ลงในโปรเจ็กต์ Flutter หากคุณไม่คุ้นเคยกับคอนโซล Firebase หรือเพิ่งเริ่มใช้ Firebase โปรดดูลิงก์ต่อไปนี้ก่อน
สิ่งที่คุณจะสร้าง
Codelab นี้จะแนะนำวิธีสร้างแอปพลิเคชันการจดบันทึกอย่างง่าย แอปพลิเคชันจะมีหน้าจอเข้าสู่ระบบ และหน้าจอที่ให้คุณอ่านบันทึกในวารสารที่ผ่านมาและสร้างบันทึกใหม่ได้
สิ่งที่คุณจะได้เรียนรู้
คุณจะได้เรียนรู้วิธีเริ่มต้นใช้งาน Firebase รวมถึงวิธีผสานรวมและใช้ Firebase Emulator Suite ในเวิร์กโฟลว์การพัฒนา Flutter หัวข้อ Firebase ที่จะกล่าวถึงมีดังนี้
โปรดทราบว่าเราจะกล่าวถึงหัวข้อเหล่านี้เท่าที่จำเป็นต่อการครอบคลุมชุดโปรแกรมจำลอง Firebase Codelab นี้มุ่งเน้นที่การเพิ่มโปรเจ็กต์ Firebase ลงในแอป Flutter และการพัฒนาโดยใช้ Firebase Emulator Suite จะไม่มีการพูดคุยเชิงลึกเกี่ยวกับการตรวจสอบสิทธิ์ Firebase หรือ Firestore หากคุณไม่คุ้นเคยกับหัวข้อเหล่านี้ เราขอแนะนำให้เริ่มต้นด้วยโค้ดแล็บการทำความรู้จัก Firebase สำหรับ Flutter
สิ่งที่ต้องมี
- มีความรู้พื้นฐานเกี่ยวกับ Flutter และติดตั้ง SDK
- โปรแกรมแก้ไขข้อความ Intellij JetBrains หรือ VS Code
- เบราว์เซอร์ Google Chrome (หรือเป้าหมายการพัฒนาอื่นๆ ที่คุณต้องการสำหรับ Flutter) คำสั่งเทอร์มินัลบางคำสั่งใน Codelab นี้จะถือว่าคุณเรียกใช้แอปใน Chrome)
2. สร้างและตั้งค่าโปรเจ็กต์ Firebase
งานแรกที่คุณต้องทำคือการสร้างโปรเจ็กต์ Firebase ในคอนโซลเว็บของ Firebase Codelab นี้ส่วนใหญ่จะเน้นที่ Emulator Suite ซึ่งใช้ UI ที่ทำงานในเครื่อง แต่คุณต้องตั้งค่าโปรเจ็กต์ Firebase แบบเต็มก่อน
สร้างโปรเจ็กต์ Firebase
- ลงชื่อเข้าใช้คอนโซล Firebase โดยใช้บัญชี Google
- คลิกปุ่มเพื่อสร้างโปรเจ็กต์ใหม่ แล้วป้อนชื่อโปรเจ็กต์ (เช่น
Firebase-Flutter-Codelab
)
- คลิกต่อไป
- หากได้รับแจ้ง ให้อ่านและยอมรับข้อกำหนดของ Firebase แล้วคลิกต่อไป
- (ไม่บังคับ) เปิดใช้ความช่วยเหลือจาก AI ในคอนโซล Firebase (เรียกว่า "Gemini ใน Firebase")
- สำหรับ Codelab นี้ คุณไม่จำเป็นต้องใช้ Google Analytics ดังนั้นให้ปิดตัวเลือก Google Analytics
- คลิกสร้างโปรเจ็กต์ รอให้ระบบจัดสรรโปรเจ็กต์ แล้วคลิกดำเนินการต่อ
ดูข้อมูลเพิ่มเติมเกี่ยวกับโปรเจ็กต์ Firebase ได้ที่ทําความเข้าใจโปรเจ็กต์ Firebase
ตั้งค่าผลิตภัณฑ์ Firebase
แอปที่คุณสร้างใช้ผลิตภัณฑ์ Firebase 2 รายการที่พร้อมใช้งานสำหรับแอป Flutter ดังนี้
- การตรวจสอบสิทธิ์ Firebase เพื่ออนุญาตให้ผู้ใช้ลงชื่อเข้าใช้แอปของคุณ
- Cloud Firestore เพื่อบันทึกข้อมูลที่มีโครงสร้างไว้ในระบบคลาวด์และรับการแจ้งเตือนทันทีเมื่อข้อมูลมีการเปลี่ยนแปลง
ผลิตภัณฑ์ทั้ง 2 รายการนี้ต้องมีการกำหนดค่าพิเศษหรือต้องเปิดใช้โดยใช้คอนโซล Firebase
เปิดใช้ Cloud Firestore
แอป Flutter ใช้ Cloud Firestore เพื่อบันทึกรายการในสมุดบันทึก
เปิดใช้ Cloud Firestore
- ในส่วนสร้างของคอนโซล Firebase ให้คลิก Cloud Firestore
- คลิกสร้างฐานข้อมูล
- เลือกตัวเลือกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัย โหมดทดสอบช่วยให้คุณเขียนไปยังฐานข้อมูลได้อย่างอิสระในระหว่างการพัฒนา คลิกถัดไป
- เลือกตำแหน่งสำหรับฐานข้อมูล (คุณใช้ค่าเริ่มต้นได้) โปรดทราบว่าคุณจะเปลี่ยนตำแหน่งนี้ในภายหลังไม่ได้
- คลิกเปิดใช้
3. ตั้งค่าแอป Flutter
คุณจะต้องดาวน์โหลดโค้ดเริ่มต้นและติดตั้ง Firebase CLI ก่อนที่เราจะเริ่ม
รับโค้ดเริ่มต้น
โคลนที่เก็บ GitHub จากบรรทัดคำสั่งโดยใช้คำสั่งต่อไปนี้
git clone https://github.com/flutter/codelabs.git flutter-codelabs
หรือหากคุณติดตั้งเครื่องมือ CLI ของ GitHub ไว้ ให้ทำดังนี้
gh repo clone flutter/codelabs flutter-codelabs
คุณควรโคลนโค้ดตัวอย่างลงในไดเรกทอรี flutter-codelabs
ซึ่งมีโค้ดสำหรับชุด Codelab โค้ดสำหรับ Codelab นี้อยู่ใน flutter-codelabs/firebase-emulator-suite
โครงสร้างไดเรกทอรีภายใต้ flutter-codelabs/firebase-emulator-suite
ประกอบด้วยโปรเจ็กต์ Flutter 2 โปรเจ็กต์ โดยมีชื่อว่า complete
ซึ่งคุณสามารถใช้เป็นข้อมูลอ้างอิงได้หากต้องการข้ามไปยังส่วนที่ต้องการ หรืออ้างอิงโค้ดของคุณเอง ส่วนอีกโปรเจ็กต์ชื่อ start
โค้ดที่คุณต้องการเริ่มต้นอยู่ในไดเรกทอรี flutter-codelabs/firebase-emulator-suite/start
เปิดหรือนำเข้าไดเรกทอรีนั้นไปยัง IDE ที่ต้องการ
cd flutter-codelabs/firebase-emulator-suite/start
ติดตั้ง Firebase CLI
Firebase CLI มีเครื่องมือสำหรับจัดการโปรเจ็กต์ Firebase คุณต้องติดตั้ง CLI เพื่อใช้ชุดโปรแกรมจำลอง
คุณติดตั้ง CLI ได้หลายวิธี วิธีที่ง่ายที่สุดหากคุณใช้ MacOS หรือ Linux คือการเรียกใช้คำสั่งนี้จากเทอร์มินัล
curl -sL https://firebase.tools | bash
หลังจากติดตั้ง CLI แล้ว คุณต้องตรวจสอบสิทธิ์กับ Firebase
- เข้าสู่ระบบ Firebase โดยใช้บัญชี Google โดยเรียกใช้คำสั่งต่อไปนี้
firebase login
- คำสั่งนี้จะเชื่อมต่อเครื่องในพื้นที่กับ Firebase และให้สิทธิ์เข้าถึงโปรเจ็กต์ Firebase แก่คุณ
- ทดสอบว่าได้ติดตั้ง CLI อย่างถูกต้องและมีสิทธิ์เข้าถึงบัญชีโดยแสดงโปรเจ็กต์ Firebase เรียกใช้คำสั่งต่อไปนี้
firebase projects:list
- รายการที่แสดงควรเหมือนกับโปรเจ็กต์ Firebase ที่แสดงในคอนโซล Firebase คุณควรเห็นอย่างน้อย firebase-flutter-codelab
ติดตั้ง FlutterFire CLI
FlutterFire CLI สร้างขึ้นบน Firebase CLI และช่วยให้การผสานรวมโปรเจ็กต์ Firebase กับแอป Flutter ง่ายขึ้น
ก่อนอื่น ให้ติดตั้ง CLI โดยทำดังนี้
dart pub global activate flutterfire_cli
ตรวจสอบว่าได้ติดตั้ง CLI แล้ว เรียกใช้คำสั่งต่อไปนี้ภายในไดเรกทอรีโปรเจ็กต์ Flutter และตรวจสอบว่า CLI แสดงเมนูความช่วยเหลือ
flutterfire --help
ใช้ Firebase CLI และ FlutterFire CLI เพื่อเพิ่มโปรเจ็กต์ Firebase ลงในแอป Flutter
เมื่อติดตั้ง CLI ทั้ง 2 รายการแล้ว คุณจะตั้งค่าผลิตภัณฑ์ Firebase แต่ละรายการ (เช่น Firestore) ดาวน์โหลดโปรแกรมจำลอง และเพิ่ม Firebase ลงในแอป Flutter ได้ด้วยคำสั่งในเทอร์มินัลเพียง 2-3 คำสั่ง
ก่อนอื่น ให้ตั้งค่า Firebase ให้เสร็จสมบูรณ์โดยเรียกใช้คำสั่งต่อไปนี้
firebase init
คำสั่งนี้จะนำคุณไปสู่ชุดคำถามที่จำเป็นต่อการตั้งค่าโปรเจ็กต์ ภาพหน้าจอเหล่านี้แสดงขั้นตอนการทำงาน
- เมื่อระบบแจ้งให้เลือกฟีเจอร์ ให้เลือก "Firestore" และ "โปรแกรมจำลอง" (ไม่มีตัวเลือกการตรวจสอบสิทธิ์ เนื่องจากไม่ได้ใช้การกำหนดค่าที่แก้ไขได้จากไฟล์โปรเจ็กต์ Flutter)
- จากนั้นเลือก "ใช้โปรเจ็กต์ที่มีอยู่" เมื่อได้รับข้อความแจ้ง
- ตอนนี้ ให้เลือกโปรเจ็กต์ที่คุณสร้างในขั้นตอนก่อนหน้า นั่นคือ flutter-firebase-codelab
- จากนั้นระบบจะถามคำถามชุดหนึ่งเกี่ยวกับการตั้งชื่อไฟล์ที่จะสร้างขึ้น ขอแนะนำให้กด "Enter" สำหรับคำถามแต่ละข้อเพื่อเลือกค่าเริ่มต้น
- สุดท้าย คุณจะต้องกำหนดค่าโปรแกรมจำลอง เลือก Firestore และการตรวจสอบสิทธิ์จากรายการ จากนั้นกด "Enter" สำหรับคำถามแต่ละข้อเกี่ยวกับพอร์ตที่เฉพาะเจาะจงที่จะใช้สำหรับโปรแกรมจำลองแต่ละรายการ คุณควรเลือกค่าเริ่มต้น "ใช่" เมื่อระบบถามว่าต้องการใช้ UI ของโปรแกรมจำลองหรือไม่
เมื่อสิ้นสุดกระบวนการ คุณควรเห็นเอาต์พุตที่มีลักษณะคล้ายกับภาพหน้าจอด้านล่าง
สำคัญ: เอาต์พุตของคุณอาจแตกต่างจากของฉันเล็กน้อยตามที่เห็นในภาพหน้าจอด้านล่าง เนื่องจากคำถามสุดท้ายจะตั้งค่าเริ่มต้นเป็น "ไม่" หากคุณดาวน์โหลดโปรแกรมจำลองไว้แล้ว
กำหนดค่า FlutterFire
จากนั้นคุณสามารถใช้ FlutterFire เพื่อสร้างโค้ด Dart ที่จำเป็นในการใช้ Firebase ในแอป Flutter
flutterfire configure
เมื่อเรียกใช้คำสั่งนี้ ระบบจะแจ้งให้คุณเลือกโปรเจ็กต์ Firebase ที่ต้องการใช้ และแพลตฟอร์มที่ต้องการตั้งค่า ใน Codelab นี้ ตัวอย่างจะใช้ Flutter Web แต่คุณสามารถตั้งค่าโปรเจ็กต์ Firebase ให้ใช้ตัวเลือกทั้งหมดได้
ภาพหน้าจอต่อไปนี้แสดงพรอมต์ที่คุณจะต้องตอบ
ภาพหน้าจอนี้แสดงเอาต์พุตที่ส่วนท้ายของกระบวนการ หากคุ้นเคยกับ Firebase คุณจะเห็นว่าไม่ต้องสร้างแอปพลิเคชันในคอนโซล และ FlutterFire CLI จะสร้างให้คุณ
เพิ่มแพ็กเกจ Firebase ไปยังแอป Flutter
ขั้นตอนการตั้งค่าสุดท้ายคือการเพิ่มแพ็กเกจ Firebase ที่เกี่ยวข้องลงในโปรเจ็กต์ Flutter ในเทอร์มินัล ให้ตรวจสอบว่าคุณอยู่ในรูทของโปรเจ็กต์ Flutter ที่ flutter-codelabs/firebase-emulator-suite/start
จากนั้นเรียกใช้คำสั่ง 3 รายการต่อไปนี้
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add cloud_firestore
ซึ่งเป็นแพ็กเกจเดียวที่คุณจะใช้ในแอปพลิเคชันนี้
4. การเปิดใช้ Firebase Emulator
ตอนนี้แอป Flutter และโปรเจ็กต์ Firebase ได้รับการตั้งค่าให้ใช้โปรแกรมจำลองได้แล้ว แต่คุณยังคงต้องบอกโค้ด Flutter ให้เปลี่ยนเส้นทางคำขอ Firebase ขาออกไปยังพอร์ตในเครื่อง
ก่อนอื่น ให้เพิ่มโค้ดการเริ่มต้น Firebase และโค้ดการตั้งค่าโปรแกรมจำลองลงในฟังก์ชัน main
ใน main.dart.
main.dart
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'app_state.dart'; import 'firebase_options.dart'; import 'logged_in_view.dart'; import 'logged_out_view.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); if (kDebugMode) { try { FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080); await FirebaseAuth.instance.useAuthEmulator('localhost', 9099); } catch (e) { // ignore: avoid_print print(e); } } runApp(MyApp()); }
โค้ด 2-3 บรรทัดแรกจะเริ่มต้น Firebase โดยทั่วไปแล้ว หากคุณใช้ Firebase ในแอป Flutter คุณควรเริ่มต้นด้วยการเรียกใช้ WidgetsFlutterBinding.ensureInitialized
และ Firebase.initializeApp
หลังจากนั้น โค้ดที่ขึ้นต้นด้วยบรรทัด if (kDebugMode)
จะบอกให้แอปกำหนดเป้าหมายเป็นโปรแกรมจำลองแทนที่จะเป็นโปรเจ็กต์ Firebase ที่ใช้งานจริง kDebugMode
ช่วยให้มั่นใจได้ว่าการกำหนดเป้าหมายไปยังโปรแกรมจำลองจะเกิดขึ้นเฉพาะในกรณีที่คุณอยู่ในสภาพแวดล้อมการพัฒนา เนื่องจาก kDebugMode
เป็นค่าคงที่ คอมไพเลอร์ Dart จึงทราบว่าควรนำบล็อกโค้ดดังกล่าวออกทั้งหมดในโหมดรีลีส
เปิดโปรแกรมจำลอง
คุณควรเริ่มโปรแกรมจำลองก่อนเริ่มแอป Flutter โดยเริ่มโปรแกรมจำลองด้วยการเรียกใช้คำสั่งนี้ในเทอร์มินัล
firebase emulators:start
คำสั่งนี้จะบูตโปรแกรมจำลองและเปิดเผยพอร์ต localhost ที่เราใช้โต้ตอบกับโปรแกรมจำลองได้ เมื่อเรียกใช้คำสั่งดังกล่าว คุณควรเห็นเอาต์พุตที่คล้ายกับเอาต์พุตต่อไปนี้
เอาต์พุตนี้จะบอกให้ทราบว่าอีมูเลเตอร์ใดที่กำลังทำงานอยู่ และคุณจะไปดูอีมูเลเตอร์ได้ที่ใด ก่อนอื่น ให้ดู UI ของโปรแกรมจำลองที่ localhost:4000
นี่คือหน้าแรกของ UI ของโปรแกรมจำลองในเครื่อง โดยจะแสดงรายการโปรแกรมจำลองทั้งหมดที่พร้อมใช้งาน และแต่ละรายการจะมีป้ายกำกับสถานะเปิดหรือปิด
5. โปรแกรมจำลอง Firebase Auth
โปรแกรมจำลองแรกที่คุณจะใช้คือโปรแกรมจำลองการตรวจสอบสิทธิ์ เริ่มต้นด้วยโปรแกรมจำลองการตรวจสอบสิทธิ์โดยคลิก "ไปที่โปรแกรมจำลอง" ในการ์ดการตรวจสอบสิทธิ์ใน UI แล้วคุณจะเห็นหน้าเว็บที่มีลักษณะดังนี้
หน้านี้มีความคล้ายคลึงกับหน้าเว็บคอนโซลการตรวจสอบสิทธิ์ โดยจะมีตารางแสดงรายชื่อผู้ใช้เหมือนกับคอนโซลออนไลน์ และให้คุณเพิ่มผู้ใช้ด้วยตนเองได้ ความแตกต่างที่สำคัญอย่างหนึ่งคือตัวเลือกวิธีการตรวจสอบสิทธิ์เดียวที่ใช้ได้ในโปรแกรมจำลองคือผ่านอีเมลและรหัสผ่าน ซึ่งเพียงพอสำหรับการพัฒนาในเครื่อง
จากนั้นคุณจะดูขั้นตอนการเพิ่มผู้ใช้ลงในโปรแกรมจำลอง Firebase Auth แล้วบันทึกการเข้าสู่ระบบของผู้ใช้รายนั้นผ่าน UI ของ Flutter
เพิ่มผู้ใช้
คลิกปุ่ม "เพิ่มผู้ใช้" แล้วกรอกข้อมูลต่อไปนี้ในแบบฟอร์ม
- ชื่อที่แสดง: Dash
- อีเมล: dash@email.com
- รหัสผ่าน: dashword
ส่งแบบฟอร์ม แล้วคุณจะเห็นว่าตอนนี้ตารางมีผู้ใช้แล้ว ตอนนี้คุณสามารถอัปเดตรหัสเพื่อเข้าสู่ระบบด้วยผู้ใช้รายนั้นได้แล้ว
logged_out_view.dart
โค้ดเดียวในวิดเจ็ต LoggedOutView
ที่ต้องอัปเดตคือโค้ดในฟังก์ชันเรียกกลับที่ทริกเกอร์เมื่อผู้ใช้กดปุ่มเข้าสู่ระบบ อัปเดตโค้ดให้มีลักษณะดังนี้
class LoggedOutView extends StatelessWidget { final AppState state; const LoggedOutView({super.key, required this.state}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Firebase Emulator Suite Codelab'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Please log in', style: Theme.of(context).textTheme.displaySmall, ), Padding( padding: const EdgeInsets.all(8.0), child: ElevatedButton( onPressed: () async { await state.logIn('dash@email.com', 'dashword').then((_) { if (state.user != null) { context.go('/'); } }); }, child: const Text('Log In'), ), ), ], ), ), ); } }
โค้ดที่อัปเดตจะแทนที่สตริง TODO
ด้วยอีเมลและรหัสผ่านที่คุณสร้างไว้ในโปรแกรมจำลองการตรวจสอบสิทธิ์ และในบรรทัดถัดไป บรรทัด if(true)
จะถูกแทนที่ด้วยโค้ดที่ตรวจสอบว่า state.user
เป็นค่าว่างหรือไม่ โค้ดใน AppClass
จะช่วยให้เข้าใจเรื่องนี้มากขึ้น
app_state.dart
คุณต้องอัปเดตโค้ด 2 ส่วนใน AppState
ก่อนอื่น ให้กำหนดประเภท User
จากแพ็กเกจ firebase_auth
ให้กับ AppState.user ของสมาชิกในชั้นเรียน แทนที่จะกำหนดประเภท 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>
เมื่อ Future เสร็จสมบูรณ์ โค้ดนี้จะตรวจสอบว่ามี User
แนบมากับ UserCredential
หรือไม่ หากมีผู้ใช้ในออบเจ็กต์ข้อมูลเข้าสู่ระบบ แสดงว่าผู้ใช้เข้าสู่ระบบสำเร็จและตั้งค่าพร็อพเพอร์ตี้ AppState.user
ได้ หากไม่มี แสดงว่ามีข้อผิดพลาดเกิดขึ้นและระบบจะพิมพ์ข้อผิดพลาดนั้น
โปรดทราบว่าโค้ดบรรทัดเดียวในวิธีนี้ที่เจาะจงสำหรับแอปนี้ (ไม่ใช่โค้ด FirebaseAuth ทั่วไป) คือการเรียกใช้เมธอด _listenForEntries
ซึ่งจะกล่าวถึงในขั้นตอนถัดไป
TODO: Action Icon – Reload your app, and then press the Login button when it renders. ซึ่งจะทำให้แอปนำทางไปยังหน้าที่ระบุว่า "ยินดีต้อนรับกลับมา คุณ" ที่ด้านบน การตรวจสอบสิทธิ์ต้องใช้งานได้ เนื่องจากคุณได้รับอนุญาตให้นำทางไปยังหน้านี้ แต่ต้องมีการอัปเดตเล็กน้อยใน logged_in_view.dart
เพื่อแสดงชื่อจริงของผู้ใช้
logged_in_view.dart
เปลี่ยนบรรทัดแรกในLoggedInView.build
วิธีดังนี้
class LoggedInView extends StatelessWidget { final AppState state; LoggedInView({super.key, required this.state}); final PageController _controller = PageController(initialPage: 1); @override Widget build(BuildContext context) { final name = state.user!.displayName ?? 'No Name'; return Scaffold( // ...
ตอนนี้บรรทัดนี้จะดึง displayName
จากพร็อพเพอร์ตี้ User
ในออบเจ็กต์ AppState
displayName
นี้ได้รับการตั้งค่าในโปรแกรมจำลองเมื่อคุณกำหนดผู้ใช้รายแรก ตอนนี้แอปควรแสดงข้อความ "ยินดีต้อนรับกลับมา แดช!" เมื่อคุณเข้าสู่ระบบ แทนที่จะเป็น TODO
6. อ่านและเขียนข้อมูลไปยังโปรแกรมจำลอง Firestore
ก่อนอื่น ให้ลองใช้โปรแกรมจำลอง Firestore ในหน้าแรกของ UI ของโปรแกรมจำลอง (localhost:4000
) ให้คลิก "ไปที่โปรแกรมจำลอง" ในการ์ด Firestore โดยควรมีลักษณะดังนี้
โปรแกรมจำลอง:
คอนโซล Firebase
หากเคยใช้ Firestore มาก่อน คุณจะเห็นว่าหน้านี้มีลักษณะคล้ายกับหน้า Firestore ในคอนโซล Firebase แต่ก็มีความแตกต่างที่สำคัญอยู่บ้าง
- คุณล้างข้อมูลทั้งหมดได้ด้วยการแตะปุ่มเดียว การดำเนินการนี้อาจเป็นอันตรายต่อข้อมูลเวอร์ชันที่ใช้งานจริง แต่ก็มีประโยชน์สำหรับการทำซ้ำอย่างรวดเร็ว หากคุณกำลังทำงานในโปรเจ็กต์ใหม่และโมเดลข้อมูลมีการเปลี่ยนแปลง คุณก็ล้างข้อมูลออกได้ง่ายๆ
- มีแท็บ "คำขอ" แท็บนี้ช่วยให้คุณดูคำขอขาเข้าที่ส่งไปยังโปรแกรมจำลองนี้ได้ เราจะพูดถึงแท็บนี้อย่างละเอียดในอีกสักครู่
- ไม่มีแท็บสำหรับกฎ ดัชนี หรือการใช้งาน มีเครื่องมือ (อธิบายไว้ในส่วนถัดไป) ที่ช่วยเขียนกฎความปลอดภัย แต่คุณไม่สามารถตั้งกฎความปลอดภัยสำหรับโปรแกรมจำลองในเครื่องได้
สรุปรายการดังกล่าวได้ว่า Firestore เวอร์ชันนี้มีเครื่องมือที่เป็นประโยชน์มากขึ้นในระหว่างการพัฒนา และนำเครื่องมือที่จำเป็นในเวอร์ชันที่ใช้งานจริงออก
เขียนไปยัง Firestore
ก่อนที่จะพูดถึงแท็บ "คำขอ" ในโปรแกรมจำลอง ให้ส่งคำขอก่อน ซึ่งต้องมีการอัปเดตโค้ด เริ่มต้นด้วยการเชื่อมต่อแบบฟอร์มในแอปเพื่อเขียนบันทึกใหม่ Entry
ไปยัง Firestore
ขั้นตอนการส่ง Entry
ในภาพรวมมีดังนี้
- ผู้ใช้กรอกแบบฟอร์มและกดปุ่ม
Submit
- UI เรียก
AppState.writeEntryToFirebase
AppState.writeEntryToFirebase
เพิ่มรายการลงใน Firebase
ไม่จำเป็นต้องเปลี่ยนแปลงโค้ดใดๆ ที่เกี่ยวข้องกับขั้นตอนที่ 1 หรือ 2 ระบบจะเพิ่มโค้ดเดียวที่ต้องเพิ่มสำหรับขั้นตอนที่ 3 ในคลาส AppState
ทำการเปลี่ยนแปลงต่อไปนี้กับ AppState.writeEntryToFirebase
app_state.dart
import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'entry.dart'; class AppState { AppState() { _entriesStreamController = StreamController.broadcast(onListen: () { _entriesStreamController.add([ Entry( date: '10/09/2022', text: lorem, title: '[Example] My Journal Entry', ) ]); }); } User? user; Stream<List<Entry>> get entries => _entriesStreamController.stream; late final StreamController<List<Entry>> _entriesStreamController; Future<void> logIn(String email, String password) async { final credential = await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); if (credential.user != null) { user = credential.user!; _listenForEntries(); } else { print('no user!'); } } void writeEntryToFirebase(Entry entry) { FirebaseFirestore.instance.collection('Entries').add(<String, String>{ 'title': entry.title, 'date': entry.date.toString(), 'text': entry.text, }); } // ... }
โค้ดในเมธอด writeEntryToFirebase จะดึงข้อมูลอ้างอิงไปยังคอลเล็กชันที่ชื่อ "Entries" ใน Firestore จากนั้นจะเพิ่มรายการใหม่ซึ่งต้องเป็นประเภท Map<String, String>
ในกรณีนี้ ไม่มีคอลเล็กชัน "Entries" ใน Firestore ดังนั้น Firestore จึงสร้างขึ้นมา
เมื่อเพิ่มโค้ดแล้ว ให้โหลดแอปใหม่แบบด่วนหรือรีสตาร์ทแอป จากนั้นเข้าสู่ระบบแล้วไปที่มุมมอง EntryForm
คุณสามารถกรอกแบบฟอร์มด้วยStrings
อะไรก็ได้ที่ต้องการ (ฟิลด์วันที่จะรับสตริงใดก็ได้ เนื่องจากเราได้ลดความซับซ้อนสำหรับโค้ดแล็บนี้แล้ว ไม่มีการตรวจสอบที่เข้มงวดหรือสนใจออบเจ็กต์ DateTime
แต่อย่างใด)
กดส่งในแบบฟอร์ม จะไม่มีอะไรเกิดขึ้นในแอป แต่คุณจะเห็นรายการใหม่ใน UI ของโปรแกรมจำลอง
แท็บคำขอในโปรแกรมจำลอง Firestore
ใน UI ให้ไปที่โปรแกรมจำลอง Firestore แล้วดูแท็บ "ข้อมูล" คุณควรเห็นว่าตอนนี้มีคอลเล็กชันอยู่ที่รูทของฐานข้อมูลชื่อ "Entries" ซึ่งควรมีเอกสารที่มีข้อมูลเดียวกันกับที่คุณป้อนในแบบฟอร์ม
ซึ่งเป็นการยืนยันว่า AppState.writeEntryToFirestore
ทำงานแล้ว และตอนนี้คุณสามารถสำรวจคำขอเพิ่มเติมในแท็บคำขอได้ คลิกแท็บนั้นเลย
คำขอของโปรแกรมจำลอง Firestore
คุณควรเห็นรายการที่มีลักษณะคล้ายกับรายการต่อไปนี้
คุณคลิกรายการใดก็ได้ในรายการดังกล่าวเพื่อดูข้อมูลที่เป็นประโยชน์ได้ คลิกCREATE
รายการในรายการที่สอดคล้องกับคำขอของคุณเพื่อสร้างรายการบันทึกบัญชีใหม่ คุณจะเห็นตารางใหม่ที่มีลักษณะดังนี้
ดังที่กล่าวไว้ โปรแกรมจำลอง Firestore มีเครื่องมือในการพัฒนากฎการรักษาความปลอดภัยของแอป มุมมองนี้จะแสดงบรรทัดในกฎความปลอดภัยที่คำขอนี้ผ่าน (หรือไม่ผ่าน หากเป็นกรณีนั้น) ในแอปที่มีความแข็งแกร่งมากขึ้น กฎความปลอดภัยจะขยายตัวและมีการตรวจสอบการให้สิทธิ์หลายรายการ มุมมองนี้ใช้เพื่อช่วยเขียนและแก้ไขข้อบกพร่องของกฎการให้สิทธิ์เหล่านั้น
นอกจากนี้ ยังช่วยให้ตรวจสอบคำขอนี้ทุกส่วนได้ง่ายๆ ซึ่งรวมถึงข้อมูลเมตาและข้อมูลการตรวจสอบสิทธิ์ ข้อมูลนี้ใช้เพื่อเขียนกฎการให้สิทธิ์ที่ซับซ้อน
การอ่านจาก Firestore
Firestore ใช้การซิงค์ข้อมูลเพื่อพุชข้อมูลที่อัปเดตไปยังอุปกรณ์ที่เชื่อมต่อ ในโค้ด Flutter คุณสามารถฟัง (หรือติดตาม) คอลเล็กชันและเอกสาร 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
(ซึ่ง UI กำลังฟังอยู่) โค้ดนี้เป็นการอัปเดตเพียงอย่างเดียวที่จำเป็น
สุดท้ายนี้ โปรดทราบว่าเมธอด AppState.logIn
จะเรียกใช้ _listenForEntries
ซึ่งจะเริ่มกระบวนการฟังหลังจากที่ผู้ใช้เข้าสู่ระบบ
// ... Future<void> logIn(String email, String password) async { final credential = await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); if (credential.user != null) { user = credential.user!; _listenForEntries(); } else { print('no user!'); } } // ...
ตอนนี้ให้เรียกใช้แอป ซึ่งควรมีลักษณะดังนี้
7. ส่งออกและนำเข้าข้อมูลไปยังโปรแกรมจำลอง
โปรแกรมจำลอง Firebase รองรับการนำเข้าและส่งออกข้อมูล การใช้การนำเข้าและส่งออกจะช่วยให้คุณพัฒนาต่อด้วยข้อมูลชุดเดิมได้เมื่อหยุดพักจากการพัฒนาและกลับมาพัฒนาต่อ นอกจากนี้ คุณยังสามารถคอมมิตไฟล์ข้อมูลไปยัง Git ได้ และนักพัฒนาซอฟต์แวร์คนอื่นๆ ที่คุณทำงานด้วยจะมีข้อมูลเดียวกันเพื่อใช้ทำงาน
ส่งออกข้อมูลโปรแกรมจำลอง
ก่อนอื่น ให้ส่งออกข้อมูลโปรแกรมจำลองที่คุณมีอยู่แล้ว ขณะที่โปรแกรมจำลองยังทำงานอยู่ ให้เปิดหน้าต่างเทอร์มินัลใหม่ แล้วป้อนคำสั่งต่อไปนี้
firebase emulators:export ./emulators_data
.emulators_data
คืออาร์กิวเมนต์ที่บอก Firebase ว่าจะส่งออกข้อมูลไปที่ใด หากไม่มีไดเรกทอรี ระบบจะสร้างไดเรกทอรีให้ คุณใช้ชื่อใดก็ได้สำหรับไดเรกทอรีนั้น
เมื่อเรียกใช้คำสั่งนี้ คุณจะเห็นเอาต์พุตต่อไปนี้ในเทอร์มินัลที่คุณเรียกใช้คำสั่ง
i Found running emulator hub for project flutter-firebase-codelab-d6b79 at http://localhost:4400 i Creating export directory /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data i Exporting data to: /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data ✔ Export complete
และหากเปลี่ยนไปที่หน้าต่างเทอร์มินัลที่อีมูเลเตอร์ทำงานอยู่ คุณจะเห็นเอาต์พุตนี้
i emulators: Received export request. Exporting data to /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data. ✔ emulators: Export complete.
และสุดท้าย หากดูในไดเรกทอรีโปรเจ็กต์ คุณจะเห็นไดเรกทอรีที่ชื่อ ./emulators_data
ซึ่งมีไฟล์ JSON
พร้อมกับไฟล์ข้อมูลเมตาอื่นๆ ที่มีข้อมูลที่คุณบันทึกไว้
นำเข้าข้อมูลโปรแกรมจำลอง
ตอนนี้คุณสามารถนำเข้าข้อมูลดังกล่าวเป็นส่วนหนึ่งของเวิร์กโฟลว์การพัฒนาและเริ่มจากจุดที่คุณค้างไว้ได้แล้ว
ก่อนอื่น ให้หยุดโปรแกรมจำลองหากกำลังทำงานอยู่โดยกด CTRL+C
ในเทอร์มินัล
จากนั้นเรียกใช้emulators:start
คำสั่งที่คุณเคยเห็นแล้ว แต่มีแฟล็กที่บอกว่าควรนำเข้าข้อมูลใด
firebase emulators:start --import ./emulators_data
เมื่อโปรแกรมจำลองพร้อมทำงานแล้ว ให้ไปที่ UI ของโปรแกรมจำลองที่ localhost:4000
แล้วคุณจะเห็นข้อมูลเดียวกันกับที่เคยใช้ก่อนหน้านี้
ส่งออกข้อมูลโดยอัตโนมัติเมื่อปิดโปรแกรมจำลอง
นอกจากนี้ คุณยังส่งออกข้อมูลโดยอัตโนมัติเมื่อออกจากโปรแกรมจำลองได้ด้วย แทนที่จะต้องคอยจำเพื่อส่งออกข้อมูลเมื่อสิ้นสุดเซสชันการพัฒนาทุกครั้ง
เมื่อเริ่มโปรแกรมจำลอง ให้เรียกใช้คำสั่ง emulators:start
โดยมี 2 แฟล็กเพิ่มเติม
firebase emulators:start --import ./emulators_data --export-on-exit
Voila! ตอนนี้ระบบจะบันทึกข้อมูลและโหลดซ้ำทุกครั้งที่คุณทำงานกับโปรแกรมจำลองสำหรับโปรเจ็กต์นี้ นอกจากนี้ คุณยังระบุไดเรกทอรีอื่นเป็นอาร์กิวเมนต์ให้กับ –export-on-exit flag
ได้ด้วย แต่ระบบจะใช้ไดเรกทอรีที่ส่งไปยัง –import
เป็นค่าเริ่มต้น
คุณยังใช้ตัวเลือกเหล่านี้ร่วมกันได้ด้วย หมายเหตุจากเอกสารมีดังนี้ คุณระบุไดเรกทอรีการส่งออกได้ด้วยแฟล็ก firebase emulators:start --export-on-exit=./saved-data
หากใช้ --import
เส้นทางการส่งออกจะเป็นเส้นทางเดียวกันโดยค่าเริ่มต้น เช่น firebase emulators:start --import=./data-path --export-on-exit
สุดท้าย หากต้องการ ให้ส่งเส้นทางไดเรกทอรีที่แตกต่างกันไปยังแฟล็ก --import
และ --export-on-exit
8. ยินดีด้วย
คุณได้ทำตามบทความเริ่มต้นใช้งานโปรแกรมจำลอง Firebase และ Flutter จนจบแล้ว คุณดูโค้ดที่เสร็จสมบูรณ์สำหรับ Codelab นี้ได้ในไดเรกทอรี "complete" ใน GitHub: Flutter Codelabs
สิ่งที่เราได้พูดถึงไปแล้ว
- การตั้งค่าแอป Flutter ให้ใช้ Firebase
- การตั้งค่าโปรเจ็กต์ Firebase
- FlutterFire CLI
- Firebase CLI
- โปรแกรมจำลองการตรวจสอบสิทธิ์ Firebase
- โปรแกรมจำลอง Firebase Firestore
- การนำเข้าและส่งออกข้อมูลโปรแกรมจำลอง
ขั้นตอนถัดไป
- ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Firestore และการตรวจสอบสิทธิ์ใน Flutter ได้ที่ Get to know Firebase for Flutter Codelab
- สำรวจเครื่องมืออื่นๆ ของ Firebase ที่มีโปรแกรมจำลอง
- Cloud Storage
- Cloud Functions
- Realtime Database
- สำรวจ FlutterFire UI เพื่อเพิ่มการตรวจสอบสิทธิ์ของ Google ลงในแอปอย่างรวดเร็ว
ดูข้อมูลเพิ่มเติม
- เว็บไซต์ Firebase: firebase.google.com
- เว็บไซต์ Flutter: flutter.dev
- วิดเจ็ต Firebase Flutter ของ FlutterFire: firebase.flutter.dev
- ช่อง YouTube ของ Firebase
- ช่อง YouTube ของ Flutter
Sparky ภูมิใจในตัวคุณ