使用 FirebaseUI 將使用者身份驗證流程新增至 Flutter 應用

1. 開始之前

在此 Codelab 中,您將了解如何使用 FlutterFire UI 套件將 Firebase 驗證新增至 Flutter 應用程式。使用此軟體包,您可以將電子郵件/密碼驗證和 Google 登入驗證新增至 Flutter 應用程式。您還將了解如何設定 Firebase 項目,以及如何使用 FlutterFire CLI 在 Flutter 應用程式中初始化 Firebase。

先決條件

此 Codelab 假設您有一定的 Flutter 經驗。如果沒有,您可能想先學習基礎知識。以下連結很有幫助:

您還應該有一些 Firebase 經驗,但如果您從未將 Firebase 添加到 Flutter 專案中也沒關係。如果您不熟悉 Firebase 控制台,或者您完全不熟悉 Firebase,請先查看以下連結:

你將創造什麼

此 Codelab 將指導您使用 Firebase 進行身份驗證,建立 Flutter 應用程式的身份驗證流程。該應用程式將有一個登入畫面、一個「註冊」畫面、一個密碼恢復畫面和一個使用者設定檔畫面。

6604fc9157f2c6ae.pngeab9509a41074930.pngda49189a5838e0bb.pngb2ccfb3632b77878.png

你將學到什麼

此代碼實驗室涵蓋:

  • 將 Firebase 新增到 Flutter 應用
  • Firebase 控制台設定
  • 使用 Firebase CLI 將 Firebase 新增到您的應用程式
  • 使用 FlutterFire CLI 在 Dart 中產生 Firebase 配置
  • 將 Firebase 身份驗證新增至您的 Flutter 應用程式
  • 控制台中的 Firebase 身份驗證設置
  • 使用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 的 Web 控制台中建立 Firebase 專案。

創建 Firebase 項目

  1. 登入Firebase
  2. 在 Firebase 控制台中,按一下新增專案(或建立專案),然後輸入 Firebase 專案的名稱(例如「 FlutterFire-UI-Codelab 」)。

df42a5e3d9584b48.png

  1. 按一下項目建立選項。如果出現提示,請接受 Firebase 條款。跳過設定 Google Analytics,因為您不會為此應用程式使用 Analytics。

d1fcec48bf251eaa.png

要了解有關 Firebase 專案的更多信息,請參閱了解 Firebase 專案

您正在建置的應用程式使用Firebase 驗證來允許您的使用者登入您的應用程式。它還允許新用戶從 Flutter 應用程式註冊。

Firebase 驗證需要使用 Firebase 控制台啟用,並且啟用後需要特殊設定。

啟用電子郵件登入以進行 Firebase 身份驗證

要允許使用者登入 Web 應用程序,您首先需要使用電子郵件/密碼登入方法。稍後,您將新增Google 登入方法。

  1. 在 Firebase 控制台中,展開左側面板中的「建置」功能表。
  2. 按一下「驗證」 ,然後按一下「開始」按鈕,然後按一下「登入方法」標籤(或按一下此處直接前往「登入方法」標籤)。
  3. 按一下登入提供者清單中的電子郵件/密碼,將啟用開關設定為開啟位置,然後按一下儲存58e3e3e23c2f16a4.png

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 ,另一個稱為startstart目錄包含一個不完整的項目,這是您花費最多時間的地方。

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 的方法有多種。如果您使用的是 MacOS 或 Linux,最簡單的方法是從終端機執行以下命令:

curl -sL https://firebase.tools | bash

安裝 CLI 後,您必須使用 Firebase 進行身份驗證。

  1. 執行以下命令,使用您的 Google 帳戶登入 Firebase:
firebase login
  1. 此命令將您的本機連接到 Firebase 並授予您對 Firebase 專案的存取權限。
  1. 透過列出您的 Firebase 專案來測試 CLI 是否已正確安裝並可以存取您的帳戶。運行以下命令:
firebase projects:list
  1. 顯示的清單應與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 專案以及要設定的平台。

