Skip to content

2.Firebase user authentication

Warning

  • 在執行此專案前必須先確認在bash的終端機使用firebase login有無登入成功
  • 若沒成功此專案無法執行

執行步驟

Note

  • 設定一個新Flutter專案
  • 到Google提供的完整程式碼將以下內容加入pubspec.yaml
    dependencies:
        firebase_auth: ^4.16.0
        firebase_core: ^2.24.2
        firebase_ui_auth: ^1.12.0
        firebase_ui_oauth_google: ^1.2.16
        flutter:
            sdk: flutter
        google_sign_in: ^6.2.1
    
    dev_dependencies:
        flutter_test:
            sdk: flutter
        flutter_lints: ^3.0.1
    
  • 在終端機輸入dart pub global activate flutterfire_cli
  • 接著輸入flutterfire configure
  • 選擇create a new project
    Alt text
  • 設定Firebase的專案名稱,要注意名稱因為很多人都取過所以要取特別一點
  • 成功的話會跳到下一步,直接按Enter
    Alt text
  • 會執行一段時間後出現以下畫面
    Alt text
  • 在lib資料夾中會出現一個名為firebase_options.dart的檔案
    Alt text
  • 將lib檔案內容裡的app.dart,auth_gate.dart,home.dart,main.dart內容複製至自己的專案lib資料夾中
  • 至Firebase官網登入並到主控台
    Alt text
  • 找到所屬專案並點入
    Alt text
  • 左側菜單點選建構,在點選Authentication
    Alt text
  • 按下開始使用
    Alt text
  • 選擇電子郵件/密碼
    Alt text
  • 選擇啟用然後儲存
    Alt text
  • 在專案中選擇Android手機模擬器(老師用iPhone模擬器示範)
    Alt text
  • 在終端機中輸入flutter run會發現出現錯誤
    Alt text
  • 在Mac系統中會自動詢問,但在Windows中可能沒有
    Alt text

要在 Flutter 應用程式中啟用 Multidex 支援,你需要在你的 android/app/build.gradle 文件中做一些修改。以下是具體的步驟:

  1. 打開 android/app/build.gradle 文件。
  2. 在 android 區塊中,找到 defaultConfig 區塊,並添加 multiDexEnabled true。
  3. 在 dependencies 區塊中,添加 implementation 'com.android.support:multidex:1.0.3'。

以下是修改後的 build.gradle 文件:

android {
    defaultConfig {
        // ...
        multiDexEnabled true
    }
    // ...
}

dependencies {
    // ...
    implementation 'com.android.support:multidex:1.0.3'
}

這樣就可以啟用 Multidex 支援了。請注意,如果你的 minSdkVersion 是 21 或更高,則不需要添加 implementation 'com.android.support:multidex:1.0.3'。

  • 在終端機中輸入flutter run會出現APP畫面
    Alt text
  • 按下Register進到註冊畫面
    Alt text
  • 註冊成功後進到Welcome畫面
    Alt text
  • 在FireBase網站也可以看到有註冊訊息
    Alt text

lib資料夾內容

Code

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(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
    ),
    home: const AuthGate(),
    );
}
}

這段代碼是一個使用 Flutter 框架構建的應用程序的入口:

  • import 'package:flutter/material.dart';:這行代碼是導入 Flutter 框架的 Material 組件庫,它包含了構建應用程序所需的各種視覺組件和功能。

  • import 'auth_gate.dart';:這行代碼是導入自定義的 auth_gate.dart 文件,該文件可能包含了應用程序的身份驗證網關或其他自定義組件。

  • class MyApp extends StatelessWidget { ... }:這是一個名為 MyApp 的類,它繼承自 StatelessWidget 類。在 Flutter 中,一個應用程序通常從一個 Widget 開始構建,而 StatelessWidget 是一個不可變的 Widget,意味著一旦構建完成,就不能更改其狀態或屬性。

  • const MyApp({super.key});:這是 MyApp 類的構造函數,使用了可選的參數 key,這個參數通常用於在 Widget 樹中標識不同的 Widget。

  • Widget build(BuildContext context) { ... }:這是 StatelessWidget 的一個必需的方法,用於構建 Widget 的 UI。BuildContext 是一個包含有關 Widget 在樹中位置和主題的信息的對象。

  • return MaterialApp(...);:這是一個 MaterialApp Widget 的實例,它是一個定義了應用程序 UI 的頂層 Widget。它包含了主題和應用程序的主頁。

  • theme: ThemeData(...):這里設置了應用程序的主題,包括顏色方案和是否使用 Material Design 3.0。

  • home: const AuthGate(),:這里指定了應用程序的主頁為一個名為 AuthGate 的 Widget,通常是用戶登錄或身份驗證的界面。

