【SwiftUI】FirebaseAuthのApple, Googleログインを簡単に実装しよう

Firebase Authを使ってアプリを開発するとき、アプリごとに毎回同じようなコードを書いていませんか？
今回、Firebase Auth関連の実装を簡単にするライブラリ、`FirebaseAuthEasier`を作成したので、ご紹介します！！
ぜひStarしてね！⭐️

https://github.com/sugijotaro/FirebaseAuthEasier

これを使うと、以下のイメージのように2行コードを書くだけで簡単にSign in with AppleとSign in with Googleを実装できます！これで開発爆速化間違いなし！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/0d256363-76c0-4408-87f0-dc80493602bc.png)

この記事では、この`FirebaseAuthEasier`の使い方やセットアップ方法をご紹介します！
以下、Firebaseのセットアップはできている前提で、Firebase Authの準備からセットアップ方法を解説します！

# 1. Firebase Authの準備

## 1-1. Firebaseコンソールでの準備
Firebaseのコンソールから`Authentication`タブを開き、`始める`をクリックしましょう
![名称未設定 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/78243fcd-e91a-492b-bd0f-c844ba9f8097.png)

## 1-2. Sign in with Appleの有効化
まず、ログインプロバイダ一覧から`Apple`を選択します
![名称未設定 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/c38f5223-7d8e-43c7-83ca-d61a65810e13.png)

ポップアップが表示されるので、`有効にする`のトグルをONにして、`保存`をクリックします
![名称未設定 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/320b2623-3036-4fb4-9e52-417f0d79b51a.png)

以下のスクリーンショットのようにAppleが追加されていれば完了です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/a95bfaa1-3efb-4126-9763-ac3fb2e277b4.png)

## 1-3. Sign in with Googleの有効化
またログインプロバイダの一覧画面を開き、今度は`Google`を選択します
![名称未設定 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/0f3ad301-7dd5-4340-8b84-a662208907fd.png)

表示されたポップアップの`有効にする`のトグルをONにして、必要な情報を埋めてから`保存`をクリックします。
ここでは、Sign in with Googleで表示されるこのアプリの名前と、サポートメールを設定する必要があります。
![名称未設定 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/e6687af2-ed82-42c9-a86b-ceeb09a7a00e.png)

保存できると、以下のようなポップアップが出ることがあります！これは、Sign in with Googleを新しく設定したことで、既に作成さている`GoogleService-Info.plist`が古くなってしまったので、更新してね！というポップアップです！
指示に従って、既にセットアップした`GoogleService-Info.plist`を、新しいものに置き換えましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/fa281c6f-49e9-4c89-bc20-8344403b677f.png)

最終的にこのように、AppleとGoogleのプロバイダが設定済みになっていれば、Firebaseコンソールでの作業は終了です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/396a7d72-31f4-42ba-a676-3cf5b328f9ed.png)

# 2. Xcodeでのセットアップ
次に、XcodeでFirebaseAuthEasierを使うための準備をしていきましょう！

## 2-1.パッケージをインストール
まずはパッケージをインストールしましょう

Xcodeの`File`タブから、`Add Package Dependencies...`を選択しましょう
![名称未設定 6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/20444e45-7ad3-4d92-94b4-6860698d9fe9.png)

するとこのような画面になるので、
↓こちらのURLをコピペして、`FirebaseAuthEasier`を探し、見つかったら`Add Package`を押しましょう！
```
https://github.com/sugijotaro/FirebaseAuthEasier.git
```
![名称未設定 7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/16775b31-95b1-45a3-8f06-03950d7e29be.png)

すると、どのTargetにPackageを追加するか聞かれるので、対象のアプリを選択し、`Add Package`を選択しましょう
![名称未設定 8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/c84ebab6-1ab9-40de-aa5b-2b1c6a6cdd6f.png)
これで`FirebaseAuthEasier`のパッケージを追加することができました！

## 2-2. Sign in with Appleを設定
アプリ内でSign in with Appleを使用するために、設定が必要です！

まず、以下の画像の通りに選択していき、`Signing & Capabilities`タブの中の`+ Capability`を押しましょう！
![名称未設定 10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/800a03ce-d312-4494-bbdb-f704c2a06742.jpeg)

