swiftUI✖️firebaseUIで簡単にログイン機能作ってみた！

# はじめに
初めまして！N高等学校7期生の3年生のさきです！名古屋キャンパスに通学しています。
以前作成したアプリで使用したfirebaseUIがとっても便利だったので、今回はswiftUIとfirebaseUIを使って、ログイン機能を作ってみたいと思います！
# FirebaseUIって？
 FirebaseのAuthentication を基に作成されたライブラリで、簡単にメールアドレスやgoogleログイン、appleログインを実装することができます。
長いコードをかくことなく、firebase単体でログイン機能を作る時よりとっても簡単に作ることができます。
# 作り方
1xcodeでプロジェクト作成、firebaseの準備
2fireabaseUIのインポート
3実際のコード
の順番に進めていきます
# xcodeでプロジェクト作成、firebaseの準備
xcodeを起動し、適当な名前を決めてプロジェクトを作成します。今回はswiftUIを使っていきます。
![スクリーンショット 2023-12-11 12.07.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/1e0dd1e4-82bf-71c9-bc71-3e4eecb68557.png)

次はfirebaseを準備します。
https://console.firebase.google.com/u/0/?hl=ja
このリンクにアクセスしてプロジェクトを追加、名前をつけてプロジェクトを作成します。Apple アプリへのFirebaseの追加も済ませておきます。

今回はfirebaseの設定の後から今回は書きたいと思います。
 Swift Package Managerを今回使用しています！
Firebase SDKは画像の2つを選択します。必要に応じて適宜別のものも追加してください。

:::note info
バージョンは **Up to Next Major Version 10.16.0<** を選んでください！
:::

![スクリーンショット 2023-12-11 13.22.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/538846c0-a0a4-7fd1-9222-9b7b52333abb.png)


この画面がひらけば準備完了です！

![スクリーンショット 2023-12-11 13.25.11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/4a0ef7cf-b5f0-5ec4-a5d8-f2104200c0eb.jpeg)

次にAuthenticationを追加します。
今回はメール、google、appleでログインできるようにしたいと思います。

![スクリーンショット 2023-12-11 13.28.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/0ac4d63f-ca7f-fbfd-3883-3388eaa93e52.png)

googleを有効にしたら、ファイルを置き換えてください。

![スクリーンショット 2023-12-11 13.31.00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/69bba8dd-a2e7-7968-5dca-8ea8f76b8256.jpeg)


このような画面になればOKです！

![スクリーンショット 2023-12-11 13.31.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/eef415d0-9b14-926a-710f-a4bc7b989689.png)

# fireabaseUIのインポート
addPackage Dependeciesを押して、パッケージを追加する画面を開き、https://github.com/firebase/firebaseui-ios
このリンクを貼り付けます。

![スクリーンショット 2023-12-11 13.37.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/93bfeb65-eea9-30ad-73b0-6e10440ffa10.png)

 ~~Dependency RuleをBranch、Masterに変更~~ し、AddPackageを押します。
 「追記」
 MasterではなくMainに変更されていました

![スクリーンショット 2023-12-11 13.37.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/f35b43ac-67b9-f95b-a5d5-eaa638603262.png)

今回はfirebaseAuthUIでEmailとgoogle、appleログインのみを使うので、
FirebaseAuthUI
FirebaseGoogleAuthUI
FirebaseOAuthUI
FirebaseEmailAuthUI
を選択します。必要に応じて適宜別のものも追加してください。

![スクリーンショット 2023-12-11 13.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/dd764213-1cd9-4eb8-ff8c-6bc19bffe333.png)
![スクリーンショット 2023-12-11 14.16.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/aa9dad79-efe8-a9dc-eee8-45d49782c048.png)


これでfirebaseUIのインポート完了です！

# 実際のコード
今回はcontentViewにログインボタンをつけて、ログインするとSecondViewに飛んでログアウトできるようにしたいと思います。まずはContentViewにログインボタンをつけて、LoginViewに飛べるようにします。

```swift

import SwiftUI

struct ContentView: View {
    @State var isShowLogin = false
    var body: some View {
        VStack {
            Button("ログイン") {
                isShowLogin .toggle()
            }
            Spacer()
                .sheet(isPresented: $isShowLogin) {
                    LoginView()
                }
        }
        .padding()
    }
}
```
次にLoginViewでfirebase関連をimportします。
今回はEmailとgoogle、appleログインに対応するのでこれらをimportします。