以下螢幕截圖顯示了您需要回答的提示。

  1. 選擇您要使用的項目。在這種情況下,使用flutterfire-ui-codelab 1359cdeb83204baa.png
  2. 選擇您要使用的平台。在此 Codelab 中,提供了為 Web、iOS 和 Android 版 Flutter 配置 Firebase 驗證的步驟,但您可以將 Firebase 專案設定為使用所有選項。 301c9534f594f472.png
  3. 此螢幕截圖顯示了該過程結束時的輸出。如果您熟悉 Firebase,您會注意到您不必在控制台中建立平台應用程式(例如 Android 應用程式),FlutterFire CLI 已為您完成了這件事。 12199a85ade30459.png

完成後,在文字編輯器中查看 Flutter 應用程式。 FlutterFire CLI 產生了一個名為firebase_options.dart的新檔案。該檔案包含一個名為 FirebaseOptions 的類,該類別具有保存每個平台所需的 Firebase 配置的靜態變數。如果您在執行flutterfire configure時選擇了所有平台,您將看到名為webandroidiosmacos的靜態值。

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 專案中特定平台的特定建置。例如,名為 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函數中的程式碼。

主程式.dart

void main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );


 runApp(const MyApp());
}

這段程式碼做了兩件事。

  1. WidgetsFlutterBinding.ensureInitialized()告訴 Flutter 在 Flutter 框架完全啟動之前不要開始執行應用程式小工具程式碼。 Firebase 使用本機平台通道,這需要框架正在運作。
  2. Firebase.initializeApp在您的 Flutter 應用程式和 Firebase 專案之間建立連線。 DefaultFirebaseOptions.currentPlatform是從我們產生的firebase_options.dart檔案導入的。此靜態值會偵測您正在執行的平台,並傳入對應的 Firebase 鍵。

4. 新增初始 Firebase UI 驗證頁面

Firebase UI for Auth 提供了代表應用程式中整個畫面的小工具。這些畫面處理整個應用程式中的不同身份驗證流程,例如登入、註冊、忘記密碼、使用者設定檔等。首先,在您的應用程式中新增一個登入頁面,充當主應用程式的身份驗證防護。

Material 或 Cupertino 應用程式

FlutterFire UI 要求您的應用程式包裝在 MaterialApp 或 CupertinoApp 中。根據您的選擇,UI 將自動反映 Material 或 Cupertino 小工具的差異。對於此 Codelab,請使用MaterialApp ,它已添加到應用程式的app.dart中。

應用程式.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 ,如果未登錄,則傳回 null。要在我們的應用程式中訂閱此狀態,您可以使用 Flutter 的StreamBuilder小部件並將流傳遞給它。

StreamBuilder是一個小部件,它基於您傳遞給它的Stream的最新資料快照來建構自身。當 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上述串流),如果使用者已通過驗證,它將傳回 Firebase User物件。 (否則將返回null 。)
  • 接下來,程式碼使用snapshot.hasData檢查流中的值是否包含User物件。
  • 如果沒有,它將返回一個SignInScreen小部件。目前,該畫面不會執行任何操作。這將在下一步中更新。
  • 否則,它會傳回一個HomeScreen ,這是應用程式的主要部分,只有經過身份驗證的使用者才能存取。

SignInScreen是一個來自 FlutterFire UI 包的小部件。這將是本 Codelab 下一步的重點。此時執行應用程式時,您應該會看到一個空白的登入畫面。

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參數是獲取所有上述功能所需的唯一代碼。現在您應該看到一個登入畫面,其中包含“電子郵件”和“密碼”文字輸入以及“登入”按鈕。

雖然功能齊全,但缺乏造型。此小部件公開參數來自訂登入畫面的外觀。例如,您可能想要新增您公司的商標。

自訂登入畫面

標題產生器

使用SignInScreen.headerBuilder參數,您可以在登入表單上方新增所需的任何小工具。使用以下程式碼更新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,
);