するとポップアップが出るので、ここから`Sign in with Apple`を検索し、出てきたCapabilityをドラッグ&ドロップでアプリに組み込みましょう！
![ezgif-8262574c5f28fe.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/7d555f93-9bda-4927-b68e-af574a06dfad.gif)

これでSign in with Appleのセットアップは完了です

## 2-3. Sign in with Googleを設定
アプリ内でSign in with Googleを使用するために、設定が必要です！

まず、以下の画像のように、アプリ内にある`GoogleService-Info.plist`を開き、その中の`REVERSED_CLIENT_ID`の`Value`を探します
見つけたら、それをコピーしましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/76faaad8-0879-4914-9373-c58b0e4e4a3d.png)

次に、そのコピーした値をペーストする場所を探しましょう。
以下の画像を参考に、`Info`タブの`URL Types`の中身を開き、`+`ボタンを押してください。
![名称未設定 12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/0d2db37e-7735-459b-ac83-7356d98f3c8c.jpeg)

するとこのような画面になるので、右側の`URL Schemes`の部分に先ほどコピーした値をペーストしてください！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/17acc1f9-ad70-4740-9f0e-9b01a76bdcf0.png)

これでSign in with Googleのセットアップも完了です！

# 3. FirebaseAuthEasierを使う
セットアップお疲れ様でした！
ここまでできれば、あとは超簡単です！

## 3-1. 超簡単に使おう！
ログイン画面を使用したいところに以下のようにコードを追加します

```diff_swift
import SwiftUI
+ import FirebaseAuthEasier

struct ContentView: View {
    
    var body: some View {
+        FirebaseAuthView()
    }
}
```
すると、こんな感じで認証画面が出てきてくれます！嬉しい！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/0d256363-76c0-4408-87f0-dc80493602bc.png)
自動的にアプリのアイコンとアプリ名を持ってきて、表示してくれるよ！

## 3-2. カスタマイズして使おう！
ここまでで「一瞬でFirebase Authが使える！」ことが分かったと思いますが、
「自分のアプリに合わせて、もっと見た目や動きをこだわりたい」
そんな方のために、FirebaseAuthEasierのカスタマイズ術をまとめました！

### 3-2-1. 日本語で表示してほしい
まずはカスタマイズというより基本的な使い方ですが、、
「Sign in with Apple」などの文言を日本語などローカライズした言語で表示することができます！

`PROJECT`を選択し、`Info`のなかの`Localizations`を`Japanese`など任意の言語に設定すれば、日本語の表示にできます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/575df592-5c1e-4ad8-b834-9ba238b5dc95.png)

<details><summary>イメージ</summary>

![simulator_screenshot_7A7551EB-80F9-42A4-B49A-625C18DE9748.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/b42b05d1-16fb-447f-be20-d963ef381458.png)

</details>

### 3-2-2. サインイン画面をカスタマイズ

FirebaseAuthViewのイニシャライザ引数を活用すれば、見た目も機能もあなた好みに仕上げられます。

主要なカスタマイズ例: 

#### サインインプロバイダの種類をカスタマイズ

```swift
FirebaseAuthView(providers: [.apple]) //Appleのみ
FirebaseAuthView(providers: [.google]) //Googleのみ
FirebaseAuthView(providers: [.google, .apple]) //並び順を変える
```

#### ボタンの文言を「サインアップ」や「続ける」に
```swift
FirebaseAuthView(labelType: .signIn) //サインイン
FirebaseAuthView(labelType: .signUp) //登録
FirebaseAuthView(labelType: .continue) //続ける
```

#### 利用規約・プライバシーポリシーを表示したい

```swift
FirebaseAuthView(
    termsOfServiceURL: URL(string: "https://example.com/terms")!, //利用規約
    privacyPolicyURL: URL(string: "https://example.com/privacy")! //プライバシーポリシー
)
```

#### 画面上部を自分のデザインに差し替えたい

```swift
FirebaseAuthView {
    VStack {
        Text("MyAppへようこそ！")
        Image(systemName: "sparkles")
    }
}
```

#### サインイン開始や完了時にイベントを仕込みたい

```swift
FirebaseAuthView(
    onSignInStart: { provider in
        print("サインイン開始: \(provider)")
    },
    didSignIn: { result in
        switch result {
        case .success(let authData):
            // ログイン成功時の処理
        case .failure(let error):
            // エラー処理
        }
    }
)
```

