1. 事前準備
在本程式碼研究室中,您將瞭解如何使用 FlutterFire UI 套件,將 Firebase 驗證功能新增至 Flutter 應用程式。透過這個套件,您將在 Flutter 應用程式中加入電子郵件和密碼驗證和 Google 登入驗證。您也會瞭解如何設定 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
套件新增使用者註冊 - 新增「忘記密碼?」頁面
- 新增 Google 登入功能,使用
firebase_ui_auth
- 設定應用程式以支援多個登入服務供應器。
- 使用
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 控制台中,按一下「Add Project」 (或「Create a project」),然後輸入 Firebase 專案名稱 (例如「FlutterFire-UI-Codelab」)。
- 點選專案建立選項。當系統顯示提示時,請接受 Firebase 條款。略過設定 Google Analytics,因為這個應用程式不會用到 Analytics。
如要進一步瞭解 Firebase 專案,請參閱「瞭解 Firebase 專案」一文。
為 Firebase 驗證啟用電子郵件登入功能
您正在建構的應用程式會使用 Firebase 驗證,讓使用者登入應用程式,也能讓新使用者透過 Flutter 應用程式註冊。
您必須透過 Firebase 控制台啟用 Firebase 驗證,並在啟用後進行特殊設定。
為了讓使用者登入網頁應用程式,您必須先使用「電子郵件/密碼」登入方式。稍後您將新增 Google 登入方法。
- 在 Firebase 控制台中,展開左側面板中的「Build」選單。
- 依序點選「Authentication」和「Get Started」按鈕,然後點選「Sign-in method」分頁標籤 (或直接前往「Sign-in method」分頁標籤)。
- 在「Sign-in providers」清單中點選「電子郵件/密碼」,將「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 專案的工具。這個 CLI 是 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
- 選取要使用的平台。本程式碼研究室中提供設定 Flutter 適用於網頁、iOS 和 Android 的 Firebase 驗證機制的步驟,但您可以設定 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-codelabs/firebase-emulator-suite/start
的 Flutter 專案根目錄中。接著,請執行下列三個指令:
flutter pub add firebase_core firebase_auth firebase_ui_auth
目前只需要這些套件。
初始化 Firebase
為了使用新增的套件,DefaultFirebaseOptions.currentPlatform,
會更新 main.dart
檔案中 main
函式的程式碼。
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 驗證工具提供小工具,可代表應用程式中的整個畫面。這些畫面會處理應用程式中的不同驗證流程,例如登入、註冊、忘記密碼、使用者個人資料等。首先,請在應用程式中新增登陸頁面,做為主要應用程式的驗證守衛。
Material 或 Cupertino 應用程式
FlutterFire UI 要求應用程式必須包裝在 MaterialApp
或 CupertinoApp
中。根據您的選擇,UI 會自動反映 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 驗證外掛程式,監聽 FirebaseAuth
的 authStateChanges
。
在上述程式碼範例中,MaterialApp
會在其 build
方法中建構 AuthGate
小工具。(這是自訂小工具,並非由 FlutterFire UI 提供)。
您需要更新該小工具,才能納入 authStateChanges
串流。
authStateChanges
API 會傳回 Stream
,其中包含目前使用者 (如果使用者已登入),如果使用者未登入,則傳回空值。如要在應用程式中訂閱此狀態,您可以使用 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.
}
}
StreamBuilder.stream
會傳遞FirebaseAuth.instance.authStateChanged
,也就是上述串流,如果使用者已通過驗證,就會傳回 FirebaseUser
物件,否則會傳回null
。- 接下來,程式碼會使用
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();
},
);
}
}
側邊建構工具
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
的子類別有很多,您通常會使用這些類別,讓應用程式對不同的驗證狀態變更做出反應。SignedOutAction 會呼叫回呼函式,您在 Firebase 驗證狀態變更為 currentUser 為空值時,會將此函式提供給該函式。
只要在 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。這個引數會接受小工具清單,這些小工具會垂直放置在 Column
小工具中,而該小工具已用於內部建構 ProfileScreen
。ProfileScreen
建構方法中的這個 Column
小工具會將您傳遞的子項放在「Sign out」按鈕上方。
更新 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」。
- 切換「Enable」(啟用) 按鈕,然後按下「Save」(儲存)。
- 如果畫面上顯示有關下載設定檔的資訊,請按一下「完成」。
- 確認已新增 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 設定」展開面板。
- 複製「Web client 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 和 Authentication:瞭解 Flutter 適用的 Firebase Codelab
- 探索其他 Firebase 工具,用於建構 Flutter 應用程式:
瞭解詳情
- Firebase 網站:firebase.google.com
- Flutter 網站:flutter.dev
- FlutterFire Firebase Flutter 小工具:firebase.flutter.dev
- Firebase YouTube 頻道
- Flutter YouTube 頻道
Sparky 在此為你獻上祝福!