因為它是一個回調,所以它公開了您可以使用的值,例如BuildContextBoxConstraints ,並要求您返回一個小部件。無論您返回哪個小部件,都會顯示在螢幕頂部。在此範例中,新程式碼將圖像新增至螢幕頂部。您的應用程式現在應該如下所示。

73d7548d91bbd2ab.png

字幕產生器

登入畫面公開了三個附加參數,可讓您自訂畫面: subtitleBuilderfooterBuildersideBuilder

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 相同。它不公開BoxConstraintsshrinkOffset ,因為它適用於文字而不是圖像。 (儘管您可以添加任何您想要的小部件。)

使用此程式碼將頁尾新增至登入畫面。

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 參數接受回調,這次回呼的參數是BuildContextdouble shrinkOffset 。 sideBuilder 傳回的小工具將顯示在登入表單的左側,並且僅在寬螢幕上顯示。實際上,這意味著該小部件將僅顯示在桌面和網路應用程式上。

在內部,FlutterFire UI 使用斷點來決定是否應顯示標題內容(在高螢幕上,如行動裝置)或應顯示側面內容(在寬螢幕、桌面或 Web 上)。具體來說,如果螢幕寬度超過 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)。

8dc60b4e5d7dd2d0.png

創建用戶

至此,該畫面的所有代碼都已完成。不過,在登入之前,您需要建立一個使用者。您可以透過「註冊」畫面執行此操作,也可以在 Firebase 控制台中建立使用者。

若要使用控制台:

  1. 前往 Firebase 控制台中的「使用者」表。
  2. 點這裡
  3. 選擇“flutterfire-ui-codelab”(如果您使用了不同的名稱,請選擇另一個項目)。你會看到這個表:

f038fd9a58ed60d9.png

  1. 點選“新增使用者”按鈕。

2d78390d4c5dbbfa.png

  1. 輸入新使用者的電子郵件地址和密碼。這可能是假電子郵件和密碼,如下圖所示。這可行,但如果您使用虛假電子郵件地址,「忘記密碼」功能將無法運作。

62ba0feb33d54add.png

  1. 點擊“新增用戶”

32b236b3ef94d4c7.png

現在,您可以返回 Flutter 應用程序,並透過登入頁面登入使用者。您的應用程式應如下所示:

dd43d260537f3b1a.png

6. 個人資料螢幕

FlutterFire UI 還提供了一個ProfileScreen小部件,它再次透過幾行程式碼為您提供了許多功能。

新增個人資料螢幕小工具

在文字編輯器中導航到home.dart檔案。使用以下程式碼更新它:

首頁.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回呼傳回的。

重新加載您的應用程序,然後按下右上角(在應用程式欄中)的圖標,它將顯示如下頁面:

36487fc4ab4f26a7.png

這是FlutterFire UI頁面提供的標準UI。所有按鈕和文字欄位都連接到 Firebase Auth,並且開箱即用。例如,您可以在「Name」文字欄位中輸入名稱,FlutterFire UI 將呼叫FirebaseAuth.instance.currentUser?.updateDisplayName方法,該方法會將該名稱儲存在 Firebase 中。

退出

現在,如果您按“退出”按鈕,應用程式將不會更改。它會將您登出,但不會導覽回 AuthGate 小工具。若要實現此目的,請使用 ProfileScreen.actions 參數。

首先,更新 home.dart 中的程式碼。

首頁.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的子類型,通常您使用它們來告訴您的應用程式對不同的身份驗證狀態變更做出反應。當 Firebase 驗證狀態變更為 currentUser 為 null 時,SignedOutAction 會呼叫您提供的回呼函數。

透過新增在 SignedOutAction 觸發時呼叫Navigator.of(context).pop()回調,應用程式將導航到上一頁。在此範例應用程式中,只有一個永久路由,如果沒有用戶登錄,則顯示登入頁面;如果有用戶,則顯示主頁。因為這種情況發生在使用者登出時,應用程式將顯示登入頁面。

自訂個人資料頁面

與登入頁面類似,個人資料頁面是可自訂的。首先,一旦使用者進入個人資料頁面,我們的當前頁面就無法導航回主頁。透過為 ProfileScreen 小部件提供一個 AppBar 來解決此問題。

