iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0
自我挑戰組

30天學習flutter系列 第 21

21.flutter的持久化存儲(四)

  • 分享至 

  • xImage
  •  

今天來使用firebase auth來處理我們app的登入登出。

在開始之前,我們先修改一下我們project的架構

1.創建services資料夾並將db_provider移至裡面並重新命名db_service
https://ithelp.ithome.com.tw/upload/images/20221006/2010893100Xx7v4mBT.png
2.打開todo\lib\services\db_services.dart,右鍵點擊將所有的DbProvider重命名
https://ithelp.ithome.com.tw/upload/images/20221006/20108931CINHjOQJor.png
https://ithelp.ithome.com.tw/upload/images/20221006/20108931iFXsVn9Vxu.png
=>
https://ithelp.ithome.com.tw/upload/images/20221006/20108931e983rmXcCq.png


firebase

安裝依賴

安裝依賴firebaase_corefirebase_auth

dependencies:
  firebase_core: ^1.24.0
  firebase_auth: ^3.11.1

設置我們的firebase

a) 打開firebase,並創建專案

https://ithelp.ithome.com.tw/upload/images/20221006/20108931znfwtt4odz.png
https://ithelp.ithome.com.tw/upload/images/20221006/20108931q03SZwghA8.png

點擊繼續並建立專案
https://ithelp.ithome.com.tw/upload/images/20221006/20108931glcxk1Dv82.png

b) 完成後,我們選擇要使用的裝置,我們這邊選擇android
https://ithelp.ithome.com.tw/upload/images/20221006/20108931tmMjkb9BPW.png

接著打開我們專案中的android,並找到todo\android\app\build.gradle,並找到applicationId
https://ithelp.ithome.com.tw/upload/images/20221006/20108931fK9Yxn9SQp.png

1.註冊應用程式
https://ithelp.ithome.com.tw/upload/images/20221006/201089319zejfVMSBv.png

2.將下載的設定檔google-services.json加入到模組 (應用程式層級) 根目錄中
https://ithelp.ithome.com.tw/upload/images/20221006/20108931BxgcDeZUAR.png

https://ithelp.ithome.com.tw/upload/images/20221006/20108931dq25MdNTnR.png

3.照著步驟3,我們打開todo\android\build.gradle加入依賴
https://ithelp.ithome.com.tw/upload/images/20221006/20108931Mu3kRZcwv1.png
https://ithelp.ithome.com.tw/upload/images/20221006/20108931rfhCsSA3I5.png

接著打開todo\android\app\build.gradle加入
https://ithelp.ithome.com.tw/upload/images/20221006/20108931DNPwe3UMJf.png

https://ithelp.ithome.com.tw/upload/images/20221006/20108931ad8yu2SeYW.png

https://ithelp.ithome.com.tw/upload/images/20221006/20108931DUZUQSc7j1.png

並且修改minSdkVersion
https://ithelp.ithome.com.tw/upload/images/20221006/20108931FdXWDxQzq9.png

4.我們已經設定完了,接著回到主控台
https://ithelp.ithome.com.tw/upload/images/20221006/20108931N7KC5f7qWS.png

c) 啟動Auth功能

我們來啟動Auth功能
https://ithelp.ithome.com.tw/upload/images/20221006/20108931eKzYXS0KIm.png
https://ithelp.ithome.com.tw/upload/images/20221006/20108931bgZtMxotdV.png

選擇email
https://ithelp.ithome.com.tw/upload/images/20221006/20108931tsijnAvfxA.png
https://ithelp.ithome.com.tw/upload/images/20221006/20108931IxnqSJ7MyT.png

創建AuthService

我們創建todo\lib\services\auth_services.dart並加入Auth功能

import 'package:firebase_auth/firebase_auth.dart';

class AuthService {
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

  User? get currentUser => _firebaseAuth.currentUser;

  Future<void> sendPasswordResetEmail({
    required String email,
  }) async {
    await _firebaseAuth.sendPasswordResetEmail(email: email);
  }

  Future<void> signInWithEmailAndPassword({
    required String email,
    required String password,
  }) async {
    await _firebaseAuth.signInWithEmailAndPassword(
      email: email,
      password: password,
    );
  }

  Future<void> createUserWithEmailAndPassword({
    required String email,
    required String password,
  }) async {
    await _firebaseAuth.createUserWithEmailAndPassword(
      email: email,
      password: password,
    );
  }

  Future<void> signOut() async {
    await _firebaseAuth.signOut();
  }
}

創建註冊頁面

我們創建新的screen,todo\lib\ui\screens\auth_screen.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:todo/services/auth_services.dart';

