1. 事前準備
在本程式碼研究室中,您將瞭解如何使用 FlutterFire UI 套件,將 Firebase 驗證新增至 Flutter 應用程式。您將使用這個套件,在 Flutter 應用程式中新增電子郵件和密碼驗證,以及 Google 登入驗證。此外,您也會瞭解如何設定 Firebase 專案,以及如何使用 FlutterFire CLI 在 Flutter 應用程式中初始化 Firebase。
事前準備
本程式碼研究室假設您具備一些 Flutter 經驗。如果沒有,建議先瞭解基本概念。以下連結可能有所幫助:
- 瀏覽 Flutter 小工具架構
- 試試「編寫第一個 Flutter 應用程式 - 第 1 部分」程式碼研究室
您也應具備一些 Firebase 經驗,但如果從未將 Firebase 新增至 Flutter 專案,也沒關係。如果您不熟悉 Firebase 控制台,或是完全不瞭解 Firebase,請先參閱下列連結:
製作內容
本程式碼研究室會引導您使用 Firebase 建立 Flutter 應用程式的驗證程序。這個應用程式會包含登入畫面、「註冊」畫面、密碼復原畫面和使用者設定檔畫面。
課程內容
本程式碼研究室涵蓋下列主題:
- 將 Firebase 新增至 Flutter 應用程式
- Firebase 控制台設定
- 使用 Firebase CLI 將 Firebase 新增至應用程式
- 使用 FlutterFire CLI 在 Dart 中產生 Firebase 設定
- 將 Firebase Authentication 新增至 Flutter 應用程式
- 在控制台中設定 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 專案
- 使用 Google 帳戶登入 Firebase 控制台。
- 按一下按鈕建立新專案,然後輸入專案名稱 (例如
FlutterFire-UI-Codelab
)。
- 按一下「繼續」。
- 如果系統提示,請詳閱並接受 Firebase 條款,然後按一下「繼續」。
- (選用) 在 Firebase 控制台中啟用 AI 輔助功能 (稱為「Gemini in Firebase」)。
- 本程式碼研究室不需要 Google Analytics,因此請關閉 Google Analytics 選項。
- 按一下「建立專案」,等待專案佈建完成,然後按一下「繼續」。
如要進一步瞭解 Firebase 專案,請參閱「瞭解 Firebase 專案」一文。
為 Firebase 驗證啟用電子郵件登入
您要建構的應用程式會使用 Firebase 驗證,讓使用者登入應用程式,並允許新使用者透過 Flutter 應用程式註冊。
您必須使用 Firebase 控制台啟用 Firebase 驗證,啟用後還需要進行特殊設定。
如要允許使用者登入網頁應用程式,請先使用「電子郵件/密碼」登入方式。稍後,您將新增 Google 登入方法。
- 在 Firebase 控制台中,展開左側面板的「Build」選單。
- 依序點選「Authentication」和「Get Started」按鈕,然後點選「Sign-in method」分頁標籤 (或直接前往「Sign-in method」分頁標籤)。
- 在「Sign-in providers」清單中點選「Email/Password」,將「Enable」切換到開啟位置,然後點選「Save」。
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 的方法有很多種,前往 firebase.google.com/docs/cli,查看作業系統的所有可用選項。
安裝 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
- 選取要使用的平台。本程式碼研究室提供步驟,說明如何為網頁、iOS 和 Android 版 Flutter 設定 Firebase Authentication,但您可以設定 Firebase 專案,使用所有選項。
- 這張螢幕截圖顯示程序結束時的輸出內容。如果您熟悉 Firebase,會發現您不必在主控台中建立平台應用程式 (例如 Android 應用程式),FlutterFire CLI 會為您完成這項作業。
完成後,請在文字編輯器中查看 Flutter 應用程式。FlutterFire CLI 已修改名為 firebase_options.dart
的檔案。這個檔案包含名為 FirebaseOptions
的類別,其中含有靜態變數,可保留各平台所需的 Firebase 設定。如果您在執行 flutterfire configure
時選取所有平台,系統會顯示名為 web
、android
、ios
和 macos
的靜態值。
lib/firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
default:
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 設定值。
將 Firebase 套件新增至 Flutter 應用程式
最後一個設定步驟是將相關的 Firebase 套件新增至 Flutter 專案。firebase_options.dart
檔案應該會出現錯誤,因為它依附於尚未新增的 Firebase 套件。在終端機中,確認您位於 Flutter 專案的根目錄 flutter-codelabs/firebase-emulator-suite/start
。然後執行下列三項指令:
flutter pub add firebase_core firebase_auth firebase_ui_auth
目前只需要這些套件。
初始化 Firebase
如要使用新增的套件,請更新 main.dart
檔案中 main
函式的程式碼。DefaultFirebaseOptions.currentPlatform,
lib/main.dart
import 'package:firebase_core/firebase_core.dart'; // Add this import
import 'package:flutter/material.dart';
import 'app.dart';
import 'firebase_options.dart'; // And this import
// TODO(codelab user): Get API key
const clientId = 'YOUR_CLIENT_ID';
void main() async {
// Add from here...
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
// To here.
runApp(const MyApp(clientId: clientId));
}
這段程式碼會執行兩項作業。
WidgetsFlutterBinding.ensureInitialized()
會告知 Flutter,在 Flutter 架構完全啟動前,不要開始執行應用程式小工具程式碼。Firebase 使用原生平台管道,因此需要執行架構。Firebase.initializeApp
會在 Flutter 應用程式和 Firebase 專案之間建立連線。DefaultFirebaseOptions.currentPlatform
是從產生的firebase_options.dart
檔案匯入。這個靜態值會偵測您執行的平台,並傳遞對應的 Firebase 金鑰。
4. 新增初始 Firebase UI 驗證頁面
Firebase 驗證 UI 提供的小工具代表應用程式中的整個畫面。這些畫面會處理應用程式中的不同驗證流程,例如登入、註冊、忘記密碼、使用者設定檔等。如要開始使用,請在應用程式中新增登陸頁面,做為主要應用程式的驗證防護機制。
Material 或 Cupertino 應用程式
FlutterFire UI 要求應用程式包裝在 MaterialApp
或 CupertinoApp
中。根據您的選擇,使用者介面會自動反映 Material 或 Cupertino 小工具的差異。在本程式碼研究室中,請使用 MaterialApp
,這已在 app.dart
中新增至應用程式。
lib/app.dart
import 'package:flutter/material.dart';
import 'auth_gate.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: AuthGate(clientId: clientId),
);
}
}
檢查驗證狀態
顯示登入畫面之前,您需要判斷使用者是否已通過驗證。最常見的檢查方式是使用 Firebase Auth 外掛程式監聽 FirebaseAuth
的 authStateChanges
。
在上述程式碼範例中,MaterialApp
會在 build
方法中建構 AuthGate
小工具。(這是自訂小工具,並非 FlutterFire UI 提供)。
該小工具必須更新,才能納入 authStateChanges
串流。
authStateChanges
API 會傳回 Stream
,其中包含目前使用者 (如果已登入),或 null (如果未登入)。如要在應用程式中訂閱這個狀態,可以使用 Flutter 的 StreamBuilder 小工具,並將串流傳遞至該小工具。
StreamBuilder
是一個小工具,會根據您傳遞的 Stream 最新資料快照建構自身。當 Stream
發出新的快照時,系統會自動重建。
更新 auth_gate.dart
中的程式碼。
lib/auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider; // Add this import
import 'package:firebase_ui_auth/firebase_ui_auth.dart'; // And this import
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>( // Modify from here...
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(providers: []);
}
return const HomeScreen();
},
); // To here.
}
}
- 正在傳遞
FirebaseAuth.instance.authStateChanged
,上述串流會傳回 FirebaseUser
物件 (如果使用者已通過驗證),否則會傳回null
。StreamBuilder.stream
- 接著,程式碼會使用
snapshot.hasData
檢查串流中的值是否包含User
物件。 - 如果沒有,系統會傳回
SignInScreen
小工具。目前這個畫面不會執行任何動作,我們會在下一個步驟更新。 - 否則會傳回
HomeScreen
,這是應用程式的主要部分,只有通過驗證的使用者才能存取。
SignInScreen
是 FlutterFire UI 套件提供的小工具。這就是本程式碼研究室下一個步驟的重點。此時執行應用程式時,您應該會看到空白的登入畫面。
5. 登入畫面
FlutterFire UI 提供的 SignInScreen
小工具新增了下列功能:
- 允許使用者登入
- 如果使用者忘記密碼,可以輕觸「忘記密碼?」並前往表單重設密碼
- 如果使用者尚未註冊,可以輕觸「註冊」,系統會將他們帶往另一個表單,讓他們註冊。
同樣地,這只需要幾行程式碼。回想 AuthGate
小工具中的程式碼:
lib/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, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(providers: [EmailAuthProvider()]); // Modify this line
}
return const HomeScreen();
},
);
}
}
如要取得上述所有功能,唯一需要的程式碼就是 SignInScreen
小工具及其 providers
引數。現在應該會看到登入畫面,當中包含「電子郵件」和「密碼」文字輸入欄位,以及「登入」按鈕。
雖然功能正常,但缺少樣式。這個小工具會公開參數,方便您自訂登入畫面的外觀。例如,您可能想新增公司標誌。
自訂登入畫面
headerBuilder
您可以使用 SignInScreen.headerBuilder
引數,在登入表單上方新增任何想要的小工具。這個小工具只會顯示在窄螢幕上,例如行動裝置。在寬螢幕上,您可以使用 SignInScreen.sideBuilder
,本程式碼研究室稍後會說明這項功能。
使用下列程式碼更新 lib/auth_gate.dart
檔案:
lib/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, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen( // Modify from here...
providers: [EmailAuthProvider()],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
); // To here.
}
return const HomeScreen();
},
);
}
}```
The headerBuilder argument requires a function of the type HeaderBuilder, which
is defined in the FlutterFire UI package.
```dart
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
由於這是回呼,因此會公開可使用的值,例如 BuildContext
和 BoxConstraints
,並要求您傳回小工具。系統會在畫面頂端顯示你返回的小工具。在本例中,新程式碼會在畫面頂端新增圖片。您的應用程式現在應如下所示。
副標題建立工具
登入畫面會公開三個額外參數,方便您自訂畫面:subtitleBuilder
、footerBuilder
和 sideBuilder
。
subtitleBuilder
的不同之處在於回呼引數包含動作,屬於 AuthAction
型別。AuthAction
是一種列舉,可用於偵測使用者目前所在的畫面是「登入」畫面還是「註冊」畫面。
更新 auth_gate.dart 中的程式碼,使用 subtitleBuilder
。
lib/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, required this.clientId});
final String clientId;
@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'),
),
);
},
subtitleBuilder: (context, action) { // Add from here...
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!'),
);
}, // To here.
);
}
return const HomeScreen();
},
);
}
}
頁尾建構工具
footerBuilder 引數與 subtitleBuilder 相同。這個函式不公開 BoxConstraints
或 shrinkOffset
,因為它適用於文字而非圖片。當然,你可以新增任何想要的小工具。
使用這段程式碼,在登入畫面中新增頁尾。
lib/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, required this.clientId});
final String clientId;
@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'),
),
);
},
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) { // Add from here...
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),
),
);
}, // To here.
);
}
return const HomeScreen();
},
);
}
}
Side Builder
SignInScreen.sidebuilder 引數會接受回呼,而這次回呼的引數是 BuildContext
和 double shrinkOffset
。sideBuilder
傳回的小工具會顯示在登入表單左側,且僅適用於寬螢幕。也就是說,小工具只會顯示在電腦和網頁應用程式上。
在內部,FlutterFire UI 會使用中斷點,判斷是否應顯示標題內容 (在手機等高螢幕上),或顯示側邊內容 (在電腦或網頁等寬螢幕上)。具體來說,如果螢幕寬度超過 800 像素,系統會顯示側邊建立工具內容,但不會顯示頁首內容。如果螢幕寬度小於 800 像素,則情況相反。
更新 auth_gate.dart 中的程式碼,加入 sideBuilder
小工具。
lib/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, required this.clientId});
final String clientId;
@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'),
),
);
},
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 網頁或 macOS)。
新增使用者
此時,這個畫面的所有程式碼都已完成。不過,您必須先建立使用者,才能登入。您可以在「註冊」畫面中執行這項操作,也可以在 Firebase 控制台中建立使用者。
如何使用控制台:
- 前往 Firebase 控制台中的「使用者」表格。選取「flutterfire-ui-codelab」,或您使用的其他專案名稱。系統會顯示這個表格:
- 按一下「新增使用者」按鈕。
- 輸入新使用者的電子郵件地址和密碼。這可以是假的電子郵件地址和密碼,如下圖所示。這樣做雖然可行,但如果使用假的電子郵件地址,「忘記密碼」功能就無法運作。
- 按一下「新增使用者」
現在您可以返回 Flutter 應用程式,並使用登入頁面登入使用者。應用程式應如下所示:
6. 個人資料畫面
FlutterFire UI 也提供 ProfileScreen
小工具,讓您只需幾行程式碼,就能使用許多功能。
新增「ProfileScreen
」小工具
在文字編輯器中前往 home.dart
檔案。使用下列程式碼更新:
lib/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: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
新的附註程式碼是傳遞至 IconButton.isPressed
方法的回呼。按下 IconButton
時,應用程式會建立新的匿名路徑並前往該路徑。該路徑會顯示 ProfileScreen
小工具,這是從 MaterialPageRoute.builder
回呼傳回的內容。
重新載入應用程式,然後推送右上方的圖示 (位於應用程式列中),畫面會顯示類似下方的頁面:
這是 FlutterFire UI 頁面提供的標準 UI。所有按鈕和文字欄位都已連結至 Firebase 驗證,可直接使用。舉例來說,您可以在「Name」文字欄位中輸入名稱,FlutterFire UI 會呼叫 FirebaseAuth.instance.currentUser?.updateDisplayName
方法,將該名稱儲存至 Firebase。
登出
目前按下「登出」按鈕後,應用程式不會有任何變更。系統會登出你的帳戶,但不會將你導向回 AuthGate 小工具。如要實作這項功能,請使用 ProfileScreen.actions 參數。
首先,請更新 home.dart 中的程式碼。
lib/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: [
SizedBox(width: 250, child: Image.asset('assets/dash.png')),
Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
const SignOutButton(),
],
),
),
);
}
}
現在,當您建立 ProfileScreen
的執行個體時,也會將動作清單傳遞至 ProfileScreen.actions
引數。這些動作屬於 FlutterFireUiAction
類型。FlutterFireUiAction
有許多不同的子型別,一般來說,您會使用這些子型別,告知應用程式對不同的驗證狀態變更做出反應。當 Firebase 驗證狀態變更為 currentUser 為空值時,SignedOutAction 會呼叫您提供的回呼函式。
新增在 SignedOutAction
觸發時呼叫 Navigator.of(context).pop()
的回呼,應用程式就會導覽至上一頁。在這個範例應用程式中,只有一個永久路徑,如果沒有使用者登入,就會顯示「登入」畫面,如果有使用者登入,就會顯示首頁。由於使用者登出時會發生這種情況,應用程式會顯示「登入」畫面。
自訂個人資料頁面
與「登入」畫面類似,個人資料頁面可自訂。首先,使用者進入個人資料頁面後,目前網頁無法返回首頁。如要修正這個問題,請為 ProfileScreen 小工具提供 AppBar。
lib/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: [
SizedBox(width: 250, child: Image.asset('assets/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
小工具,會將您傳遞的子項放在「登出」按鈕上方。
更新 home.dart
中的程式碼,在此處顯示公司標誌,類似於「登入」畫面。
lib/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: [
SizedBox(width: 250, child: Image.asset('assets/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 firebase_ui_oauth_google
啟用 Google 登入提供者
接著,在 Firebase 控制台中啟用 Google 供應商:
- 前往控制台的「驗證登入供應商」畫面。
- 按一下「新增供應商」。
- 選取「Google」。
- 切換標示為「啟用」的按鈕,然後按下「儲存」。
- 如果系統顯示對話方塊,說明如何下載設定檔,請按一下「完成」。
- 確認已新增 Google 登入供應商。
新增 Google 登入按鈕
啟用 Google 登入功能後,請新增小工具,在登入畫面上顯示樣式化的 Google 登入按鈕。前往 auth_gate.dart
檔案,並將程式碼更新為下列內容:
lib/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'; // Add this import
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key, required this.clientId});
final String clientId;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: clientId), // Add this line
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/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
專案完成本程式碼研究室,螢幕截圖中顯示「complete」的位置會顯示「start」。 - 按一下
GoogleServices-Info.plist
按鈕,下載所需的設定檔。 - 將下載的檔案拖曳至 Flutter 專案中名為
/ios/Runner
的目錄。 - 在專案根目錄中執行下列終端機指令,開啟 Xcode:
open ios/Runner.xcworkspace
- 在「Runner」目錄上按一下滑鼠右鍵,然後選取「Add Files to "Runner"」(將檔案新增至「Runner」)。
- 在檔案管理員中選取
GoogleService-Info.plist
。 - 返回文字編輯器 (不是 Xcode),將下列
CFBundleURLTypes
屬性新增至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', );
- 將該值貼到
lib/main.dart
檔案的clientId
變數中。
lib/main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'app.dart';
import 'firebase_options.dart';
const clientId = 'YOUR_CLIENT_ID'; // Replace this value with your Client ID.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const MyApp(clientId: clientId));
}
如果 Flutter 應用程式已在 iOS 中執行,您必須完全關閉應用程式,然後重新執行。否則,請在 iOS 中執行應用程式。
8. 恭喜!
您已完成 Flutter 適用的 Firebase 驗證 UI 程式碼研究室。您可以在 GitHub 上的 firebase-auth-flutterfire-ui/complete
目錄中找到本程式碼研究室的完整程式碼。
涵蓋內容
- 設定 Flutter 應用程式以使用 Firebase
- 在 Firebase 控制台中設定 Firebase 專案
- FlutterFire CLI
- Firebase CLI
- 使用 Firebase 驗證
- 使用 FlutterFire UI 在 Flutter 應用程式中處理 Firebase 驗證
後續步驟
- 進一步瞭解如何在 Flutter 中使用 Firestore 和驗證:認識 Firebase for Flutter Codelab
- 探索其他 Firebase 工具,建構 Flutter 應用程式:
瞭解詳情
- Firebase 網站:firebase.google.com
- Flutter 網站:flutter.dev
- FlutterFire Firebase Flutter 小工具:firebase.flutter.dev
- Firebase YouTube 頻道
- Flutter YouTube 頻道
Sparky 很高興能與你一同慶祝!