這段代碼的作用是創建一個基本的 Flutter 應用程序,並指定了應用程序的主題和主頁。

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';
import 'main.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: clientId),
                ],
                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),
                    ),
                );
                },
            );
            }

            return const HomeScreen();
        },
        );
    }
}

這段 Dart 程式碼定義了一個名為 AuthGate 的 Flutter widget,該 widget 是 StatelessWidget 的子類,這意味著它的 UI 在生命週期內不會改變。

在 build 方法中,我們返回一個 StreamBuilder widget,它會根據 FirebaseAuth.instance.authStateChanges() 的結果來構建 UI。authStateChanges() 是一個 Stream,當 Firebase Auth 的認證狀態發生變化時,它會發出事件。

StreamBuilder 的 builder 方法會根據 Stream 的最新事件來構建 UI。如果 Stream 尚未發出事件(即 snapshot.hasData 為 false),則返回一個 SignInScreen widget,該 widget 提供用戶登入的界面。在這個界面中,用戶可以選擇使用 Email 或 Google 進行登入。

如果 Stream 已經發出事件,這意味著用戶的認證狀態已經確定,則返回 HomeScreen widget,這是用戶已登入後看到的主頁面。

這個 AuthGate widget 的主要功能是根據用戶的認證狀態來決定顯示哪個界面。如果用戶未登入,則顯示登入界面;如果用戶已登入,則顯示主頁面。

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

這段 Dart 程式碼定義了一個名為 HomeScreen 的 Flutter widget,該 widget 是 StatelessWidget 的子類,這意味著它的 UI 在生命週期內不會改變。

在 build 方法中,我們返回一個 Scaffold widget,這是一個基本的視覺布局結構,包含了應用程序的主要元素,如 appBar 和 body。

appBar 是一個 AppBar widget,其中包含一個 IconButton。當按下這個按鈕時,會使用 Navigator.push 方法導航到 ProfileScreen 頁面。ProfileScreen 頁面包含一個 AppBar,一個 SignedOutAction,以及一個顯示圖片的 AspectRatio widget,請注意ProfileScreen是Firebase的package提供的widget

body 是一個 Center widget,其中包含一個 Column widget。Column widget 包含一個圖片,一個歡迎文字,以及一個 SignOutButton。

這個 HomeScreen widget 的主要功能是提供一個主頁面,用戶可以從這裡導航到他們的個人資料頁面,或者登出。

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

import 'app.dart';
import 'firebase_options.dart';

// TODO(codelab user): Get API key
const clientId = 'YOUR_CLIENT_ID';

void main() async {
WidgetsFlutterBinding.ensureInitialized();  // 初始化 Flutter 應用程序綁定
await Firebase.initializeApp(  // 初始化 Firebase 應用
    options: DefaultFirebaseOptions.currentPlatform,  // 使用默認 Firebase 選項
);

runApp(const MyApp());  // 運行我們的 Flutter 應用程序
}

這段代碼是一個Flutter應用程序的主入口:

  1. import 'package:firebase_core/firebase_core.dart'; 和 import 'package:flutter/material.dart';:這些語句用於導入Flutter和Firebase庫,以便我們可以使用它們的功能。

  2. WidgetsFlutterBinding.ensureInitialized();:這行代碼確保Flutter應用程序已經初始化綁定。這是因為Flutter應用程序在運行之前需要綁定到操作系統。

  3. await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);:這是初始化Firebase應用程序的關鍵部分。我們使用await關鍵字等待初始化完成,以確保我們在繼續之前已經準備好使用Firebase。

  4. const clientId = 'YOUR_CLIENT_ID';:這是一個常量,存儲著你的客戶端ID。在這個示例中,你需要替換YOUR_CLIENT_ID為你的實際客戶端ID。


Last update : 13 novembre 2024
Created : 13 novembre 2024

Comments

Comments