1.准备工作
在此 Codelab 中,您将学习如何使用 FlutterFire 界面软件包将 Firebase Authentication 添加到 Flutter 应用。借助此软件包,您将向 Flutter 应用添加电子邮件地址/密码身份验证和 Google 登录身份验证。您还将学习如何设置 Firebase 项目,以及如何在 Flutter 应用中使用 FlutterFire CLI 初始化 Firebase。
前提条件
此 Codelab 假定您具有一些 Flutter 经验。如果没有,您可能需要先了解基础知识。以下链接非常有用:
您还应该具有一定的 Firebase 经验,但如果您从未将 Firebase 添加到过 Flutter 项目,也没有关系。如果您不熟悉 Firebase 控制台,或者完全不熟悉 Firebase,请先访问以下链接:
您将创建的内容
此 Codelab 将指导您使用 Firebase 进行身份验证,为 Flutter 应用构建身份验证流程。该应用会显示登录屏幕,即“Register”密码恢复屏幕和用户个人资料屏幕。
学习内容
此 Codelab 涵盖以下内容:
- 将 Firebase 添加到 Flutter 应用
- Firebase 控制台设置
- 使用 Firebase CLI 将 Firebase 添加到您的应用
- 使用 FlutterFire CLI 在 Dart 中生成 Firebase 配置
- 将 Firebase Authentication 添加到您的 Flutter 应用
- 控制台中的 Firebase Authentication 设置
- 使用
firebase_ui_auth
软件包添加电子邮件地址和密码登录 - 使用
firebase_ui_auth
软件包添加用户注册 - 添加“忘记了密码?”,信息页
- 使用
firebase_ui_auth
添加 Google 登录功能 - 配置应用,使其支持多个登录提供方。
- 使用
firebase_ui_auth
软件包向应用添加用户个人资料屏幕
此 Codelab 主要介绍如何使用 firebase_ui_auth
软件包添加强大的身份验证系统。如您所见,包含上述所有功能的整个应用只需使用大约 100 行代码即可实现。
您需要满足的条件
- 掌握 Flutter 的应用知识和所安装的 SDK
- 文本编辑器(Flutter 支持 JetBrains IDE、Android Studio 和 VS Code)
- Google Chrome 浏览器或 Flutter 的其他首选目标开发平台。(此 Codelab 中的某些终端命令将假定您在 Chrome 上运行应用)
2. 创建和设置 Firebase 项目
您需要完成的第一个任务是在 Firebase 的网络控制台中创建一个 Firebase 项目。
创建 Firebase 项目
- 登录 Firebase。
- 在 Firebase 控制台中,点击添加项目(或创建项目),然后为您的 Firebase 项目输入一个名称(例如“FlutterFire-UI-Codelab”)。
- 点击各个项目创建选项。如果系统提示,请接受 Firebase 条款。跳过设置 Google Analytics,因为您不会为此应用使用 Google Analytics。
如需详细了解 Firebase 项目,请参阅了解 Firebase 项目。
您正在构建的应用使用 Firebase Authentication,让您的用户能够登录您的应用。它还允许新用户从 Flutter 应用注册。
Firebase Authentication 需要使用 Firebase 控制台启用,并且在启用后需要进行特殊配置。
为 Firebase Authentication 启用电子邮件地址登录
要允许用户登录 Web 应用,您需先使用电子邮件地址/密码登录方法。稍后,您需要添加 Google 登录方法。
- 在 Firebase 控制台中,展开左侧面板中的构建菜单。
- 点击身份验证,然后依次点击开始使用按钮和登录方法标签页(也可以点击此处直接转到登录方法标签页)。
- 点击登录提供商列表中的电子邮件地址/密码,将启用开关设置为开启位置,然后点击保存。
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-auth-flutterfire-ui
中。
目录 flutter-codelabs/firebase-auth-flutterfire-ui
包含两个 Flutter 项目。一个名为 complete
,另一个名为 start
。start
目录包含不完整的项目,也是您最常使用的项目。
cd flutter-codelabs/firebase-auth-flutterfire-ui/start
如果您想快进,或者查看完成后的呈现效果,请在名为 complete 的目录中查找交叉引用。
如果您想按照此 Codelab 操作并自行添加代码,则应从位于 flutter-codelabs/firebase-auth-flutterfire-ui/start
的 Flutter 应用开始,并在整个 Codelab 中向该项目添加代码。打开该目录或将该目录导入您的首选 IDE。
安装 Firebase CLI
Firebase CLI 提供了用于管理 Firebase 项目的工具。FlutterFire CLI 需要使用 CLI,稍后您将安装此 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 项目相同。您应该会看到至少
flutterfire-ui-codelab.
安装 FlutterFire CLI
FlutterFire CLI 是一款工具,可帮助您在 Flutter 应用的所有受支持平台上简化 Firebase 的安装流程。它基于 Firebase CLI 构建而成。
首先,安装 CLI:
dart pub global activate flutterfire_cli
确保已安装 CLI。运行以下命令并确保 CLI 会输出帮助菜单。
flutterfire -—help
将您的 Firebase 项目添加到 Flutter 应用
配置 FlutterFire
您可以使用 FlutterFire 生成所需的 Dart 代码,以便在您的 Flutter 应用中使用 Firebase。
flutterfire configure
运行此命令时,系统会提示您选择要使用的 Firebase 项目以及要设置的平台。
以下屏幕截图显示了您需要回答的提示。
- 选择要使用的项目。在本例中,请使用
flutterfire-ui-codelab
- 选择要使用的平台。在此 Codelab 中,您需要按照相应步骤为 Web、iOS 和 Android 版 Flutter 配置 Firebase Authentication,但您可以将 Firebase 项目设置为使用所有选项。
- 此屏幕截图显示了该过程结束时的输出。如果您熟悉 Firebase,就会发现无需在控制台中创建平台应用(例如 Android 应用),而 FlutterFire CLI 会为您执行创建。
完成后,请在文本编辑器中查看 Flutter 应用。FlutterFire CLI 生成了一个名为 firebase_options.dart
的新文件。此文件包含一个名为 FirebaseOptions 的类,该类具有静态变量,用于存储每个平台所需的 Firebase 配置。如果您在运行 flutterfire configure
时选择了所有平台,则会看到名为 web
、android
、ios
和 macos
的静态值。
firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
// ignore: missing_enum_constant_in_switch
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
}
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyCqFjCV_9CZmYeIvcK9FVy4drmKUlSaIWY',
appId: '1:963656261848:web:7219f7fca5fc70afb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
authDomain: 'flutterfire-ui-codelab.firebaseapp.com',
storageBucket: 'flutterfire-ui-codelab.appspot.com',
measurementId: 'G-DGF0CP099H',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyDconZaCQpkxIJ5KQBF-3tEU0rxYsLkIe8',
appId: '1:963656261848:android:c939ccc86ab2dcdbb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.appspot.com',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.appspot.com',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.appspot.com',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
}
Firebase 使用应用一词来指代 Firebase 项目中特定平台的特定 build。例如,名为 FlutterFire-ui-codelab 的 Firebase 项目有多个应用:一个用于 Android,一个用于 iOS,一个用于 MacOS,一个用于 Web。
DefaultFirebaseOptions.currentPlatform
方法使用 Flutter 公开的 TargetPlatform
枚举来检测您的应用运行所在的平台,然后返回正确 Firebase 应用所需的 Firebase 配置值。
将 Firebase 软件包添加到 Flutter 应用
最后一步的设置步骤是将相关的 Firebase 软件包添加到您的 Flutter 项目中。firebase_options.dart
文件应该包含错误,因为它依赖于尚未添加的 Firebase 软件包。在终端中,确保您位于 Flutter 项目的根目录中 flutter-codelabs/firebase-emulator-suite/start
。然后,运行以下三个命令:
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add firebase_ui_auth
您目前只需要这些软件包。
初始化 Firebase
为了使用添加的软件包,并且 DefaultFirebaseOptions.currentPlatform,
更新了 main.dart
文件的 main
函数中的代码。
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
此代码有两件事。
WidgetsFlutterBinding.ensureInitialized()
告知 Flutter 在 Flutter 框架完全启动之前不要开始运行应用 widget 代码。Firebase 使用原生平台渠道,这需要运行框架。Firebase.initializeApp
会在您的 Flutter 应用和 Firebase 项目之间建立连接。DefaultFirebaseOptions.currentPlatform
是从我们生成的firebase_options.dart
文件导入的。此静态值用于检测您在哪个平台上运行,并传入相应的 Firebase 键。
4. 添加初始 Firebase 界面身份验证页面
Firebase 身份验证界面提供了代表应用中的整个屏幕的微件。这些屏幕会处理您整个应用中不同的身份验证流程,例如登录、注册、忘记密码、用户个人资料等。首先,请为您的应用添加一个着陆页,充当主应用的身份验证保护页面。
Material 或 Cupertino 应用
FlutterFire 界面要求您的应用封装在 MaterialApp 或 CupertinoApp 中。根据您的选择,界面会自动反映 Material 或 Cupertino 微件的差异。对于此 Codelab,请使用 MaterialApp
,它已在 app.dart
中添加到应用中。
app.dart
import 'package:flutter/material.dart';
import 'auth_gate.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AuthGate(),
);
}
}
检查身份验证状态
在显示登录屏幕之前,您需要确定用户当前是否通过身份验证。检查是否存在此问题的最常见方法是使用 Firebase 身份验证插件监听 FirebaseAuth 的 authStateChanges。
在上面的代码示例中,MaterialApp
在其构建方法中构建了 AuthGate
widget。(这是一个自定义 widget,并非由 FlutterFire 界面提供。)
需要更新该 widget 以包含 authStateChanges
流。
authStateChanges
API 会返回包含当前用户(如果用户已登录)的 Stream
,如果用户未登录,则返回 null。如需在我们的应用中订阅此状态,您可以使用 Flutter 的 StreamBuilder widget 并将数据流传递给它。
StreamBuilder
是一个 widget,它根据您向其传递的 Stream 中的最新数据快照来构建自身。当数据流发出新快照时,它会自动重新构建。
更新 auth_gate.dart
中的代码。
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [],
);
}
return const HomeScreen();
},
);
}
}
- 正在向
StreamBuilder.stream
传递FirebaseAuth.instance.authStateChanged
,即前面提到的数据流,如果用户已通过身份验证,它将返回一个 FirebaseUser
对象。(否则,它将返回null
。) - 接下来,代码会使用
snapshot.hasData
检查数据流中的值是否包含User
对象。 - 如果没有,它将返回一个
SignInScreen
widget。目前,该界面不会执行任何操作。这些信息将在下一步中更新。 - 否则,它会返回
HomeScreen
,这是应用的主要部分,只有经过身份验证的用户才能访问。
SignInScreen
是一个来自 FlutterFire 界面软件包的 widget。这将是此 Codelab 的下一步的重点。此时,您应该看到空白的登录屏幕。
5. 登录屏幕
FlutterFire 界面提供的 SignInScreen
widget 添加了以下功能:
- 允许用户登录
- 如果用户忘记了密码,可以点按“忘记了密码?”,并且系统会跳转到表单以重置密码
- 如果用户尚未注册,可以点按“注册”,系统即会将其转到另一个可以进行注册的表单。
同样,这只需要几行代码。回顾 AuthGate 微件中的代码:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(), // new
],
);
}
return const HomeScreen();
},
);
}
}
SignInScreen
widget 及其 providers
参数是实现上述所有功能所需的唯一代码。您现在应该会看到一个包含“email”的登录屏幕和“password”以及“登录”按钮按钮。
尽管它能正常运行,但缺少样式。该 widget 提供用于自定义登录屏幕外观的参数。例如,您可以添加公司的徽标。
自定义登录屏幕
headerBuilder
使用 SignInScreen.headerBuilder
参数,您可以在登录表单上方添加所需的任何 widget。此 widget 仅显示在较窄的屏幕(例如移动设备)上。在宽屏上,您可以使用 SignInScreen.sideBuilder
,此 Codelab 稍后会对此进行讨论。
使用以下代码更新 auth_gate.dart
文件:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
headerBuilder 参数需要一个 HeaderBuilder 类型的函数,该函数在 FlutterFire 界面软件包中定义。
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
因为它是一个回调,所以它会公开您可以使用的值(例如 BuildContext
和 BoxConstraints
),并要求您返回一个 widget。返回的任何微件都显示在屏幕顶部。在此示例中,新代码会将一张图片添加到屏幕顶部。现在,您的应用应如下所示。
字幕制作工具
登录屏幕公开了三个额外的参数,您可以使用这些参数来自定义屏幕:subtitleBuilder
、footerBuilder
和 sideBuilder
。
subtitleBuilder
略有不同,因为回调参数包含一个操作,其类型为 AuthAction
。AuthAction
是一个枚举,可用于检测用户所在屏幕是否为“登录”屏幕或“register”屏幕。
更新 auth_gate.dart 中的代码以使用 subtitleBuilder。
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider()
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
);
}
return const HomeScreen();
},
);
}
}
重新加载应用,显示的内容应如下所示:
页脚制作工具
footerBuilder 参数与 subtitleBuilder 相同。它不会显示 BoxConstraints
或 shrinkOffset
,因为它适用于文本而非图片。(但您可以根据需要添加任何微件。)
使用此代码向您的登录屏幕添加页脚。
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider()
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
);
}
return const HomeScreen();
},
);
}}
Side Builder
SignInScreen.sidebuilder 参数接受回调,并且这次该回调的参数为 BuildContext
和 double shrinkOffset
。sideBuilder 返回的 widget 将显示在登录表单的左侧,并且仅在宽屏屏幕上显示。实际上,这意味着该微件只会显示在桌面和 Web 应用中。
在内部,FlutterFire 界面使用断点来确定是应该显示标头内容(在移动设备等较高的屏幕上),还是应该显示侧边内容(在宽屏、桌面设备或网页上)。具体而言,如果屏幕宽度超过 800 像素,则会显示侧边构建器内容,而不显示标题内容。如果屏幕宽度小于 800 像素,情况正好相反。
更新 auth_gate.dart 中的代码以添加 sideBuilder 微件。
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
现在,当您展开窗口宽度时,您的应用应如下所示(如果您使用的是 Flutter Web 或 MacOS)。
创建用户
此时,此界面的所有代码均已编写完毕。不过,您需要先创建一个用户,然后才能登录。为此,您可以使用“注册”也可以在 Firebase 控制台中创建用户。
如需使用控制台,请执行以下操作:
- 前往“用户”表格。
- 请点击此处
- 选择“flutterfire-ui-codelab”(如果您使用的是其他名称,则为其他项目)。您会看到以下表格:
- 点击“添加用户”按钮。
- 输入新用户的电子邮件地址和密码。这可能是虚假的电子邮件地址和密码,如下图所示。可以,但“忘记了密码”如果您使用虚假电子邮件地址,“ ”功能将不起作用。
- 点击“添加用户”
现在,您可以返回到 Flutter 应用,并通过登录页面让用户登录。您的应用应如下所示:
6. 个人资料屏幕
FlutterFire 界面还提供了一个 ProfileScreen
widget,它同样只需几行代码即可为您提供很多功能。
添加 ProfileScreen widget
在文本编辑器中找到 home.dart
文件。请使用以下代码对其进行更新:
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => const ProfileScreen(),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
需要注意的新代码是传递给 IconButton.isPressed method.
的回调。当用户按下该 IconButton
时,您的应用会创建一个新的匿名路由并导航到该路由。该路线将显示从 MaterialPageRoute.builder
回调返回的 ProfileScreen
widget。
重新加载应用,并按下右上角(应用栏中)的图标,系统会显示如下页面:
这是 FlutterFire 界面页面提供的标准界面。所有按钮和文本字段都连接到 Firebase Auth,开箱即可使用。例如,您可以在“名称”字段输入名称文本字段,FlutterFire 界面将调用 FirebaseAuth.instance.currentUser?.updateDisplayName
方法,该方法会将该名称保存在 Firebase 中。
正在退出账号
现在,如果您按“退出”按钮,应用不会更改。这会使您退出登录,但您不会导航回 AuthGate 微件。为此,请使用 ProfileScreen.actions 参数。
首先,更新 home.dart 中的代码。
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
现在,当您创建 ProfileScreen
的实例时,也会将操作列表传递给 ProfileScreen.actions
实参。这些操作的类型为 FlutterFireUiAction
。有许多不同的类是 FlutterFireUiAction
的子类型,一般来说,您可以使用这些类来指示应用响应不同的身份验证状态变化。SignedOutAction 会调用一个回调函数,您可以在 Firebase 身份验证状态变为 currentUser 为 null 时向其提供该函数。
添加在 SignedOutAction 触发时调用 Navigator.of(context).pop()
的回调,应用将转到上一页。在此示例应用中,只有一条永久路由,如果没有用户登录,则显示登录页面;如果有用户,则显示首页。由于此操作会在用户退出后显示,因此应用会显示登录页面。
自定义个人资料页面
与“登录页面”类似,个人资料页面也可以自定义。首先,用户进入个人资料页面后,就无法返回到当前页面。为 ProfileScreen widget 指定一个应用栏,可解决此问题。
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(
title: const Text('User Profile'),
),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
ProfileScreen.appBar
参数接受来自 Flutter Material 软件包的 AppBar
widget,因此可以将其视为您已构建并传递给 Scaffold
的任何其他 AppBar
。在本示例中,默认功能是自动添加“back”按钮的保存位置,屏幕现在有一个标题。
将儿童添加到个人资料屏幕
ProfileScreen widget 还有一个名为 child 的可选参数。此参数接受 widget 列表,这些 widget 将垂直放置在已在内部用于构建 ProfileScreen 的 Column widget 内。ProfileScreen 构建方法中的这个 Column widget 会将您传递的子微件放在“Sign out”上方按钮。
更新 home.dart 中的代码,使其在此处显示公司徽标,类似于登录屏幕。
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(
title: const Text('User Profile'),
),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
children: [
const Divider(),
Padding(
padding: const EdgeInsets.all(2),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
),
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
重新加载应用,您将在屏幕上看到以下内容:
7. 多平台 Google Auth 登录
FlutterFire 界面还提供微件和功能,用于向第三方提供商(例如 Google、Twitter、Facebook、Apple 和 GitHub)进行身份验证。
要与 Google 身份验证集成,请安装官方 firebase_ui_oauth_google 插件及其依赖项,它们将处理原生身份验证流程。在终端中,前往 flutter 项目的根目录,然后输入以下命令:
flutter pub add google_sign_in flutter pub add firebase_ui_oauth_google
启用 Google 登录提供方
接下来,在 Firebase 控制台中启用 Google 提供方:
- 转到控制台中的身份验证登录提供商屏幕。
- 点击“添加新的提供方”。
- 选择“Google”。
- 切换标有“启用”的开关,然后按“保存”。
- 如果出现一个模态窗口,其中包含有关如何下载配置文件的信息,请点击“完成”。
- 确认已添加 Google 登录提供方。
添加 Google 登录按钮
启用 Google 登录功能后,向登录页面添加显示风格化 Google 登录按钮所需的 widget。导航至 auth_gate.dart 文件,并将代码更新为以下内容:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart'; // new
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: "YOUR_WEBCLIENT_ID"), // new
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
此处的唯一新代码是向 SignInScreen widget 配置添加 GoogleProvider(clientId: "YOUR_WEBCLIENT_ID")
。
完成上述操作后,重新加载您的应用,您就会看到 Google 登录按钮。
配置登录按钮
如果不进行其他配置,该按钮将不起作用。如果您使用 Flutter Web 进行开发,只需添加此步骤即可实现此功能。其他平台需要执行额外的步骤,我们稍后会讨论这些步骤。
- 前往 Firebase 控制台中的“身份验证提供方”页面。
- 点击相应的 Google 提供方。
- 点击“Web SDK 配置”展开面板。
- 复制“Web 客户端 ID”中的值
- 返回文本编辑器,然后将此 ID 传递给
clientId
具名形参,以更新auth_gate.dart
文件中的GoogleProvider
实例。
GoogleProvider(
clientId: "YOUR_WEBCLIENT_ID"
)
输入 Web 客户端 ID 后,请重新加载您的应用。您按“使用 Google 账号登录”按钮后按钮,您会看到一个新窗口(如果您使用的是网页),该窗口会引导您完成 Google 登录流程。最初,代码如下所示:
配置 iOS
为使它在 iOS 上发挥作用,还需要执行一个额外的配置流程。
- 进入 Firebase 控制台中的“项目设置”屏幕。您会看到一张卡片,其中列出了您的 Firebase 应用,如下所示:
- 点击 iOS。请注意,您的应用名称与我的应用名称不同。我的问题是说“完成”如果您使用
flutter-codelabs/firebase-auth-flutterfire-ui/start
项目来按照此 Codelab 的说明操作,则您的 ID 将是“start”。 - 点击“GoogleServices-Info.plist”按钮下载所需的配置文件。
- 将下载的文件拖放到名为 的目录中。
/ios/Runner
。 - 从项目的根目录运行以下终端命令,以打开 Xcode:
打开 ios/Runner.xcworkspace
- 右键点击 Runner 目录,然后选择“Add Files to Runner”。
- 从文件管理器中选择 GoogleService-Info.plist。
- 返回文本编辑器(不是 Xcode),将下面的 CFBundle网址Types 属性添加到 [my_project]/ios/Runner/Info.plist 文件中。
<!-- Put me in the [my_project]/ios/Runner/Info.plist file -->
<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string>
</array>
</dict>
</array>
<!-- End of the Google Sign-in Section -->
如果您的 Flutter 应用已在 iOS 中运行,您必须将其完全关闭,然后重新运行该应用。否则,请在 iOS 中运行该应用。
8. 恭喜!
您已完成“适用于 Flutter 的 Firebase Auth 界面”Codelab。您可以在“complete”(完成)中找到此 Codelab 的完整代码GitHub 上的目录:Flutter Codelab
所学内容
- 设置 Flutter 应用以使用 Firebase
- 在 Firebase 控制台中设置 Firebase 项目
- FlutterFire CLI
- Firebase CLI
- 使用 Firebase Authentication
- 使用 FlutterFire 界面在 Flutter 应用中轻松处理 Firebase 身份验证
后续步骤
- 详细了解如何在 Flutter 中使用 Firestore 和 Authentication:“了解如何将 Firebase 用于 Flutter”Codelab
- 探索用于构建 Flutter 应用的其他 Firebase 工具:
- Cloud Storage
- Cloud Functions
- Realtime Database
了解详情
- Firebase 网站:firebase.google.com
- Flutter 网站:flutter.dev
- FlutterFire Firebase Flutter 微件:firebase.flutter.dev
- Firebase YouTube 频道
- Flutter YouTube 频道
Sparky 在这里与您一起庆祝!