1.准备工作
在此 Codelab 中,您将学习如何在本地开发期间将 Firebase Emulator Suite 与 Flutter 搭配使用。您将了解如何通过 Emulator Suite 使用电子邮件地址/密码身份验证,以及如何在 Firestore 模拟器中读取和写入数据。最后,您将从模拟器中导入和导出数据,以便每次返回开发时都使用相同的虚构数据。
前提条件
此 Codelab 假定您具有一些 Flutter 经验。如果没有,您可能需要先了解基础知识。以下链接非常有用:
您还应该具有一定的 Firebase 经验,但如果您从未将 Firebase 添加到过 Flutter 项目,也没有关系。如果您不熟悉 Firebase 控制台,或者完全不熟悉 Firebase,请先访问以下链接:
您将创建的内容
此 Codelab 将指导您构建一个简单的日记应用。该应用程序将包含一个登录屏幕和一个可让您阅读以前的日记条目和创建新日记条目的屏幕。
学习内容
您将学习如何开始使用 Firebase,以及如何将 Firebase Emulator 套件集成并使用到您的 Flutter 开发工作流中。我们将介绍以下 Firebase 主题:
请注意,这些主题在介绍 Firebase Emulator Suite 时必不可少。此 Codelab 将重点介绍如何向 Flutter 应用添加 Firebase 项目,以及使用 Firebase Emulator Suite 进行开发。我们不会对 Firebase Authentication 或 Firestore 进行深入讨论。如果您不熟悉这些主题,建议您先学习“了解 Firebase for Flutter”Codelab。
您需要满足的条件
- 具备 Flutter 方面的实用知识,并安装了 SDK
- Intellij JetBrains 或 VS Code 文本编辑器
- Google Chrome 浏览器(或 Flutter 的其他首选目标开发平台)。此 Codelab 中的一些终端命令将假定您在 Chrome 上运行应用)
2. 创建和设置 Firebase 项目
您需要完成的第一个任务是在 Firebase 的网络控制台中创建一个 Firebase 项目。此 Codelab 的绝大部分内容都将重点介绍 Emulator Suite,它使用本地运行的界面,但您必须先设置一个完整的 Firebase 项目。
创建 Firebase 项目
- 登录 Firebase 控制台。
- 在 Firebase 控制台中,点击添加项目(或创建项目),然后为您的 Firebase 项目输入一个名称(例如“Firebase-Flutter-Codelab”)。
- 点击各个项目创建选项。如果系统提示,请接受 Firebase 条款。跳过设置 Google Analytics,因为您不会为此应用使用 Google Analytics。
如需详细了解 Firebase 项目,请参阅了解 Firebase 项目。
您正在构建的应用使用两款可用于 Flutter 应用的 Firebase 产品:
- Firebase Authentication:让用户可以登录到您的应用。
- Cloud Firestore:用于将结构化数据保存到云端,并在数据发生变化时即时获得通知。
这两种产品需要特殊配置,或者需要使用 Firebase 控制台启用。
启用 Cloud Firestore
Flutter 应用使用 Cloud Firestore 保存日志条目。
启用 Cloud Firestore:
- 在 Firebase 控制台的构建部分中,点击 Cloud Firestore。
- 点击创建数据库。
- 选择 Start in test mode 选项。阅读有关安全规则的免责声明。测试模式可确保您在开发过程中可以随意向数据库写入数据。点击下一步。
- 选择数据库的位置(您可以使用默认值)。请注意,此位置以后无法更改。
- 点击启用。
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 项目的工具。使用 Emulator Suite 需要 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”和“模拟器”(没有 Authentication 选项,因为它不使用可通过 Flutter 项目文件修改的配置。)
- 接下来,在出现提示时选择“使用现有项目”。
- 现在,选择您在上一步中创建的项目:flutter-firebase-codelab。
- 接下来,您需要回答一系列有关为生成的文件命名的问题。建议按 Enter 键选择默认值。
- 最后,您需要配置模拟器。从列表中选择 Firestore 和 Authentication,然后按 Enter 键与每个模拟器使用的特定端口有关的每个问题。当系统询问您是否要使用模拟器界面时,您应选择默认的“是”。
完成此过程后,您应该会看到类似于以下屏幕截图的输出。
重要提示:您的输出可能与我的输出略有不同(如下面的屏幕截图所示),因为最后一个问题默认为“否”(如果您已下载模拟器)。
配置 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
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 端口,以便我们与模拟器进行交互。运行该命令时,您应该会看到类似如下所示的输出:
此输出可以告诉您正在运行哪些模拟器,以及您可以在哪里查看模拟器。首先,查看位于 localhost:4000
的模拟器界面。
这是本地模拟器界面的首页。它会列出所有可用的模拟器,每个模拟器都标有开启或关闭状态。
5. Firebase Auth 模拟器
您将使用的第一个模拟器是 Authentication 模拟器。点击“前往模拟器”以启动 Auth 模拟器您将看到如下所示的页面:
此页面与 Auth 网页控制台页面类似。其中包含一个列出用户的表格(例如在线控制台),并且允许您手动添加用户。这里的一个最大区别是,模拟器上唯一可用的身份验证方法选项是电子邮件地址和密码。这对于本地开发已经足够。
接下来,您将逐步介绍如何向 Firebase Auth 模拟器添加用户,然后通过 Flutter 界面使该用户登录。
添加用户
点击“添加用户”按钮,然后在表单中填写以下信息:
- 显示名称:Dash
- 电子邮件地址:dash@email.com
- 密码:dashword
提交表单,您将看到表格中现在包含一个用户。现在,您可以更新代码以使用该用户登录。
logged_out_view.dart
LoggedOutView
widget 中唯一需要更新的代码是在用户按下登录按钮时触发的回调。更新代码,使其如下所示:
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
中的代码进一步阐明了这一点。
app_state.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>
对象。未来完成时,此代码会检查 UserCredential
是否附加了 User
。如果凭据对象上有用户,则表示用户已成功登录,系统可以设置 AppState.user
属性。如果没有,则表示出现了错误,并输出了该信息。
请注意,此方法中专用于此应用的唯一代码(而不是常规的 FirebaseAuth 代码)是对 _listenForEntries
方法的调用,我们将在下一步中对此进行介绍。
待办事项:操作图标 – 重新加载您的应用,然后在应用呈现时按“登录”按钮。这会使应用转到显示“Welcome Back, Person!”(欢迎回来,朋友!)的页面顶部。身份验证必须正常运行,因为它允许您导航到此页面,但需要对 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( // ...
现在,以下代码行会从 AppState
对象的 User
属性获取 displayName
。此 displayName
在您定义第一个用户时在模拟器中设置。现在,您的应用应该会显示“Welcome back, Dash!”(欢迎回来,Dash!)而不是 TODO
。
6. 对 Firestore 模拟器执行数据读写操作
首先,查看 Firestore 模拟器。在模拟器界面首页 (localhost:4000
) 上,点击“前往模拟器”Firestore 卡片上的卡片它应如下所示:
模拟器:
Firebase 控制台:
如果您曾使用过 Firestore,会注意到此页面类似于 Firebase 控制台的 Firestore 页面。不过,二者之间存在一些显著差异。
- 只需点按一下按钮即可清除所有数据。这对于生产数据来说很危险,但有助于快速迭代!如果您正在处理新项目,并且数据模型发生变化,这很容易清除。
- 有一个“请求”标签页。通过此标签页,您可以观察向此模拟器发出的传入请求。我将更详细地介绍此标签。
- 没有“规则”、“索引”或“使用情况”标签页。有一个工具(将在下一部分讨论)可帮助您编写安全规则,但您无法为本地模拟器设置安全规则。
总而言之,此版本的 Firestore 提供了更多在开发过程中有用的工具,并移除了在生产环境中所需的工具。
写入 Firestore
在讨论“请求”之前请先发出请求。这需要更新代码。首先在应用中连接表单,以便将新的日志 Entry
写入 Firestore。
提交 Entry
的大致流程如下:
- 用户填写表单并按下
Submit
按钮 - 界面调用
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>
。
本例中的“条目”因此 Firestore 创建了一个。
添加该代码后,热重载或重启应用,登录并导航到 EntryForm
视图。您可以根据需要在表单中填写任何Strings
。(Date 字段将采用任何字符串,因为在此 Codelab 中,该字段已进行了简化。它既没有进行强有力的验证,也没有以任何方式关注 DateTime
对象。)
在表单上按“提交”。应用中不会发生任何变化,但您可以在模拟器界面中看到新条目。
Firestore 模拟器中的“请求”标签页
在界面中,前往 Firestore 模拟器,然后查看“Data”标签页。您应该会看到,数据库的根目录下有一个名为“Entries”的集合。这份表单应包含您在表单中输入的信息。
这证明了 AppState.writeEntryToFirestore
正常运行,现在您可以在“请求”标签页中进一步探索该请求。立即点击该标签页。
Firestore 模拟器请求
在这里,您应该会看到一个类似于以下内容的列表:
您可以点击进入这些列表项,看到很多有用的信息。点击与您的请求对应的 CREATE
列表项,创建新日记条目。您将看到如下所示的新表:
如前所述,Firestore 模拟器提供了用于开发应用的安全规则的工具。此视图会准确显示此请求通过(或失败,如果是这种情况)的安全规则中的哪一行。在更强大的应用中,安全规则可以扩展并包含多项授权检查。此视图用于帮助编写和调试这些授权规则。
它还提供了一种简单方法来检查此请求的每一部分,包括元数据和身份验证数据。这些数据用于编写复杂的授权规则。
从 Firestore 读取数据
Firestore 使用数据同步功能将更新后的数据推送到已连接的设备。在 Flutter 代码中,您可以监听(或订阅)Firestore 集合和文档,这样每当数据发生更改时,您的代码都会收到通知。在此应用中,监听 Firestore 更新的操作是在名为 AppState._listenForEntries
的方法中完成的。
此代码分别与名为 AppState._entriesStreamController
和 AppState.entries
的 StreamController
和 Stream
结合使用。该代码已经编写完成,界面中显示 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); }); } // ... }
此代码会监听“条目”Firestore 中的集合。当 Firestore 通知此客户端有新数据时,它会传递该数据,_listenForEntries
中的代码会将其所有子文档更改为可供应用使用的对象 (Entry
)。然后,它会将这些条目添加到名为 _entriesStreamController
的 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
进入模拟器界面,您应该会看到与之前使用的相同数据。
关闭模拟器时自动导出数据
您还可以在退出模拟器时自动导出数据,而无需记得在每个开发会话结束时导出数据。
启动模拟器时,运行带有两个额外标志的 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”。您可以在“complete”(完成)中找到此 Codelab 的完整代码GitHub 上的目录:Flutter Codelab
所学内容
- 设置 Flutter 应用以使用 Firebase
- 设置 Firebase 项目
- FlutterFire CLI
- Firebase CLI
- Firebase Authentication 模拟器
- Firebase Firestore 模拟器
- 导入和导出模拟器数据
后续步骤
- 详细了解如何在 Flutter 中使用 Firestore 和 Authentication:“了解如何将 Firebase 用于 Flutter”Codelab
- 探索其他提供模拟器的 Firebase 工具:
- Cloud Storage
- Cloud Functions
- Realtime Database
- 探索 FlutterFire 界面,快速向您的应用添加 Google 身份验证。
了解详情
- Firebase 网站:firebase.google.com
- Flutter 网站:flutter.dev
- FlutterFire Firebase Flutter 微件:firebase.flutter.dev
- Firebase YouTube 频道
- Flutter YouTube 频道
Sparky 为你骄傲!