1. 开始之前
在此 Codelab 中,您将了解如何在本地开发期间将 Firebase Emulator Suite 与 Flutter 结合使用。您将了解如何通过模拟器套件使用电子邮件密码身份验证,以及如何在 Firestore 模拟器中读取和写入数据。最后,您将从模拟器导入和导出数据,以便每次返回开发时都使用相同的伪造数据。
先决条件
此 Codelab 假设您有一定的 Flutter 经验。如果没有,您可能想先学习基础知识。以下链接很有帮助:
您还应该有一些 Firebase 经验,但如果您从未将 Firebase 添加到 Flutter 项目中也没关系。如果您不熟悉 Firebase 控制台,或者您完全不熟悉 Firebase,请首先查看以下链接:
你将创造什么
此 Codelab 将指导您构建简单的日记应用程序。该应用程序将有一个登录屏幕,以及一个允许您阅读过去的日记条目并创建新条目的屏幕。
你将学到什么
您将了解如何开始使用 Firebase,以及如何将 Firebase 模拟器套件集成并使用到您的 Flutter 开发工作流程中。将涵盖以下 Firebase 主题:
请注意,这些主题的涵盖范围仅限于涵盖 Firebase 模拟器套件所需的范围。此 Codelab 的重点是向您的 Flutter 应用添加 Firebase 项目,并使用 Firebase Emulator Suite 进行开发。不会深入讨论 Firebase 身份验证或 Firestore。如果您不熟悉这些主题,我们建议您从了解 Firebase for Flutter Codelab开始。
你需要什么
- Flutter 的使用知识以及已安装的 SDK
- Intellij JetBrains 或 VS Code 文本编辑器
- Google Chrome 浏览器(或您的其他首选 Flutter 开发目标。此 Codelab 中的某些终端命令将假设您在 Chrome 上运行应用程序)
2. 创建并设置 Firebase 项目
您需要完成的第一个任务是在 Firebase 的 Web 控制台中创建 Firebase 项目。此 Codelab 的绝大多数内容将重点关注模拟器套件,它使用本地运行的 UI,但您必须首先设置完整的 Firebase 项目。
创建 Firebase 项目
- 登录 Firebase 控制台。
- 在 Firebase 控制台中,单击“添加项目” (或“创建项目”),然后输入 Firebase 项目的名称(例如“ Firebase-Flutter-Codelab”) 。
- 单击项目创建选项。如果出现提示,请接受 Firebase 条款。跳过设置 Google Analytics,因为您不会为此应用程序使用 Analytics。
要了解有关 Firebase 项目的更多信息,请参阅了解 Firebase 项目。
您正在构建的应用使用两种可用于 Flutter 应用的 Firebase 产品:
- Firebase 身份验证允许您的用户登录您的应用。
- Cloud Firestore将结构化数据保存在云上,并在数据发生变化时接收即时通知。
这两个产品需要特殊配置或需要使用 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
或者,如果您安装了GitHub 的 cli工具:
gh repo clone flutter/codelabs flutter-codelabs
示例代码应克隆到flutter-codelabs
目录中,其中包含 Codelab 集合的代码。此 Codelab 的代码位于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,因此您需要安装它。
安装 CLI 的方法有多种。如果您使用的是 MacOS 或 Linux,最简单的方法是从终端运行以下命令:
curl -sL https://firebase.tools | bash
安装 CLI 后,您必须使用 Firebase 进行身份验证。
- 运行以下命令,使用您的 Google 帐户登录 Firebase:
firebase login
- 此命令将您的本地计算机连接到 Firebase 并授予您对 Firebase 项目的访问权限。
- 通过列出您的 Firebase 项目来测试 CLI 是否已正确安装并可以访问您的帐户。运行以下命令:
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 后,您可以设置单独的 Firebase 产品(例如 Firestore)、下载模拟器,然后只需几个终端命令即可将 Firebase 添加到您的 Flutter 应用程序中。
首先,通过运行以下命令完成 Firebase 设置:
firebase init
该命令将引导您回答设置项目所需的一系列问题。这些屏幕截图显示了流程:
- 当提示选择功能时,选择“Firestore”和“模拟器”。 (没有身份验证选项,因为它不使用可从 Flutter 项目文件中修改的配置。)
- 接下来,出现提示时选择“使用现有项目”。
- 现在,选择您在上一步中创建的项目:flutter-firebase-codelab。
- 接下来,系统将询问您一系列有关命名将生成的文件的问题。我建议对每个问题按“Enter”键选择默认值。
- 最后,您需要配置模拟器。从列表中选择 Firestore 和身份验证,然后针对有关每个模拟器要使用的特定端口的每个问题按“Enter”键。当询问您是否要使用模拟器 UI 时,您应该选择默认值“是”。
在该过程结束时,您应该看到类似于以下屏幕截图的输出。
重要提示:您的输出可能与我的稍有不同,如下面的屏幕截图所示,因为如果您已经下载了模拟器,最后的问题将默认为“否”。
配置 FlutterFire
接下来,您可以使用 FlutterFire 生成所需的 Dart 代码,以便在 Flutter 应用程序中使用 Firebase。
flutterfire configure
运行此命令时,系统会提示您选择要使用的 Firebase 项目以及要设置的平台。在此 Codelab 中,示例使用 Flutter Web,但您可以将 Firebase 项目设置为使用所有选项。
以下屏幕截图显示了您需要回答的提示。
此屏幕截图显示了该过程结束时的输出。如果您熟悉 Firebase,您会注意到您不必在控制台中创建应用程序,FlutterFire CLI 已经为您完成了这件事。
将 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.dart 中的main
函数中main.dart.
主程序.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。几乎普遍来说,如果您在 Flutter 应用程序中使用 Firebase,您需要首先调用WidgetsFlutterBinding.ensureInitialized
和Firebase.initializeApp
。
接下来, if (kDebugMode)
行开头的代码告诉您的应用程序以模拟器而不是生产 Firebase 项目为目标。 kDebugMode
确保仅当您处于开发环境中时才会针对模拟器。因为kDebugMode
是一个常量值,所以 Dart 编译器知道在发布模式下完全删除该代码块。
启动模拟器
您应该在启动 Flutter 应用程序之前启动模拟器。首先,通过在终端中运行以下命令来启动模拟器:
firebase emulators:start
该命令启动模拟器,并公开本地主机端口,我们可以通过这些端口与它们进行交互。当您运行该命令时,您应该看到类似于以下内容的输出:
此输出告诉您哪些模拟器正在运行,以及您可以在哪里查看模拟器。首先,检查localhost:4000
的模拟器 UI。
这是本地模拟器 UI 的主页。它列出了所有可用的模拟器,并且每个模拟器都标有状态打开或关闭。
5.Firebase Auth 模拟器
您将使用的第一个模拟器是身份验证模拟器。通过单击 UI 中身份验证卡上的“转到模拟器”开始使用 Auth 模拟器,您将看到如下所示的页面:
此页面与 Auth Web 控制台页面相似。它有一个像在线控制台一样列出用户的表格,并允许您手动添加用户。这里的一个很大的区别是模拟器上唯一可用的身份验证方法选项是通过电子邮件和密码。这足以满足当地的发展。
接下来,您将逐步完成将用户添加到 Firebase Auth 模拟器,然后通过 Flutter UI 登录该用户的过程。
添加用户
单击“添加用户”按钮,并使用以下信息填写表单:
- 显示名称:破折号
- 电子邮件: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
字符串替换为您在身份验证模拟器中创建的电子邮件和密码。在下一行中, if(true)
行已替换为检查state.user
是否为 null 的代码。 AppClass
中的代码更清楚地说明了这一点。
应用程序状态.dart
AppState
中的两部分代码需要更新。首先,为类成员 AppState.user 提供firebase_auth
包中的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:操作图标 – 重新加载您的应用程序,然后在呈现时按登录按钮。这会导致应用程序导航到显示“欢迎回来,人员!”的页面。在顶部。身份验证必须有效,因为它允许您导航到此页面,但需要对logged_in_view.dart
进行较小的更新以显示用户的实际名称。
登录视图.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( // ...
现在,该行从AppState
对象的User
属性中获取displayName
。当您定义第一个用户时,此displayName
是在模拟器中设置的。您的应用程序现在应该显示“欢迎回来,Dash!”当您登录时,而不是TODO
。
6. 向 Firestore 模拟器读取和写入数据
首先,检查 Firestore 模拟器。在模拟器 UI 主页 ( localhost:4000
) 上,单击 Firestore 卡上的“转到模拟器”。它应该看起来像这样:
模拟器:
Firebase 控制台:
如果您有使用 Firestore 的经验,您会注意到此页面看起来与 Firebase 控制台 Firestore 页面类似。不过,还是有一些显着的差异。
- 您只需点击一个按钮即可清除所有数据。这对于生产数据来说是危险的,但对于快速迭代很有帮助!如果您正在开发一个新项目并且您的数据模型发生了变化,那么很容易清除。
- 有一个“请求”选项卡。此选项卡允许您查看对此模拟器发出的传入请求。我将稍后更详细地讨论此选项卡。
- 没有规则、索引或用法选项卡。有一个工具(在下一节中讨论)可以帮助编写安全规则,但您无法为本地模拟器设置安全规则。
总而言之,此版本的 Firestore 提供了更多在开发过程中有用的工具,并删除了生产中所需的工具。
写入 Firestore
在讨论模拟器中的“请求”选项卡之前,首先发出一个请求。这需要更新代码。首先连接应用程序中的表单以将新的日记Entry
写入 Firestore。
提交Entry
的高级流程是:
- 用户填写表格并按下
Submit
按钮 - UI调用
AppState.writeEntryToFirebase
-
AppState.writeEntryToFirebase
向 Firebase 添加条目
步骤 1 或步骤 2 中涉及的代码都不需要更改。步骤 3 中唯一需要添加的代码将添加到AppState
类中。对AppState.writeEntryToFirebase
进行以下更改。
应用程序状态.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 方法中的代码获取对 Firestore 中名为“Entries”的集合的引用。然后它添加一个新条目,该条目的类型必须为Map<String, String>
。
在本例中,Firestore 中的“Entries”集合不存在,因此 Firestore 创建了一个集合。
添加该代码后,热重载或重新启动您的应用程序,登录并导航到EntryForm
视图。您可以使用您想要的任何Strings
填写表格。 (Date 字段将采用任何字符串,因为它已针对此 Codelab 进行了简化。它没有强验证,也不以任何方式关心DateTime
对象。)
按表格上的“提交”。应用程序中不会发生任何事情,但您可以在模拟器 UI 中看到新条目。
Firestore 模拟器中的请求选项卡
在 UI 中,导航到 Firestore 模拟器,然后查看“数据”选项卡。您应该看到数据库的根目录现在有一个名为“Entries”的集合。该文档应该包含您在表单中输入的相同信息。
这证实了AppState.writeEntryToFirestore
有效,现在您可以在“请求”选项卡中进一步探索该请求。现在单击该选项卡。
Firestore 模拟器请求
在这里,您应该看到一个与此类似的列表:
您可以单击任何列表项并查看大量有用的信息。单击与您的请求相对应的CREATE
列表项,以创建新的日记帐分录。您将看到一个如下所示的新表:
如前所述,Firestore 模拟器提供了用于开发应用安全规则的工具。此视图准确显示此请求在安全规则中的哪一行通过(或失败,如果是这种情况)。在更强大的应用程序中,安全规则可以增长并具有多个授权检查。该视图用于帮助编写和调试这些授权规则。
它还提供了一种简单的方法来检查该请求的每个部分,包括元数据和身份验证数据。该数据用于编写复杂的授权规则。
从 Firestore 读取
Firestore 使用数据同步将更新的数据推送到连接的设备。在 Flutter 代码中,您可以监听(或订阅)Firestore 集合和文档,只要数据发生变化,您的代码就会收到通知。在此应用程序中,侦听 Firestore 更新是在名为AppState._listenForEntries
方法中完成的。
此代码与分别称为AppState._entriesStreamController
和AppState.entries
的StreamController
和Stream
结合使用。该代码已经编写完毕,UI 中显示 Firestore 数据所需的所有代码也是如此。
更新_listenForEntries
方法以匹配以下代码:
应用程序状态.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); }); } // ... }
此代码侦听 Firestore 中的“Entries”集合。当 Firestore 通知此客户端有新数据时,它会传递该数据,并且_listenForEntries
中的代码将其所有子文档更改为我们的应用程序可以使用的对象 ( Entry
)。然后,它将这些条目添加到名为_entriesStreamController
(UI 正在侦听)的StreamController
中。此代码是唯一需要的更新。
最后,回想一下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
当模拟器启动后,导航到位于localhost:4000
的模拟器 UI,您应该会看到与之前使用的数据相同的数据。
关闭模拟器时自动导出数据
您还可以在退出模拟器时自动导出数据,而不必记住在每个开发会话结束时导出数据。
当您启动模拟器时,请运行带有两个附加标志的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. 恭喜!
您已完成 Firebase 模拟器和 Flutter 的启动和运行。您可以在 github 上的“完整”目录中找到此 Codelab 的完整代码: Flutter Codelabs
我们涵盖的内容
- 设置 Flutter 应用以使用 Firebase
- 设置 Firebase 项目
- FlutterFire CLI
- Firebase CLI
- Firebase 身份验证模拟器
- Firebase Firestore 模拟器
- 导入和导出模拟器数据
下一步
- 了解有关在 Flutter 中使用 Firestore 和身份验证的更多信息:了解 Firebase for Flutter Codelab
- 探索提供模拟器的其他 Firebase 工具:
- 云储存
- 云功能
- 实时数据库
- 探索FlutterFire UI以快速将 Google 身份验证添加到您的应用程序中。
了解更多
- Firebase 网站: firebase.google.com
- 颤动网站: flutter.dev
- FlutterFire Firebase Flutter 小部件: firebase.flutter.dev
- Firebase YouTube 频道
- 颤动 YouTube 频道
斯帕克为你感到骄傲!