【Xcode/Swift】Firebase Authenticationを用いたログイン機能（メアド＆パスワード）

# 環境
- Xcode15.0.1
- Swift 5

# 前提
以下を前提とする

- firebaseでプロジェクトを作成している
- firbeaeのプロジェクトとxcodeのプロジェクトを紐づけている
- firebaseのプロジェクトのGoogleService-infoをxcodeのプロジェクトにダウンロードしている
- xcodeのプロジェクトにfirebase sdkをインストールしている
- AppDelegate.swiftに'FirebaseApp.configure()'の設定をしている

# 手順
### Story Boardの作成
1. LoginViewControllerを作成し、メールアドレス（UITextField）・パスワード（UITextField）・ログインボタン（UIButton）を配置する
1. MainViewControllerを作成し、ログアウトボタン（UIButton）を配置する
### LoginViewControllerの作成
```
import UIKit
import FirebaseAuth

class LoginViewController: UIViewController {

    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupKeyboardDismissal()
    }

    @IBAction func loginButtonTapped(_ sender: UIButton) {
        guard let email = emailTextField.text, !email.isEmpty,
              let password = passwordTextField.text, !password.isEmpty else {
            showAlert(message: "メールアドレスとパスワードを入力してください")
            return
        }

        Auth.auth().signIn(withEmail: email, password: password) { authResult, error in
            if let error = error {
                let localizedErrorMessage = NSLocalizedString(error.localizedDescription, comment: "")
                self.showAlert(message: "ログインに失敗しました: \(localizedErrorMessage)")
                return
            }

            // ログインが成功した場合、必要に応じてユーザーを次の画面に遷移させる
            //self.showAlert(message: "ログインに成功しました！")
            self.transitionToMainViewController()
            
        }
    }

    // メイン画面に遷移する関数
    func transitionToMainViewController() {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let mainViewController = storyboard.instantiateViewController(withIdentifier: "MainViewController")
        
        // アニメーションで遷移
        if let window = UIApplication.shared.windows.first {
            window.rootViewController = mainViewController
            UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: nil, completion: nil)
        }
    }
    
    // アラートを表示するヘルパー関数
    func showAlert(message: String) {
        let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "OK", style: .default))
        present(alertController, animated: true)
    }

    // キーボードを閉じるためのセットアップ関数
    func setupKeyboardDismissal() {
        // Viewにタップジェスチャーを追加
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        view.addGestureRecognizer(tapGesture)
    }

    // キーボードを閉じるための関数
    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}
```
### MainViewControllerの作成
```
import UIKit
import FirebaseAuth

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func logoutButtonTapped(_ sender: UIButton) {
        do {
            try Auth.auth().signOut()
            // ログイン画面に遷移
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let loginViewController = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
            if let window = UIApplication.shared.windows.first {
                window.rootViewController = loginViewController
                UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: nil, completion: nil)
            }
        } catch let signOutError as NSError {
            print("Error signing out: %@", signOutError)
        }
    }
}
```
### ローカライゼーション
Localizable.stringsを作成し、以下を追加
```
"The password is invalid or the user does not have a password." = "パスワードが無効であるか、ユーザーにパスワードがありません。";
"User not found." = "ユーザーが見つかりません。";
```
### 自動ログイン機能
SceneDelegate.swiftに以下を追加
```
import UIKit
import FirebaseAuth

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let _ = (scene as? UIWindowScene) else { return }

        // 現在のユーザーを取得
        if Auth.auth().currentUser != nil {
            // ログインしている場合は、メイン画面に遷移
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let mainViewController = storyboard.instantiateViewController(withIdentifier: "MainViewController")
            window?.rootViewController = mainViewController
        } else {
            // ログインしていない場合は、ログイン画面に遷移
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let loginViewController = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
            window?.rootViewController = loginViewController
        }
    }

    // その他のメソッド...
}
```
AppDelegate.swiftに以下追加
```
import UIKit
import FirebaseAuth

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        // Firebaseの設定
        FirebaseApp.configure()

        // 現在のユーザーを取得
        if Auth.auth().currentUser != nil {
            // ログインしている場合は、メイン画面に遷移
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let mainViewController = storyboard.instantiateViewController(withIdentifier: "MainViewController")
            window?.rootViewController = mainViewController
        } else {
            // ログインしていない場合は、ログイン画面に遷移
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let loginViewController = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
            window?.rootViewController = loginViewController
        }

        return true
    }

    // その他のメソッド...
}
```
### Identifierの設定
Story Boardにて、LoginViewControllerとMainViewControllerのIdentifierをそれぞれ設定する