#### いろいろまとめて使いたい時はこう！

```swift
import SwiftUI
import FirebaseAuthEasier

struct ContentView: View {
    var body: some View {
        FirebaseAuthView(
            providers: [.apple, .google],
            labelType: .signIn,
            termsOfServiceURL: URL(string: "apple.com")!,
            privacyPolicyURL: URL(string: "apple.com")!,
            onSignInStart: { provider in
                print("Sign-in started with provider: \(provider)")
            },
            didSignIn: { result in
                switch result {
                case .success(let authResult):
                    print("Sign-in successful")
                case .failure(let error):
                    print("Sign-in failed: \(error.localizedDescription)")
                }
            }
        ) {
            VStack {
                Image(systemName: "person.circle")
                    .imageScale(.large)
                    .foregroundStyle(.tint)
                Text("ようこそ！")
            }
        }
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/a0e99bde-d23a-40b4-a600-164ba60ab66b.png)

### 3-2-3. 認証状態に合わせて画面を切り替える

「ログインしている人はホーム画面、未ログインなら認証画面」といった切り替えもとても簡単です。
`FirebaseAuthEasier`ライブラリで提供している`FirebaseAuthService`を使えば、下記のような実装もすぐにできます。

```swift
import SwiftUI
import FirebaseAuth
import FirebaseAuthEasier

class AuthViewModel: ObservableObject {
    @Published var currentUser: FirebaseAuth.User? = nil
    private let authService = FirebaseAuthService()
    private var handle: AuthStateDidChangeListenerHandle?

    init() {
        handle = authService.addAuthStateDidChangeListener { [weak self] _, user in
            self?.currentUser = user
        }
    }
    deinit {
        if let handle = handle {
            authService.removeAuthStateDidChangeListener(handle)
        }
    }

    func signOut() {
        authService.signOut { _ in }
    }
}

struct ContentView: View {
    @StateObject private var viewModel = AuthViewModel()

    var body: some View {
        if viewModel.currentUser == nil {
            FirebaseAuthView()
        } else {
            VStack {
                Text("ログイン中です")
                Button("サインアウト") {
                    viewModel.signOut()
                }
            }
        }
    }
}
```

これで、ログインしていなければ`FirebaseAuthView()`を表示して、ログインされていれば他のViewを表示する実装ができます！


### 3-2-4. ボタン単体での利用・デザインも自由自在

「既存画面にサインインボタンだけ置きたい」「独自UIと並べたい」という場合は、SignInButtonコンポーネントの出番です！

```swift
import SwiftUI
import FirebaseAuthEasier

SignInButton(
    provider: .apple,
    buttonStyle: .black,
    labelStyle: .titleAndIcon,
    labelType: .signIn,
    cornerStyle: .radius(12),
    hasBorder: true
) {
    // ボタン押下時処理
}
```

色・角丸・アイコン・ラベル、すべて好みに合わせて調整できます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">え、素敵 <a href="https://t.co/CrzoM3xoSd">https://t.co/CrzoM3xoSd</a> <a href="https://t.co/mxqjy0bMoG">pic.twitter.com/mxqjy0bMoG</a></p>&mdash; わくわくさん (@sugijotaro) <a href="https://twitter.com/sugijotaro/status/1927355881651421221?ref_src=twsrc%5Etfw">May 27, 2025</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### 3-2-5. 直接APIでさらに細かい制御も可能

「匿名認証も使いたい」「再認証やアカウント削除もしたい」といった時は、FirebaseAuthServiceのメソッドを直接呼び出して活用できます。

```swift
let authService = FirebaseAuthService()

// 匿名サインイン
authService.signInAnonymously { result in
    // 結果に応じた処理
}

// サインアウト
authService.signOut { result in
    // 完了時の処理
}
```
その他詳細な使い方は、sampleプロジェクトを見てみてください！

<details>
<summary>より詳細なFirebaseAuthServiceのメソッド（例と使い方）</summary>


#### 認証状態リスナーの追加・削除

ユーザーのサインイン・サインアウト状態を監視したいとき
```swift
// 追加
let handle = authService.addAuthStateDidChangeListener { auth, user in
    if let user = user {
        print("Signed in as \(user.uid)")
    } else {
        print("Signed out")
    }
}
// 削除
authService.removeAuthStateDidChangeListener(handle)
```

#### Appleサインイン & Appleアカウントのリンク

```swift
// Appleサインイン
authService.startSignInWithApple { result in
    switch result {
    case .success(let authResult):
        print("Appleサインイン成功: \(authResult.user.uid)")
    case .failure(let error):
        print("Appleサインイン失敗: \(error)")
    }
}