class AuthScreen extends StatefulWidget {
  const AuthScreen({Key? key}) : super(key: key);

  @override
  State<AuthScreen> createState() => _AuthScreenState();
}

class _AuthScreenState extends State<AuthScreen> {
  String? errorMessage = '';
  bool isLogin = true;

  final TextEditingController _controllerEmail = TextEditingController();
  final TextEditingController _controllerPassword = TextEditingController();

  Future<void> signInWithEmailAndPassword() async {
    try {
      await AuthService().signInWithEmailAndPassword(
        email: _controllerEmail.text,
        password: _controllerPassword.text,
      );
    } on FirebaseAuthException catch (e) {
      setState(() {
        errorMessage = e.message;
      });
    }
  }

  Future<void> createUserWithEmailAndPassword() async {
    try {
      await AuthService().createUserWithEmailAndPassword(
        email: _controllerEmail.text,
        password: _controllerPassword.text,
      );
    } on FirebaseAuthException catch (e) {
      setState(() {
        errorMessage = e.message;
      });
    }
  }

  Widget _entry(
    String title,
    TextEditingController controller,
  ) {
    return TextField(
      controller: controller,
      decoration: InputDecoration(
        labelText: title,
      ),
    );
  }

  Widget _message() {
    return Text(errorMessage == '' ? '' : '$errorMessage');
  }

  Widget _submitButton() {
    return ElevatedButton(
      onPressed:
          isLogin ? signInWithEmailAndPassword : createUserWithEmailAndPassword,
      child: Text(isLogin ? 'Login' : 'Register'),
    );
  }

  Widget _authButton() {
    return TextButton(
      onPressed: () {
        setState(() {
          isLogin = !isLogin;
        });
      },
      child: Text(isLogin ? 'Register instead' : 'Login instead'),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        width: double.infinity,
        height: double.infinity,
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _entry('email', _controllerEmail),
            _entry('password', _controllerPassword),
            _message(),
            _submitButton(),
            _authButton(),
          ],
        ),
      ),
    );
  }
}

並且打開我們的todo\lib\ui\widgets\user_header_widget.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:todo/models/user_model.dart';
import 'package:todo/services/auth_services.dart';
import 'package:todo/states/user_state.dart';
import 'package:todo/ui/screens/auth_screen.dart';

class UserHeader extends ConsumerWidget {
  const UserHeader({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final User? user = AuthService().currentUser;

    UserModel _testUser = UserModel(
      username: 'username',
      isLogin: false,
      bio: 'bio',
      email: 'email@test.com',
      message: '',
    );

    // bool isLogin = ref.watch(userProvider).isLogin;
    bool isLogin = (user != null ? true : false);
    // String message = ref.watch(userProvider).message;

    return Container(
      child: Row(children: [
        Placeholder(
          fallbackHeight: 50,
          fallbackWidth: 50,
        ),
        const SizedBox(
          width: 20,
        ),
        isLogin
            ? ElevatedButton(
                onPressed: () {},
                child: Text('Logout'),
              )
            : ElevatedButton(
                onPressed: () {
                  // ref.read(userProvider.notifier).login(_testUser);
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => const AuthScreen(),
                    ),
                  );
                },
                child: Text('Login'),
              ),
      ]),
    );
  }
}

並修改我們的main.dart來init firebase

import 'dart:math';

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:todo/states/todo_state.dart';
import 'package:todo/ui/screens/nav_screen.dart';

void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FutureBuilder(
        future: Firebase.initializeApp(),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return Text('Something Wrong');
          }
          if (snapshot.connectionState == ConnectionState.done) {
            return NavScreen();
          }

          return CircularProgressIndicator();
        },
      ),
      debugShowCheckedModeBanner: false,
    );
  }
}

測試

https://ithelp.ithome.com.tw/upload/images/20221006/20108931oJFAHmgMe4.png
點擊登入
https://ithelp.ithome.com.tw/upload/images/20221006/20108931h1kDG6ce7p.png
出現Error Message
https://ithelp.ithome.com.tw/upload/images/20221006/20108931i6rUbfKN4V.png

接著,我們測試使用註冊
https://ithelp.ithome.com.tw/upload/images/20221006/20108931cxaoSFUYH7.png
點擊註冊
https://ithelp.ithome.com.tw/upload/images/20221006/20108931itdfopIfSS.png

接著我們到firebase看
https://ithelp.ithome.com.tw/upload/images/20221006/20108931IRC6QTSMWi.png

我們已經成功註冊了


上一篇
20.flutter的持久化存儲(三)
下一篇
22.flutter的持久化存儲(五)
系列文
30天學習flutter30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言