首頁.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 小工具會將您傳遞給它的子項目放置在「登出」按鈕上方。

更新 home.dart 中的程式碼以在此處顯示公司徽標,類似於登入畫面。

首頁.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(),
          ],
        ),
      ),
    );
  }
}

重新加載您的應用程序,您將在螢幕上看到以下內容:

ebe5792b765dbf87.png

7. 多平台 Google Auth 登入

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 提供者:

  1. 導覽至控制台中的驗證登入提供者畫面。
  2. 按一下“新增提供者”。 8286fb28be94bf30.png
  3. 選擇“Google”。 c4e28e6f4974be7f.png
  4. 切換標記為“啟用”的開關,然後按“儲存”。 e74ff86990763826.png
  5. 如果出現包含有關下載設定檔的資訊的模式,請按一下「完成」。
  6. 確認已新增 Google 登入提供者。 5329ce0543c90d95.png

新增 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 登入按鈕。

aca71a46a011bfb5.png

配置登入按鈕

如果沒有額外的配置,按鈕將無法運作。如果您使用 Flutter Web 進行開發,這是您需要新增的唯一步驟才能使其正常運作。其他平台需要額外的步驟,稍後將對此進行討論。

  1. 導覽至Firebase 控制台中的驗證提供者頁面。
  2. 按一下 Google 提供者。 9b3a325c5eca6e49.png
  3. 點選“Web SDK 配置”擴充面板。
  4. 複製“Web 用戶端 ID”中的值711a79f0d931c60f.png
  5. 返回文字編輯器,並透過將此 ID 傳遞給clientId命名參數來更新檔案auth_gate.dart中的GoogleProvider實例。
GoogleProvider(
   clientId: "YOUR_WEBCLIENT_ID"
)

輸入 Web 用戶端 ID 後,重新載入您的應用程式。當您按下「使用 Google 登入」按鈕時,將會出現一個新視窗(如果您使用的是網路),引導您完成 Google 登入流程。最初,它看起來像這樣:

14e73e3c9de704bb.png

配置 iOS

為了使其在 iOS 上運行,需要一個額外的配置過程。

  1. 導覽至Firebase 控制台中的「專案設定」畫面。將有一張卡片列出您的 Firebase 應用程序,如下所示: fefa674acbf213cc.png
  2. 點選 iOS。請注意,您的應用程式名稱將與我的不同。如果您使用flutter-codelabs/firebase-auth-flutterfire-ui/start專案來執行此 Codelab,那麼我的版本會顯示“完成”,而您的版本則會顯示“開始”。
  3. 按一下「GoogleServices-Info.plist」按鈕下載所需的設定檔。 f89b3192871dfbe3.png
  4. 將下載的檔案拖曳到名為 的目錄中。 Flutter 專案中的/ios/Runner
  5. 透過從專案的根目錄執行以下終端命令來開啟 Xcode:

開啟 ios/Runner.xcworkspace

  1. 右鍵單擊 Runner 目錄並選擇將檔案新增至“Runner”。 858986063a4c5201.png
  2. 從檔案總管中選擇 GoogleService-Info.plist。
  3. 返回文字編輯器(不是 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 -->

如果您的 Flutter 應用程式已經在 iOS 中運行,您必須完全關閉它,然後重新運行該應用程式。否則,請在 iOS 中運行該應用程式。

8. 恭喜!

您已完成 Flutter 的 Firebase Auth UI Codelab 。您可以在 github 上的“完整”目錄中找到此 Codelab 的完整程式碼: Flutter Codelabs

我們涵蓋的內容

  • 設定 Flutter 應用程式以使用 Firebase
  • 在 Firebase 控制台中設定 Firebase 項目
  • FlutterFire CLI
  • Firebase CLI
  • 使用 Firebase 驗證
  • 使用 FlutterFire UI 輕鬆處理 Flutter 應用程式中的 Firebase 驗證

下一步

了解更多

Sparky在這裡與您一起慶祝!

2a0ad195769368b1.gif