// Appleアカウントを既存ユーザーにリンク
authService.startLinkWithApple { result in
    switch result {
    case .success(let authResult):
        print("Appleアカウントのリンク成功: \(authResult.user.uid)")
    case .failure(let error):
        print("Appleアカウントのリンク失敗: \(error)")
    }
}
```

#### Googleサインイン & Googleアカウントのリンク

Google認証の処理を行う場合、startSignInWithGoogleやstartLinkWithGoogleのpresentingViewControllerには、RootViewControllerを指定する必要があります。

```swift
// Googleサインイン
if let rootVC = getRootViewController() {
    authService.startSignInWithGoogle(presentingViewController: rootVC) { result in
        switch result {
        case .success(let authResult):
            print("Googleサインイン成功: \(authResult.user.uid)")
        case .failure(let error):
            print("Googleサインイン失敗: \(error)")
        }
    }
}

// Googleアカウントを既存ユーザーにリンク
if let rootVC = getRootViewController() {
    authService.startLinkWithGoogle(presentingViewController: rootVC) { result in
        switch result {
        case .success(let authResult):
            print("Googleアカウントのリンク成功: \(authResult.user.uid)")
        case .failure(let error):
            print("Googleアカウントのリンク失敗: \(error)")
        }
    }
}


// rootViewControllerの取得方法
func getRootViewController() -> UIViewController? {
    let scenes = UIApplication.shared.connectedScenes
    let windowScene = scenes.first as? UIWindowScene
    return windowScene?.keyWindow?.rootViewController
}
```

このようにして、Googleサインインやリンク処理時は
「rootViewControllerを取得 → presentingViewControllerとして渡す」
という実装を行ってください。


#### 再認証フロー（認証し直しが必要な操作時）
```swift
// 例：アカウント削除時や機密操作の直前に
authService.reauthenticateIfNeeded(
    presentingViewController: self,
    for: { completion in
        // ここに本来の操作を書く（例：user.deleteなど）
        completion(.success(()))
    },
    completion: { result in
        switch result {
        case .success:
            print("再認証→操作完了")
        case .failure(let error):
            print("再認証失敗: \(error)")
        }
    }
)
```

#### アカウント削除（再認証付き）

```swift
authService.deleteAccount(
    presentingViewController: self
) { result in
    switch result {
    case .success:
        print("アカウント削除完了")
    case .failure(let error):
        print("削除失敗: \(error)")
    }
}
```

#### 認証プロバイダのリンク（汎用）
```swift
let credential: AuthCredential = // 任意のプロバイダーのcredential
authService.linkCurrentUserWithCredential(credential) { result in
    switch result {
    case .success(let authResult):
        print("リンク成功")
    case .failure(let error):
        print("リンク失敗: \(error)")
    }
}
```

#### 任意の認証情報でサインイン

```swift
let credential: AuthCredential = // 任意のcredential
authService.signInWithCredential(credential) { result in
    switch result {
    case .success(let authResult):
        print("サインイン成功")
    case .failure(let error):
        print("サインイン失敗: \(error)")
    }
}
```

#### 現在のユーザーが持つプロバイダIDの一覧取得
```swift
if let user = Auth.auth().currentUser {
    let providerIDs = FirebaseAuthService.providerIDs(for: user)
    print(providerIDs) // [.apple, .google] など
}
```

そのほか、必要に応じてAPIを追加予定！
「このAPIほしい」「こういうケース対応したい」等リクエストはぜひGitHub Issueまでどうぞ！
</details>

# まとめ
`FirebaseAuthEasier`なら、「とりあえず導入」から「細かく作り込む」まで、どちらも超ラク＆超早いです！
SwiftUIらしい使い方ができるので、ぜひ使ってみてください！

もし「ここをもっとこうしたい」「このオプションって？」という質問やリクエストがあれば、
ぜひGitHubリポジトリまでどうぞ！

https://github.com/sugijotaro/FirebaseAuthEasier/