FirebaseUIをSwiftUIで表示する

# はじめに
Firebase Authenticationを使う上で簡単にSign-In画面を簡単に表示できるFirebaseUIを使うことはSign-In機能を使う上で開発効率をあげる上で重要だと考えています。
そこでSwiftUIを使ってFirbaseUIを表示する方法を考えました。
[サンプルコードをGitHub](https://github.com/FromF/FirebaseUI_SwiftUI)で公開しています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42735/ee6770e3-3cae-4af1-9e7f-182ad8420067.png" width=200>

# コードの解説
## Swift Package Managerで導入
FirebaseUI 12よりCocoapods以外にもSwift Package Managerに対応しました。
簡単な手順とSign-In方法別に導入するパッケージ一覧をまとめます。

### Step1.SPMのパッケージURLを指定する
File>Swift Packages>Add Package Dependency...を選択します。
Choose Package Repositoryというウィンドウがポップアップしますので、`https://github.com/firebase/FirebaseUI-iOS.git`と入力します。
![SPM01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42735/dd448432-43f2-0a00-8067-7ca15786e195.png)

### Step2.パッケージバージョン選択
Dependency Ruleを**Branch**にする。横にmasterとなっているか確認します。
次に、Add Packageを選択する。
![SPM02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42735/93d144d9-2890-1014-e345-38bc72eecb05.png)

### Step3.導入するパッケージの選択
Choose Package Products for FirebaseUI-iOSとウィンドウが出てきます。
ここでSign-In方法別に導入するパッケージを選択します。(主なパッケージとその内容は表を参照)
選択が終わったらAdd Packageを選択します。

| パッケージ名            | 内容                            | 必須/任意 |
| ----------------------- | ------------------------------- | --------- |
| FirebaseAnonymousAuthUI | 匿名ログイン                    | 任意      |
| FirebaseAuthUI          | FirebaseUIのコア                | **必須**  |
| FirebaseDatabaseUI      | Firebaseデータベース用のUI       | 対象外    |
| FirebaseEmailAuthUI     | Emailログイン                   | 任意      |
| FirebaseFacebookAuthUI  | Facebookログイン                | 任意      |
| FirebaseFirestoreUI     | Firestore（データベース）用のUI     | 対象外    |
| FirebaseGoogleAuthUI    | Googleログイン                  | 任意      |
| FirebaseOAuthUI         | Sign in with Apple, Twitterなど | 任意      |
| FirebasePhoneAuthUI     | 電話番号                        | 任意      |
| FirebaseStorageUI       | Cloud Storage用のUI            | 対象外    |

![SPM03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42735/c245cb61-2d64-631c-4d9b-899846a65226.png)

## 初期化について
Xcode12よりLifeCycleという項目が追加されSwiftUI App時にどのように書けばわからなかったで追加で調査しました。(Xcode13よりSwiftUIを選択すると自動的にLifeCycleがSwiftUI Appとなりますので選択肢は無くなりました。)
下記のようにすればUIKit App Delegate同等になります。参考にしてください。

```Swift:FirebaseUIAppApp.swift
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 ChatAPPApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
    var body: some Scene {
        WindowGroup {
            HomeView()
        }
    }
}
```

## FirebaseUIを表示するView
UIKit系のFirebaseUIを表示するために、`UIViewControllerRepresentable`を利用して表示します。
[サンプルコード](https://github.com/FromF/FirebaseUI_SwiftUI)では、`FirebaseAuthUIView.swift`に記述しました。

基本的には[リファレンスマニュアル](https://firebase.google.com/docs/auth/ios/firebaseui?hl=ja)通りの実装内容となっています。

また、Sign in with Appleが最近のFirebaseUIでも利用可能になっています。`authUI.providers`のArrayリストに`FUIOAuth.appleAuthProvider()`を追加する必要があります。

```Swift
        // サポートするログイン方法を構成
        let providers: [FUIAuthProvider] = [
            FUIGoogleAuth(authUI: authUI),
            FUIFacebookAuth(authUI: authUI),
            FUIOAuth.twitterAuthProvider(),
            FUIPhoneAuth(authUI:authUI),
            FUIOAuth.appleAuthProvider(),
        ]
        authUI.providers = providers
```

## SignIn状態の管理
SignIn状態を管理し表示をコントロールするためにObservationを使っています。
`AuthenticationManager`と命名しました。（ネーミングセンスが悪くてすみません）
コードは[リファレンスマニュアル-認証状態をリッスンする](https://firebase.google.com/docs/auth/ios/start#listen_for_authentication_state)を参考にしました。

## Googleログインでクラッシュする
Firebase公式ドキュメントの[Google ログインを実装する](https://firebase.google.com/docs/auth/ios/google-signin?hl=ja#implement_google_sign-in)の中にある「**1.Xcode プロジェクトにカスタム URL スキームを追加します。**」を手順を実施しカスタムURLスキームを設定してください。

# 最後に
FirebaseUIの実装例が少ないと感じています。
[リファレンスマニュアル](https://firebase.google.com/docs/auth/ios/firebaseui?hl=ja)通りといえばそうですが、サンプルプロジェクトがあると便利かと思い作成しました。
参考になれば幸いです。

## Cocoapodsの記述
SwiftPackageManagerに移行してきましたが、Cocoapodsの記述についてもAppendixとして残しておきます。

**pod 'FirebaseUI'** と記述してもいいのですが、利用するSin-In方法を個別に指定することができます。
個別に指定することによってビルド時間の短縮が期待できます。
**pod 'FirebaseUI/Auth'** は必須です。注意が必要です。

| podfileに記述する内容 | 内容 | 必須/任意 |
| ------------------------- | ------------------------------- | --------- |
| pod 'FirebaseUI/Auth' | FirebaseUIのコア | 必須 |
| pod 'FirebaseUI/Google' | Googleログイン | 任意 |
| pod 'FirebaseUI/Facebook' | Facebookログイン | 任意 |
| pod 'FirebaseUI/OAuth' | Sign in with Apple, Twitterなど | 任意 |
| pod 'FirebaseUI/Phone' | 電話番号 | 任意 |