1. 事前準備
在本程式碼研究室中,您將瞭解如何使用 FlutterFire UI 套件將 Firebase 驗證新增至 Flutter 應用程式。透過這個套件,您會將電子郵件/密碼驗證和 Google 登入驗證新增至 Flutter 應用程式。您會學到如何設定 Firebase 專案,以及使用 FlutterFire CLI 在 Flutter 應用程式中初始化 Firebase。
事前準備
本程式碼研究室假設您具備一些 Flutter 相關經驗。如果您還不熟悉,建議您先瞭解基本概念。以下連結相當實用:
- 觀看 Flutter Widget 架構導覽
- 試試「編寫第一個 Flutter 應用程式,第 1 部分」程式碼研究室
您也應具備一些 Firebase 使用經驗,但如果您從未將 Firebase 新增至 Flutter 專案,也沒關係。如果您對 Firebase 控制台不熟悉,或是完全不熟悉 Firebase,請先查看下列連結:
您要建立的內容
本程式碼研究室會引導您使用 Firebase 驗證功能,為 Flutter 應用程式建立驗證流程。應用程式將包含登入畫面、「註冊」畫面、密碼復原畫面和使用者個人資料畫面。
課程內容
本程式碼研究室涵蓋以下內容:
- 將 Firebase 新增至 Flutter 應用程式
- Firebase 控制台設定
- 使用 Firebase CLI 將 Firebase 新增至應用程式
- 使用 FlutterFire CLI 在 Dart 中產生 Firebase 設定
- 在 Flutter 應用程式中新增 Firebase 驗證機制
- 在控制台中設定 Firebase 驗證
- 使用
firebase_ui_auth
套件新增電子郵件和密碼登入功能 - 正在透過
firebase_ui_auth
套件新增使用者註冊 - 新增「忘記密碼?」頁面
- 正在新增「
firebase_ui_auth
」的 Google 登入功能 - 設定應用程式以支援多個登入服務供應器。
- 使用
firebase_ui_auth
套件將使用者個人資料畫面新增至應用程式
本程式碼研究室將著重於使用 firebase_ui_auth
套件新增完善的驗證系統。如您所見,您可以使用上述所有功能,在整個應用程式中約使用 100 行程式碼實作。
事前準備
- 熟悉 Flutter 和已安裝的 SDK
- 文字編輯器 (Flutter 支援 JetBrains IDE、Android Studio 和 VS Code)
- Google Chrome 瀏覽器或其他偏好的 Flutter 開發目標。(本程式碼研究室中的部分終端機指令會假設您在 Chrome 上執行應用程式)
2. 建立及設定 Firebase 專案
您需要先在 Firebase 的網路控制台中建立 Firebase 專案。
建立 Firebase 專案
- 登入 Firebase。
- 在 Firebase 控制台中,按一下「新增專案」 (或「建立專案」),然後輸入 Firebase 專案名稱 (例如「FlutterFire-UI-Codelab」)。
- 點選專案建立選項。當系統顯示提示時,請接受 Firebase 條款。略過設定 Google Analytics,因為這個應用程式不會使用 Analytics。
如要進一步瞭解 Firebase 專案,請參閱「瞭解 Firebase 專案」一文。
為 Firebase 驗證啟用電子郵件登入功能
您建構的應用程式採用 Firebase 驗證,可讓使用者登入您的應用程式。此外,您所建立的應用程式也會允許新使用者從 Flutter 應用程式註冊。
Firebase 驗證功能必須透過 Firebase 控制台啟用,且啟用後需要進行特殊設定。
如要允許使用者登入網頁應用程式,您必須先使用電子郵件/密碼登入方式。稍後,您將新增 Google 登入方法。
- 在 Firebase 控制台中,展開左側面板中的「Build」選單。
- 依序點選「驗證」和「開始使用」按鈕,再點選「登入方式」分頁標籤 (或按這裡直接前往「登入方式」分頁)。
- 按一下「登入供應商」清單中的「電子郵件/密碼」,將「啟用」的切換按鈕設為開啟,然後按一下「儲存」。
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
目錄中,當中包含一系列程式碼研究室的程式碼。本程式碼研究室的程式碼位於 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 的目錄中查看交叉參照。
如果您想按照程式碼研究室的說明進行操作,並自行新增程式碼,請先從 flutter-codelabs/firebase-auth-flutterfire-ui/start
的 Flutter 應用程式開始,然後在程式碼研究室中為該專案新增程式碼。開啟該目錄或將其匯入至您偏好的 IDE。
安裝 Firebase CLI
Firebase CLI 提供可用來管理 Firebase 專案的工具。FlutterFire 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 是一項以 Firebase CLI 為基礎建構的工具,可協助您簡化 Flutter 應用程式支援平台上的 Firebase 安裝程序。
首先,請安裝 CLI:
dart pub global activate flutterfire_cli
確認已安裝 CLI。執行下列指令,並確保 CLI 輸出說明選單。
flutterfire -—help
將 Firebase 專案新增至 Flutter 應用程式
設定 FlutterFire
您可以使用 FlutterFire 產生所需的 Dart 程式碼,以便在 Flutter 應用程式中使用 Firebase。
flutterfire configure
執行這個指令時,系統會提示您選取要使用的 Firebase 專案,以及想要設定的平台。
以下螢幕截圖顯示您需要回答的提示。
- 選取要使用的專案。在本例中,請使用
flutterfire-ui-codelab
- 選取要使用的平台。在本程式碼研究室中,您需要為 Flutter 設定 Firebase 驗證,針對網頁、iOS 和 Android 進行設定。不過,您可以為 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.firebasestorage.app',
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.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
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.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
}
Firebase 會使用「應用程式」一詞,指稱 Firebase 專案中特定平台的特定版本。例如,名為 FlutterFire-ui-codelab 的 Firebase 專案有多個應用程式:一個適用於 Android、一個適用於 iOS,另一個用於 MacOS,另一個用於網頁。
DefaultFirebaseOptions.currentPlatform
方法會使用 Flutter 公開的 TargetPlatform
列舉來偵測執行應用程式的平台,然後傳回正確 Firebase 應用程式所需的 Firebase 設定值。
在 Flutter 應用程式中新增 Firebase 套件
最後一個設定步驟是將相關 Firebase 套件新增至 Flutter 專案。firebase_options.dart
檔案應會出現錯誤,因為它依賴尚未新增的 Firebase 套件。在終端機中,確認您位於 flutter-codelabs/firebase-emulator-suite/start
的 Flutter 專案根目錄。接著,請執行下列三個指令:
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 架構完全啟動前,開始執行應用程式小工具程式碼。Firebase 使用需要執行架構的原生平台管道。Firebase.initializeApp
會設定 Flutter 應用程式和 Firebase 專案之間的連結。DefaultFirebaseOptions.currentPlatform
是從產生的firebase_options.dart
檔案匯入。這個靜態值會偵測您所使用的平台,並傳入對應的 Firebase 金鑰。
4. 新增初始 Firebase UI 驗證頁面
Firebase 驗證機制的 Firebase UI 提供代表應用程式整個畫面的小工具。這些畫面會處理應用程式中的不同驗證流程,例如登入、註冊、忘記密碼、使用者個人資料等。如要開始使用,請在應用程式中加入到達網頁,做為主要應用程式驗證防護機制。
Material Design 或 Cupertino 應用程式
FlutterFire UI 要求應用程式必須包裝在 MaterialApp 或 CupertinoApp 中。視您的選擇而定,UI 會自動反映 Material 或 Cupertino 小工具的差異。在本程式碼研究室中,請使用已新增至 app.dart
應用程式的 MaterialApp
。
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 Auth 外掛程式監聽 FirebaseAuth 的 authStateChanges。
在上述程式碼範例中,MaterialApp
會在建構方法中建構 AuthGate
小工具。(這是自訂小工具,並非由 FlutterFire UI 提供)。
該小工具需要更新,才能加入 authStateChanges
資料流。
authStateChanges
API 會傳回含有目前使用者 (若登入) 的 Stream
,如果沒有目前使用者,則會傳回空值。如要在應用程式中訂閱此狀態,可以使用 Flutter 的 StreamBuilder 小工具,並將串流傳給它。
StreamBuilder
是一種小工具,可根據您傳遞的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
小工具。目前,這個畫面不會執行任何操作。我們會在下一個步驟中更新這項資訊。 - 否則,則會傳回
HomeScreen
,這是應用程式的主要部分,只有經過驗證的使用者可以存取。
SignInScreen
是來自 FlutterFire UI 套件的小工具。這會是本程式碼研究室下一個步驟的重點。這時當您執行應用程式時,應會看到空白的登入畫面。
5. 登入畫面
FlutterFire UI 提供的 SignInScreen
小工具會新增下列功能:
- 允許使用者登入
- 如果使用者忘記密碼,可以輕觸「忘記密碼?」,進入重設密碼的表單。
- 如果尚未註冊,使用者可以輕觸「報名」,這樣使用者就能進入其他表單進行註冊。
同樣地,這只需要幾行程式碼。回想 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
小工具及其 providers
引數,是取得上述所有功能所需的唯一程式碼。您現在應該會看到登入畫面,其中包含「電子郵件」和「密碼」文字輸入欄位,以及「登入」按鈕。
雖然可正常運作,但缺乏樣式。小工具會公開參數,讓您自訂登入畫面的外觀。舉例來說,您可以新增公司的標誌。
自訂登入畫面
headerBuilder
透過 SignInScreen.headerBuilder
引數,您可以在登入表單上方新增任何想要的小工具。這個小工具只會顯示在行動裝置等窄螢幕上。在寬螢幕上,您可以使用 SignInScreen.sideBuilder
,這會在本程式碼研究室的後續部分討論。
使用下列程式碼更新 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 UI 套件中定義。
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
由於這是回呼,因此會公開可用的值,例如 BuildContext
和 BoxConstraints
,並要求您傳回小工具。您返回的任何小工具都會顯示在畫面頂端。在本例中,新程式碼會在畫面頂端加入圖片。您的應用程式現在應如下所示。
字幕建立工具
登入畫面會提供三個額外參數,讓您自訂畫面:subtitleBuilder
、footerBuilder
和 sideBuilder
。
subtitleBuilder
略有不同,因為回呼引數包含類型為 AuthAction
的動作。AuthAction
是列舉,可用來偵測使用者目前所在的畫面是「登入」畫面或「註冊」畫面。
更新 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();
},
);
}}
側邊建構工具
SignInScreen.sidebuilder 引數接受回呼,這次回呼的引數為 BuildContext
和 double shrinkOffset
。sideBuilder 傳回的小工具會顯示在登入表單左側,且僅限於寬螢幕。也就是說,小工具只會顯示在電腦版和網頁應用程式上。
FlutterFire UI 會在內部使用中斷點,判斷是否應在大螢幕 (例如行動裝置) 上顯示標頭內容,或是側邊內容 (在寬螢幕、電腦或網頁上) 是否應顯示。具體來說,如果螢幕寬度超過 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 控制台中建立使用者。
如何使用控制台:
- 前往 Firebase 控制台的「使用者」表格。
- 請按這裡閱讀相關說明文章
- 選取「flutterfire-ui-codelab」(或您使用的其他專案名稱)。就會看到這個表格:
- 按一下「新增使用者」按鈕。
- 輸入新使用者的電子郵件地址和密碼。這可以是假的電子郵件地址和密碼,如我在下方圖片中所示。這個方法雖然有效,但若您使用假的電子郵件地址,「忘記密碼」功能將無法運作。
- 按一下「新增使用者」
您現在可以返回 Flutter 應用程式,並透過登入頁面登入使用者。應用程式應如下所示:
6. 設定檔畫面
FlutterFire UI 也提供 ProfileScreen
小工具,該工具同樣以幾行程式碼提供許多功能。
新增 ProfileScreen 小工具
前往文字編輯器中的 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
時,應用程式會建立新的匿名路徑並前往該路徑。該路徑會顯示 ProfileScreen
小工具,該小工具會從 MaterialPageRoute.builder
回呼傳回。
重新載入應用程式,然後將右上角的圖示推送到應用程式列中,系統隨即會顯示如下所示的頁面:
這是 FlutterFire UI 頁面提供的標準 UI。所有按鈕和文字欄位都已連結至 Firebase 驗證,並可立即使用。舉例來說,您可以在「名稱」文字欄位中輸入名稱,FlutterFire UI 會呼叫 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 為空值時,系統會呼叫該函式。
藉由新增會在 SignedOutAction 觸發時呼叫 Navigator.of(context).pop()
的回呼,應用程式會前往上一頁。在這個範例應用程式中,只有一個永久路徑,如果沒有使用者登入,就會顯示登入頁面,如果有使用者登入,則會顯示首頁。因為當使用者登出時,應用程式會顯示「登入」頁面。
自訂個人資料頁面
與「Sign in」頁面類似,您也可以自訂個人資料頁面。首先,使用者在個人資料頁面時,目前的網頁無法導回首頁。如要修正這個問題,請將 ProfileScreen 小工具設為 AppBar。
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
小工具,因此系統會將其視為您建構並傳遞至 Scaffold
的任何其他 AppBar
。在本例中,系統會保留自動新增「返回」按鈕的預設功能,且畫面現在已包含標題。
在「設定檔」畫面中新增兒童
ProfileScreen 小工具也有名為 children 的選用引數。這個引數會接受小工具清單,這些小工具會垂直放置在已用於內部建構 ProfileScreen 的 Column 小工具中。ProfileScreen 建構方法中的這個「Column」小工具會將您傳遞的子項置於「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 驗證登入
FlutterFire UI 也提供驗證第三方供應商的小工具和功能,例如 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 登入按鈕。請前往 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();
},
);
}
}
這裡唯一的新程式碼,就是將 GoogleProvider(clientId: "YOUR_WEBCLIENT_ID")
新增至 SignInScreen 小工具設定。
新增這項資訊後,請重新載入應用程式,您就會看到 Google 登入按鈕。
設定登入按鈕
這個按鈕需要額外設定才能運作。如果您使用 Flutter Web 進行開發,這就是唯一需要新增的步驟,即可讓這項功能運作。其他平台需要額外的步驟,我們稍後會說明。
- 前往 Firebase 控制台的「驗證供應商」頁面。
- 按一下 Google 供應商。
- 按一下「Web SDK 設定」展開面板。
- 複製「網路用戶端 ID」中的值
- 返回文字編輯器,並將這個 ID 傳遞至名為
clientId
的參數,更新檔案auth_gate.dart
中的GoogleProvider
例項。
GoogleProvider(
clientId: "YOUR_WEBCLIENT_ID"
)
輸入網頁用戶端 ID 後,請重新載入應用程式。按下「使用 Google 帳戶登入」按鈕後,系統會顯示新視窗 (如果您使用網頁),引導您完成 Google 登入流程。一開始會如下所示:
設定 iOS
為了讓這項功能在 iOS 上運作,您必須進行額外的設定程序。
- 前往 Firebase 主控台的「專案設定」畫面。系統會顯示資訊卡,列出您的 Firebase 應用程式,如下所示:
- 按一下 iOS。請注意,您的應用程式名稱會與我的不同。如果您使用
flutter-codelabs/firebase-auth-flutterfire-ui/start
專案搭配本程式碼研究室,在 mine 顯示「complete」(完成) 部分。 - 按一下「GoogleServices-Info.plist」按鈕,下載所需的設定檔。
- 將下載的檔案拖曳至 目錄。
/ios/Runner
。 - 在專案根目錄中執行下列終端機指令,即可開啟 Xcode:
open ios/Runner.xcworkspace
- 在「Runner」目錄上按一下滑鼠右鍵,然後選取「Add Files to Runner」。
- 從檔案管理員選取「GoogleService-Info.plist」。
- 返回文字編輯器 (非 Xcode),將下列 CFBundleURLTypes 屬性加入 [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 -->
- 您必須將在網頁設定中新增的
GoogleProvider.clientId
替換為與 Firebase iOS 用戶端 ID 相關聯的用戶端 ID。首先,您可以在firebase_options.dart
檔案中找到這個 ID,做為iOS
常數的一部分。複製傳遞至iOSClientId
的值。
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'YOUR API KEY',
appId: 'YOUR APP ID',
messagingSenderId: '',
projectId: 'PROJECT_ID',
storageBucket: 'PROJECT_ID.firebasestorage.app',
iosClientId: 'IOS CLIENT ID', // Find your iOS client Id here.
iosBundleId: 'com.example.BUNDLE',
);
- 將這個值貼到
AuthGate
小工具的GoogleProvider.clientId
引數中。
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';
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 IOS CLIENT ID"), // replace String
],
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 應用程式已在 iOS 中執行,則必須先完全關閉應用程式,然後重新執行應用程式。在其他情況下,請在 iOS 執行應用程式。
8. 恭喜!
您已完成 Flutter 程式碼研究室適用的 Firebase 驗證 UI。您可以在 GitHub 的「complete」目錄中找到本程式碼研究室的完成版程式碼:Flutter 程式碼研究室
涵蓋內容
- 設定 Flutter 應用程式來使用 Firebase
- 在 Firebase 控制台中設定 Firebase 專案
- FlutterFire CLI
- Firebase CLI
- 使用 Firebase 驗證
- 使用 FlutterFire UI 在 Flutter 應用程式中輕鬆處理 Firebase 驗證
後續步驟
- 進一步瞭解如何在 Flutter 中使用 Firestore 和 Authentication:瞭解 Flutter 適用的 Firebase Codelab
- 探索其他 Firebase 工具,用於建構 Flutter 應用程式:
- Cloud Storage
- Cloud Functions
- 即時資料庫
瞭解詳情
- Firebase 網站:firebase.google.com
- Flutter 網站:flutter.dev
- FlutterFire Firebase Flutter 小工具:firebase.flutter.dev
- Firebase YouTube 頻道
- Flutter YouTube 頻道
Sparky 要和你一起慶祝!