```swift
import SwiftUI
import FirebaseAuthUI
import FirebaseGoogleAuthUI
import FirebaseOAuthUI
import FirebaseEmailAuthUI
```
```swift
struct LoginView: UIViewControllerRepresentable {
    
    func makeUIViewController(context: Context) -> UINavigationController {
        let authUI = FUIAuth.defaultAuthUI()!
        // ログイン方法を選択
        let providers: [FUIAuthProvider] = [
            FUIGoogleAuth(authUI: authUI),
            FUIOAuth.appleAuthProvider(),
            FUIEmailAuth()
        ]
        authUI.providers = providers
        
        // FirebaseUIを表示する
        let authViewController = authUI.authViewController()
        
        return authViewController
    }
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
        // 処理なし
    }
}
```
firebaseを初期化します

```swift
import SwiftUI
import FirebaseCore
import FirebaseAuthUI


class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        FirebaseApp.configure()
        
        return true
    }
    // MARK: URL Schemes
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
        let sourceApplication = options[UIApplication.OpenURLOptionsKey.sourceApplication] as! String?
        if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication) ?? false {
            return true
        }
        // other URL handling goes here.
        return false
    }
}
@main
struct sampleFirebaseUIApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

```
起動するとこのような画面になると思います！sign in with emailを押して進むと最初のログイン画面に戻ります！
今の状態だとgoogleログインとappleログインを押すとエラーが出ます。
![IMG_2604.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/b1682780-927f-d92f-59ae-70de86fb4774.jpeg)
![IMG_2605.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/c6b250e8-fc65-e858-cb69-9651d7d4f019.jpeg)


# ログイン分岐してみた
次はログインしているかをみて、別viewに飛ばします

**AuthenticationManager**を作成して、ログインしているかを分岐します。

```swift
import Foundation
import FirebaseAuth


@Observable class AuthenticationManager {
    private(set) var isSignIn: Bool = false
    private var handle: AuthStateDidChangeListenerHandle!
    
    init() {
        // ここで認証状態の変化を監視する（リスナー）
        handle = Auth.auth().addStateDidChangeListener { (auth, user) in
            if let _ = user {
                print("Sign-in")
                self.isSignIn = true
            } else {
                print("Sign-out")
                self.isSignIn = false  
            }
        }
    }
    
    deinit {
        // ここで認証状態の変化の監視を解除する
        Auth.auth().removeStateDidChangeListener(handle)
    }
    
    func signOut() {
        do {
            try Auth.auth().signOut()
        } catch {
            print("Error")
        }
    }     
}
```

**ContentView**に戻り、コードを変更します。

```swift
import SwiftUI

struct ContentView: View {
    @State var isShowLogin = false
    var authenticationManager = AuthenticationManager()
    var body: some View {
        VStack {
            if authenticationManager.isSignIn == false {
                //ログインしていないとき
                Button("ログイン") {
                    isShowLogin .toggle()
                }
            }else{
                //ログインしているとき
                SecondView()
            }
            Spacer()
                .sheet(isPresented: $isShowLogin) {
                    LoginView()
                }
        }
        .padding()
    }
}
```
**SecondView**にログアウトボタンを設置します。
```swift
import SwiftUI

struct SecondView: View {
    var authenticationManager = AuthenticationManager()
    var body: some View {
        Button("ログアウト") {
            authenticationManager.signOut()
        }
    }
}
```

# googleログイン
今の状態だとgoogleログインとappleログインを押すとエラーが出るので設定していきます。

GoogleServive infoの reversed client IDを

![IMG_2596.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/e5cbaca4-dc82-a9e3-0412-12e3941a71f7.png)


URLtypesの**URLSchemes**に貼り付けます

![スクリーンショット 2023-12-11 19.07.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/4bb40dc3-d39e-8263-1d47-6ac2bc35be92.png)

googleはこれでOK

# appleログイン
Apple のデベロッパーサイトからappleログインを有効にします。
https://developer.apple.com/account/resources/certificates/list

**Identifers**からプラスを押してApp IDs→Appを選択、

![IMG_2601.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/1a3a676e-726e-9637-ef0c-e1291c61a21f.png)

**sign In with Appleを有効**にします。
**Server-to-Server Notification Endpoint**にfirebaseの認証コールバックURLを貼り、
continueを押して保存します。


![スクリーンショット 2023-12-11 19.18.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/741b326e-7fe4-6819-ff88-4591c5e133f1.jpeg)

![IMG_2603.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/cb96feb7-7608-7f5c-ed19-d2eb09465f1b.png)


ここまでできたらxcodeに戻って、signing & capabilitiesから**capability**を選択して
sign In with Appleを追加します。

![スクリーンショット 2023-12-11 20.35.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627452/9986d898-e327-521a-9f09-f05901864b1c.png)

これでappleログインも無事実装できました！

# 終わりに
初めて記事を書いたので読みにくいところたくさんあったと思います！普通にfirebaseでログイン機能を作るより短いコードでログイン機能を実装することができました！
firebaseもswiftUIもお勉強中なのでこれからもたくさん使っていきたいと思います！ありがとうございました！