1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【SwiftUI】Firebase Authenticationでログイン機能を作ってみる

Posted at

前提

こちらの記事の続きでFirebaseAuthを用いてログイン機能を実装します。

参考

導入手順などは公式サイトの手順通りに行いました。

GitHub

実装

アプリ起動時にFirebase.configure()を呼びます。

import SwiftUI
import Firebase

@main
struct SwiftUI_MVVM_LoginApp: App {
    init() {
        FirebaseApp.configure()
    }

    var body: some Scene {
        WindowGroup {
            NavigationView {
                ContentView(viewModel: ContentViewModel(firebaseAuthService: FirebaseAuthService.shared))
            }
        }
    }
}

FirebaseAuth用のServiceを作成します。

シングルトンで作ってみました。
addStateDidChangeListenerのクロージャーで受け取ったuserを保持しておけば
ログイン中のユーザー情報をこの常にこのServiceから取得することもできます。

import FirebaseAuth

protocol IFirebaseAuthService: AnyObject {
    func addStateDidChangeListener(completion: @escaping (Bool) -> Void)
    func removeStateDidChangeListener()
    func signIn(email: String?, password: String?, completion: @escaping (Error?) -> Void)
    func signUp(email: String?, password: String?, completion: @escaping (Error?) -> Void)
    func signOut()
}

final class FirebaseAuthService: IFirebaseAuthService {
    public static let shared = FirebaseAuthService()

    private var handler: AuthStateDidChangeListenerHandle?

    private init() {}

    deinit {
        removeStateDidChangeListener()
    }

    func addStateDidChangeListener(completion: @escaping (Bool) -> Void) {
        handler = Auth.auth().addStateDidChangeListener { (auth, user) in
            if let _ = user {
                completion(true)
            } else {
                completion(false)
            }
        }
    }

    func removeStateDidChangeListener() {
        if let handler = handler {
            Auth.auth().removeStateDidChangeListener(handler)
        }
    }

    func signUp(email: String?, password: String?, completion: @escaping (Error?) -> Void) {
        guard let email = email, let password = password else {
            completion(nil)
            return
        }

        Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
            completion(error)
        }
    }

    func signIn(email: String?, password: String?, completion: @escaping (Error?) -> Void) {
        guard let email = email, let password = password else {
            completion(nil)
            return
        }

        Auth.auth().signIn(withEmail: email, password: password) { authResult, error in
            completion(error)
        }
    }

    func signOut() {
        do {
            try Auth.auth().signOut()
        }
        catch(let error) {
            debugPrint(error.localizedDescription)
        }
    }
}

ContentViewのViewModelを作成して、ログイン中かどうかのフラグを持たせています。

import FirebaseAuth
import Combine

final class ContentViewModel: ObservableObject {
    @Published var isLogin: Bool = false

    private let firebaseAuthService: IFirebaseAuthService

    // Input: Viewで発生するイベントをViewModelで検知するためのもの
    let didTapLogoutButton = PassthroughSubject<Void, Never>()

    // cancellable
    private var cancellables = Set<AnyCancellable>()

    init(firebaseAuthService: IFirebaseAuthService) {
        self.firebaseAuthService = firebaseAuthService
        firebaseAuthService.addStateDidChangeListener(completion: { [weak self] in
            self?.isLogin = $0
        })

        didTapLogoutButton
            .sink(receiveValue: {
                firebaseAuthService.signOut()
            })
            .store(in: &cancellables)
    }
}

あとはログイン画面や新規登録画面でFirebaseAuthServiceのメソッドを呼ぶだけです

ログイン処理

didTapLoginButton
    .sink(receiveValue: { [weak self] in
        firebaseAuthService.signIn(email: self?.email, password: self?.password, completion: {
            if let error = $0 {
                self?.isShowError = (true, error.localizedDescription)
            }
        })
    })
    .store(in: &cancellables)

新規登録処理

didTapSignUpButton
    .sink(receiveValue: { [weak self] in
        firebaseAuthService.signUp(email: self?.email, password: self?.password, completion: { [weak self] in
            if let error = $0 {
                self?.isShowError = (true, error.localizedDescription)
            }
        })
    })
    .store(in: &cancellables)
1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?