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.dartauth_gate.darthome.dartmain.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 的認證狀態發生變化時,它會發出事件。

StreamBuilderbuilder 方法會根據 Stream 的最新事件來構建 UI。如果 Stream 尚未發出事件(即 snapshot.hasDatafalse),則返回一個 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,這是一個基本的視覺布局結構,包含了應用程序的主要元素,如 appBarbody

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