PR

UnityでFirebase Authenticationを使ってアカウント機能を付ける方法 SNSログイン対応

スポンサーリンク

対象プラットフォーム:Android / iOS / Windows(デスクトップ)
UnityでFirebase Authentication使ってアカウント登録・ログイン機能を付ける方法を紹介します。SNSログイン対応してます。


1. 概要と設計方針(短め)

  • 方針:クライアント(Unity)で各 SNS のネイティブログインを行い、取得したトークン(idToken / accessToken / identityToken)を Firebase の SignInWithCredentialAsync に渡して認証を完了する。
  • メール/パスワードは Firebase の API を直接使う。SNS は各ネイティブ SDK を使う(GoogleSignIn, Facebook SDK, Sign in with Apple プラグイン)。
  • Windows(デスクトップ)は Firebase Unity SDK の機能制限があるため、必要なら REST API を用いた代替案を用意する。
  • アカウントの衝突(同じメールで別プロバイダ)時は FetchSignInMethodsForEmailAsyncLinkWithCredentialAsync でリンクして UX を整える。

2. 必要な準備(Firebase コンソール、ダウンロード物、Unity 設定)

スポンサーリンク

Firebase コンソールでやること(全プラットフォーム)

  1. Firebase プロジェクトを作成。
  2. AuthenticationSign-in method で以下を有効化:
    • Email/Password
    • Google
    • Facebook
    • Apple(iOS 用)
  3. Android/iOS アプリをそれぞれ追加して、google-services.json(Android)と GoogleService-Info.plist(iOS)をダウンロードする。これらは後で Unity の Assets/ 配下に置きます。

重要:Android は SHA-1 / SHA-256 を Firebase に登録する必要があります(開発用 keystore / リリース keystore / Play App Signing の署名など)。Facebook は Android の Key Hash、iOS は Apple Developer で Sign in with Apple を有効にする必要があります。これらは後述します。

Unity プロジェクト側(準備)

  • Unity 推奨バージョン:2020 LTS 以降(推奨は 2021.3 LTS など)。ただし Firebase のサポート範囲を確認して使ってください。
  • 新規プロジェクトを作成(3D または URP/Universal などお好みで)。
  • Assets/Plugins/ フォルダを用意してプラグインを格納すると管理しやすい。
  • Player Settings:package name(Bundle Identifier)を Firebase コンソールで登録したものと一致させる。Android/iOS で別々の ID を使う場合はそれぞれ登録済みであること。

3. 推奨プロジェクト構成(例)

Assets/
  Scripts/
    Auth/
      FirebaseAuthManager.cs
      EmailAuth.cs
      GoogleAuthHandler.cs
      FacebookAuthHandler.cs
      AppleAuthHandler.cs
      AuthUIController.cs
      ProfileService.cs
      AuthErrorHandler.cs
      Utils.cs
  Plugins/
    Firebase/   <- Firebase SDK をここに
    GoogleSignIn/
    FacebookSDK/
    AppleSignIn/
  Scenes/
    AuthScene.unity
    MainScene.unity
  Resources/
  Prefabs/
    AuthUI.prefab

4. フルコード(Unity C# スクリプト一式)

使い方:以下のファイルを Assets/Scripts/Auth/ に配置してください。コメントで使い方を併記しています。各ハンドラはプラットフォームコンパイル定義(#if UNITY_ANDROID 等)を使っており、エディタではダミー挙動を返すようにしています(テストのため)。


FirebaseAuthManager.cs

// FirebaseAuthManager.cs
using System;
using UnityEngine;
using Firebase;
using Firebase.Auth;
using System.Threading.Tasks;

public class FirebaseAuthManager : MonoBehaviour
{
    public static FirebaseAuthManager Instance { get; private set; }
    public FirebaseAuth Auth { get; private set; }
    public FirebaseUser CurrentUser => Auth?.CurrentUser;

    void Awake()
    {
        if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); }
        else { Destroy(gameObject); return; }

        InitializeFirebase();
    }

    void InitializeFirebase()
    {
        FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
        {
            var status = task.Result;
            if (status == DependencyStatus.Available)
            {
                Auth = FirebaseAuth.DefaultInstance;
                Debug.Log("[FirebaseAuthManager] Firebase initialized. CurrentUser: " + (Auth.CurrentUser != null ? Auth.CurrentUser.Email : "none"));
            }
            else
            {
                Debug.LogError("[FirebaseAuthManager] Could not resolve all Firebase dependencies: " + status);
            }
        });
    }

    // サインアウト(全プロバイダ用)
    public void SignOut()
    {
        if (Auth != null) Auth.SignOut();
        Debug.Log("[FirebaseAuthManager] Signed out local user.");
    }

    // カスタムトークンでのサインイン(サーバーで作成したトークンを使う場合)
    public void SignInWithCustomToken(string token)
    {
        Auth.SignInWithCustomTokenAsync(token).ContinueWith(t =>
        {
            if (t.IsFaulted) Debug.LogError("[FirebaseAuthManager] SignInWithCustomToken failed: " + t.Exception);
            else Debug.Log("[FirebaseAuthManager] Signed in with custom token: " + t.Result.Email);
        });
    }
}

EmailAuth.cs(メール登録・ログイン・パスワードリセット)

// EmailAuth.cs
using System;
using UnityEngine;
using Firebase.Auth;

public class EmailAuth : MonoBehaviour
{
    FirebaseAuth auth => FirebaseAuthManager.Instance.Auth;

    public void Register(string email, string password, Action<FirebaseUser, string> callback)
    {
        auth.CreateUserWithEmailAndPasswordAsync(email, password).ContinueWith(task =>
        {
            if (task.IsCanceled || task.IsFaulted)
            {
                var msg = AuthErrorHandler.FormatAggregateException(task.Exception);
                Debug.LogError("[EmailAuth] Register failed: " + msg);
                callback?.Invoke(null, msg);
                return;
            }
            var newUser = task.Result;
            Debug.Log("[EmailAuth] Registered: " + newUser.Email);
            callback?.Invoke(newUser, null);
        });
    }

    public void Login(string email, string password, Action<FirebaseUser, string> callback)
    {
        auth.SignInWithEmailAndPasswordAsync(email, password).ContinueWith(task =>
        {
            if (task.IsCanceled || task.IsFaulted)
            {
                var msg = AuthErrorHandler.FormatAggregateException(task.Exception);
                Debug.LogError("[EmailAuth] Login failed: " + msg);
                callback?.Invoke(null, msg);
                return;
            }
            var user = task.Result;
            Debug.Log("[EmailAuth] Logged in: " + user.Email);
            callback?.Invoke(user, null);
        });
    }

    public void SendPasswordReset(string email, Action<string> callback)
    {
        auth.SendPasswordResetEmailAsync(email).ContinueWith(task =>
        {
            if (task.IsFaulted)
            {
                var msg = AuthErrorHandler.FormatAggregateException(task.Exception);
                Debug.LogError("[EmailAuth] PasswordReset failed: " + msg);
                callback?.Invoke(msg);
                return;
            }
            Debug.Log("[EmailAuth] Password reset email sent.");
            callback?.Invoke(null);
        });
    }
}

GoogleAuthHandler.cs(Google Sign-In → Firebase)

:このファイルは Google Sign-In プラグイン(またはネイティブラッパー)を使う前提のコード例です。プラグインの API に合わせて SignInWithGoogleNative() 部分を実装してください。エディタ時・Windows はテスト用のダミー処理があります。

// GoogleAuthHandler.cs
using UnityEngine;
using Firebase.Auth;
using System;

public class GoogleAuthHandler : MonoBehaviour
{
    FirebaseAuth auth => FirebaseAuthManager.Instance.Auth;

    // プラグイン固有の SignIn 呼び出しをここに書く
    public void SignInWithGoogle(Action<FirebaseUser, string> callback)
    {
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
        // エディタ/Windows デバッグ用: ダミーアカウントの作成(開発時のみ)
        Debug.Log("[GoogleAuthHandler] Editor/Windows dummy google sign-in.");
        // ここは実際にはトークンを取得できないため、テスト用の匿名ログインなどにする
        auth.SignInAnonymouslyAsync().ContinueWith(t => {
            if (t.IsFaulted) callback?.Invoke(null, AuthErrorHandler.FormatAggregateException(t.Exception));
            else callback?.Invoke(t.Result, null);
        });
#else
        // 実機: Google Sign-In プラグインを起動
        SignInWithGoogleNative((idToken, accessToken, error) =>
        {
            if (!string.IsNullOrEmpty(error))
            {
                callback?.Invoke(null, error);
                return;
            }
            var credential = GoogleAuthProvider.GetCredential(idToken, accessToken);
            auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
            {
                if (task.IsFaulted || task.IsCanceled)
                {
                    var msg = AuthErrorHandler.FormatAggregateException(task.Exception);
                    Debug.LogError("[GoogleAuthHandler] Firebase sign-in failed: " + msg);
                    callback?.Invoke(null, msg);
                    return;
                }
                var user = task.Result;
                Debug.Log("[GoogleAuthHandler] Signed in with Google: " + user.Email);
                callback?.Invoke(user, null);
            });
        });
#endif
    }

    // ここをプラグイン API に合わせて実装してください
    private void SignInWithGoogleNative(Action<string, string, string> cb)
    {
        // idToken, accessToken, error
        // 例: GoogleSignIn.DefaultInstance.SignIn() の結果から idToken を cb に渡す
        cb?.Invoke(null, null, "Not implemented: Replace SignInWithGoogleNative with plugin call.");
    }
}

FacebookAuthHandler.cs(Facebook SDK → Firebase)

// FacebookAuthHandler.cs
using UnityEngine;
using Firebase.Auth;
using System;
using System.Collections.Generic;
#if FACEBOOK_SDK
using Facebook.Unity;
#endif

public class FacebookAuthHandler : MonoBehaviour
{
    FirebaseAuth auth => FirebaseAuthManager.Instance.Auth;

    public void LoginWithFacebook(Action<FirebaseUser, string> callback)
    {
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
        // Editor/Windows fallback
        Debug.Log("[FacebookAuthHandler] Editor/Windows: falling back to anonymous login.");
        auth.SignInAnonymouslyAsync().ContinueWith(t =>
        {
            if (t.IsFaulted) callback?.Invoke(null, AuthErrorHandler.FormatAggregateException(t.Exception));
            else callback?.Invoke(t.Result, null);
        });
#else
#if FACEBOOK_SDK
        if (!FB.IsInitialized)
        {
            FB.Init(() => {
                FB.ActivateApp();
                ContinueFBLogin(callback);
            });
            return;
        }
        ContinueFBLogin(callback);
#else
        callback?.Invoke(null, "Facebook SDK not imported. Define FACEBOOK_SDK and install Facebook Unity SDK.");
#endif
#endif
    }

#if FACEBOOK_SDK
    void ContinueFBLogin(Action<FirebaseUser, string> callback)
    {
        var perms = new List<string>() { "public_profile", "email" };
        FB.LogInWithReadPermissions(perms, result =>
        {
            if (result == null || !FB.IsLoggedIn)
            {
                callback?.Invoke(null, "Facebook login cancelled or failed.");
                return;
            }
            string accessToken = AccessToken.CurrentAccessToken.TokenString;
            var credential = FacebookAuthProvider.GetCredential(accessToken);
            auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
            {
                if (task.IsFaulted) callback?.Invoke(null, AuthErrorHandler.FormatAggregateException(task.Exception));
                else callback?.Invoke(task.Result, null);
            });
        });
    }
#endif
}

AppleAuthHandler.cs(Sign in with Apple → Firebase)

重要:iOS(実機)で Sign in with Apple を使う場合は Unity 用の Apple SignIn プラグインを導入するのが現実的です。ここでは nonce 生成と Firebase への渡し方を示します。プラグイン API に合わせて SignInWithAppleNative() を実装してください。

// AppleAuthHandler.cs
using System;
using UnityEngine;
using Firebase.Auth;

public class AppleAuthHandler : MonoBehaviour
{
    FirebaseAuth auth => FirebaseAuthManager.Instance.Auth;

    public void SignInWithApple(Action<FirebaseUser, string> callback)
    {
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
        // Editor/Windows: fallback
        Debug.Log("[AppleAuthHandler] Editor/Windows fallback to anonymous.");
        auth.SignInAnonymouslyAsync().ContinueWith(t =>
        {
            if (t.IsFaulted) callback?.Invoke(null, AuthErrorHandler.FormatAggregateException(t.Exception));
            else callback?.Invoke(t.Result, null);
        });
#else
        // iOS 実機: nonce を作ってネイティブプラグインに渡す
        string rawNonce = Utils.GenerateNonce();
        string hashed = Utils.Sha256(rawNonce);
        SignInWithAppleNative(hashed, (identityToken, error) =>
        {
            if (!string.IsNullOrEmpty(error))
            {
                callback?.Invoke(null, error);
                return;
            }
            // identityToken と rawNonce(ハッシュではなく**生の**rawNonce)を Firebase に渡す
            var credential = OAuthProvider.GetCredential("apple.com", identityToken, rawNonce);
            auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
            {
                if (task.IsFaulted) callback?.Invoke(null, AuthErrorHandler.FormatAggregateException(task.Exception));
                else callback?.Invoke(task.Result, null);
            });
        });
#endif
    }

    // プラグインの呼び出しに合わせて実装
    void SignInWithAppleNative(string hashedNonce, Action<string, string> cb)
    {
        cb?.Invoke(null, "Not implemented: replace with Sign in with Apple plugin call.");
    }
}

AuthUIController.cs(UI とバリデーションの例)

// AuthUIController.cs
using UnityEngine;
using UnityEngine.UI;
using System;

public class AuthUIController : MonoBehaviour
{
    [Header("Email")]
    public InputField emailInput;
    public InputField passwordInput;
    public Button emailRegisterButton;
    public Button emailLoginButton;

    [Header("Social")]
    public Button googleButton;
    public Button facebookButton;
    public Button appleButton;

    [Header("Status")]
    public Text statusText;

    EmailAuth emailAuth;
    GoogleAuthHandler googleAuth;
    FacebookAuthHandler facebookAuth;
    AppleAuthHandler appleAuth;

    void Awake()
    {
        emailAuth = GetComponent<EmailAuth>() ?? gameObject.AddComponent<EmailAuth>();
        googleAuth = GetComponent<GoogleAuthHandler>() ?? gameObject.AddComponent<GoogleAuthHandler>();
        facebookAuth = GetComponent<FacebookAuthHandler>() ?? gameObject.AddComponent<FacebookAuthHandler>();
        appleAuth = GetComponent<AppleAuthHandler>() ?? gameObject.AddComponent<AppleAuthHandler>();

        emailRegisterButton.onClick.AddListener(() => OnRegisterClicked());
        emailLoginButton.onClick.AddListener(() => OnLoginClicked());
        googleButton.onClick.AddListener(() => OnGoogleClicked());
        facebookButton.onClick.AddListener(() => OnFacebookClicked());
        appleButton.onClick.AddListener(() => OnAppleClicked());
    }

    void SetStatus(string s) { statusText.text = s; Debug.Log("[AuthUI] " + s); }

    void OnRegisterClicked()
    {
        var email = emailInput.text.Trim();
        var password = passwordInput.text;
        var err = ValidateEmailPassword(email, password);
        if (err != null) { SetStatus(err); return; }
        SetStatus("Registering...");
        emailAuth.Register(email, password, (user, error) => {
            UnityMainThreadDispatcher.Instance().Enqueue(() => {
                if (!string.IsNullOrEmpty(error)) SetStatus("Register error: " + error);
                else SetStatus("Registered: " + user.Email);
            });
        });
    }

    void OnLoginClicked()
    {
        var email = emailInput.text.Trim();
        var password = passwordInput.text;
        var err = ValidateEmailPassword(email, password);
        if (err != null) { SetStatus(err); return; }
        SetStatus("Signing in...");
        emailAuth.Login(email, password, (user, error) => {
            UnityMainThreadDispatcher.Instance().Enqueue(() => {
                if (!string.IsNullOrEmpty(error)) SetStatus("Login error: " + error);
                else SetStatus("Signed in: " + user.Email);
            });
        });
    }

    void OnGoogleClicked()
    {
        SetStatus("Google sign-in...");
        googleAuth.SignInWithGoogle((user, error) => {
            UnityMainThreadDispatcher.Instance().Enqueue(() => {
                if (!string.IsNullOrEmpty(error)) SetStatus("Google error: " + error);
                else SetStatus("Google signed in: " + user.Email);
            });
        });
    }

    void OnFacebookClicked()
    {
        SetStatus("Facebook sign-in...");
        facebookAuth.LoginWithFacebook((user, error) => {
            UnityMainThreadDispatcher.Instance().Enqueue(() => {
                if (!string.IsNullOrEmpty(error)) SetStatus("Facebook error: " + error);
                else SetStatus("Facebook signed in: " + user.Email);
            });
        });
    }

    void OnAppleClicked()
    {
        SetStatus("Apple sign-in...");
        appleAuth.SignInWithApple((user, error) => {
            UnityMainThreadDispatcher.Instance().Enqueue(() => {
                if (!string.IsNullOrEmpty(error)) SetStatus("Apple error: " + error);
                else SetStatus("Apple signed in: " + user.Email);
            });
        });
    }

    string ValidateEmailPassword(string email, string password)
    {
        if (string.IsNullOrEmpty(email) || !email.Contains("@")) return "Invalid email.";
        if (string.IsNullOrEmpty(password) || password.Length < 6) return "Password must be 6+ chars.";
        return null;
    }
}

注:UnityMainThreadDispatcher は非同期コールバックを UI スレッドで実行するための簡易ユーティリティです。Asset Store 等で入手するか簡易実装を用意してください(付録参照)。


ProfileService.cs(ユーザープロフィール保存の例:Firestore を仮定)

// ProfileService.cs
using UnityEngine;
using Firebase.Firestore;
using System.Threading.Tasks;

public class ProfileService : MonoBehaviour
{
    FirebaseFirestore db => FirebaseFirestore.DefaultInstance;

    public async Task SaveProfileAsync(string uid, string email, string displayName = null, string photoUrl = null)
    {
        var doc = new DocumentReference(db, $"users/{uid}");
        var data = new System.Collections.Generic.Dictionary<string, object>
        {
            { "email", email },
            { "displayName", displayName ?? "" },
            { "photoUrl", photoUrl ?? "" },
            { "updatedAt", Timestamp.GetCurrentTimestamp() }
        };
        await doc.SetAsync(data, SetOptions.MergeAll);
        Debug.Log("[ProfileService] Profile saved for: " + uid);
    }
}

AuthErrorHandler.cs(エラー解析)

// AuthErrorHandler.cs
using System;
using Firebase;
using Firebase.Auth;
using System.Linq;

public static class AuthErrorHandler
{
    public static string FormatAggregateException(AggregateException agg)
    {
        if (agg == null) return "Unknown error";
        var flat = agg.Flatten();
        var inner = flat.InnerExceptions.FirstOrDefault();
        if (inner is FirebaseException fex)
        {
            return $"Firebase Error ({fex.ErrorCode}): {fex.Message}";
        }
        return inner?.Message ?? agg.Message;
    }
}

Utils.cs(nonce / SHA256 / keyhash helper)

// Utils.cs
using System;
using System.Security.Cryptography;
using System.Text;

public static class Utils
{
    private const string CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    public static string GenerateNonce(int length = 32)
    {
        var sb = new StringBuilder();
        using (var rng = RandomNumberGenerator.Create())
        {
            var buf = new byte[1];
            for (int i = 0; i < length; i++)
            {
                rng.GetBytes(buf);
                sb.Append(CHARSET[buf[0] % CHARSET.Length]);
            }
        }
        return sb.ToString();
    }

    public static string Sha256(string input)
    {
        using (var sha = SHA256.Create())
        {
            var bytes = Encoding.UTF8.GetBytes(input);
            var hash = sha.ComputeHash(bytes);
            var sb = new StringBuilder();
            foreach (var b in hash) sb.AppendFormat("{0:x2}", b);
            return sb.ToString();
        }
    }
}

5. Unity シーン & UI の作り方(スクリーン構成)

  • シーン名:AuthScene.unity
  • Canvas:AuthCanvas(画面中央にログイン UI)
    • InputField:EmailInput(プレースホルダ “Email”)
    • InputField:PasswordInput(Input Type = Password)
    • Button:RegisterButton(ラベル “Register”)
    • Button:LoginButton(ラベル “Login”)
    • Button:GoogleButton(ラベル “Google サインイン”)
    • Button:FacebookButton(ラベル “Facebook ログイン”)
    • Button:AppleButton(ラベル “Sign in with Apple” — iOS のみ)
    • Text:StatusText(ログ出力表示用)
  • AuthUIController を Canvas にアタッチし、各フィールドを紐づける。
  • FirebaseAuthManager を別 GameObject(例:FirebaseManager)としてシーンに追加しておく(DontDestroyOnLoad によりアプリ起動から常駐)。

6. プラグイン導入手順(概要)

Firebase Unity SDK

  1. Firebase の公式ページから Unity SDK をダウンロード。
  2. FirebaseAuth.unitypackage / FirebaseFirestore.unitypackage 等、必要なパッケージを Unity にインポート。
  3. Assets/Plugins/Android / Assets/Plugins/iOS を生成して SDK のファイルが配置されるのを確認。
  4. External Dependency Manager(Play Services Resolver)が入っていることを確認し、依存解決を実行(メニューから Assets > External Dependency Manager > Android Resolver > Resolve)。

Google Sign-In

  • Android/iOS 向けに Google Sign-In プラグインを導入(GoogleSignIn Unity plugin や、Google Play Games plugin など)。プラグインにより API が異なるため、GoogleAuthHandler.SignInWithGoogleNative をプラグインの呼び出しに書き換える。

Facebook SDK

  • Facebook for Unity SDK をダウンロードしてインポート。インポート後 FB.Init() が使えるようになります。FacebookAuthHandler 内に #if FACEBOOK_SDK を入れておくと便利(定義は Scripting Define Symbols に追加)。

Sign in with Apple

  • Unity 用 Sign in with Apple プラグイン(Asset Store や GitHub)を導入。プラグインの API に合わせて AppleAuthHandler.SignInWithAppleNative を実装。iOS 側で capability を有効にする必要あり。

各プラグインはバージョン差やセットアップ手順があるため、必ず公式 README を確認してください。プラグイン導入後に Android の Gradle / iOS の Xcode プロジェクトが自動で編集されます。


7. Android ビルド手順(キーストア、SHA登録、Gradle 設定)

7.1 キーストア生成(開発用)

keytool -genkey -v -keystore debug.keystore -alias mykey -keyalg RSA -keysize 2048 -validity 10000

(Unity の Player Settings > Publishing Settings で keystore を管理することを推奨します。開発用は ~/.android/debug.keystore を使うことが多い。)

7.2 SHA-1 / SHA-256 取得

# Windows
keytool -list -v -keystore <path-to-keystore> -alias <alias> -storepass <password>
# macOS / Linux 同様

keytool の出力に SHA1 と SHA256 が出るので、Firebase コンソールの Android アプリ設定で追加してください(開発用・リリース用・Play App Signing の署名をそれぞれ登録)。

7.3 google-services.json の配置

ダウンロードした google-services.jsonAssets に置く(通常は Assets/Plugins/Android に置かれても OK)。Unity の Android Resolver が Gradle に自動で反映します。

7.4 AndroidManifest / ProGuard

  • Facebook SDK や GoogleSignIn が必要とする権限や activity を AndroidManifest に追加する必要があります。プラグインが生成する場合が多いですが、手動で追加する場合は Assets/Plugins/Android/AndroidManifest.xml を作って統合してください。
  • ProGuard を使う場合は SDK のドキュメントに従った例外ルールを追加。

7.5 Play App Signing(公開時)

  • Google Play にアップロードする場合、Play App Signing の署名が本番で使われます。Play Console が保持する署名の SHA を Firebase に登録しないと Google ログインが本番で失敗することがあります。必ず Play Console で署名を確認し、Firebase に登録してください。

8. iOS ビルド手順(plist、URL Scheme、Xcode 設定、Capabilities)

8.1 GoogleService-Info.plist の配置

  • GoogleService-Info.plistAssets/ に置くと、Unity の iOS ビルドで自動的に Xcode プロジェクトに含まれます。ビルド後に Xcode 側で plist が存在するか確認してください。

8.2 URL Scheme(REVERSED_CLIENT_ID)

  • GoogleService-Info.plist に含まれる REVERSED_CLIENT_ID を Xcode の InfoURL Types に自動で追加するか、手動で設定してください。これがないと Google Sign-In が動作しません。

8.3 Sign in with Apple(Capability)

  • Xcode の Targets → Signing & Capabilities → + Capability から Sign In with Apple を追加。Apple Developer にて App ID の Sign in with Apple を有効にしておく必要があります。

8.4 Other Linker Flags / Frameworks

  • プラグインに従って Other Linker Flags や必要な frameworks(AuthenticationServices など)を追加してください。

9. Windows(デスクトップ)での運用方法(制約と REST API フォールバック)

Unity エディタや Windows スタンドアロンで動かす際、Firebase Unity SDK の一部機能が制限されることがあります。特に SNS のネイティブ SDK はモバイル向けのためそのまま動かないケースが多いです。

9.1 オプション A:エディタ/Windows は「テスト専用」にする

  • 開発中は Editor で匿名ログインやメールログインで動作確認、SNS は実機で検証する。

9.2 オプション B:REST API を使う(Windows 実運用する場合)

Firebase の Auth は REST API を提供しているので、Windows クライアントから REST で認証(メール/パスワード、カスタムトークン)を実装できます。SNS の OAuth はクライアントで行い、トークンをサーバー経由で Firebase に紐付ける(セキュア)方法が現実的です。

例:メール/パスワード via REST

POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[API_KEY]
Body JSON:

{
  "email": "user@example.com",
  "password": "password",
  "returnSecureToken": true
}

戻り値に idToken が返る。クライアントはこの idToken をサーバーへ送って検証するか、セッションとして扱います。

REST 経由の実装はセキュリティ設計(API キー管理・TLS・CORS 等)を慎重に行ってください。特に API キーはクライアントから見えるため、重要操作はサーバー側で検証することをおすすめします。


10. サーバー側ワークフロー(Node.js でのカスタムトークン生成例)

OAuth を自前サーバーで検証して Firebase カスタムトークンを発行したい場合(例:デスクトップで OAuth を行い安全に Firebase にサインインさせたい)に使えます。

Node.js(firebase-admin)でのカスタムトークン発行例

// server.js(Node.js)
const admin = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

// 任意の uid(例:Google の sub)でカスタムトークン発行
app.post('/createCustomToken', async (req, res) => {
  const { uid } = req.body;
  try {
    const token = await admin.auth().createCustomToken(uid);
    res.json({ token });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

クライアントはこの token を受け取り FirebaseAuthManager.SignInWithCustomToken(token) でサインインできます。

サーバー側で OAuth トークン(Google / Facebook / Apple のトークン)を検証してから Firebase Admin で createCustomToken() を行えば、デスクトップクライアントでも安全に Firebase ユーザーを作成できます。


11. テスト & デバッグ術(ログ・よくあるエラー対処)

共通の確認ポイント

  • Firebase の google-services.json / GoogleService-Info.plist が正しいアプリに紐づいているか。
  • Android の package name / iOS の Bundle ID と Firebase に登録した値が一致しているか。
  • Android の SHA-1 が Firebase に登録されているか(特に Google ログイン)。
  • Facebook の Key Hash(Android)を Facebook Developers コンソールに登録しているか。
  • Sign in with Apple は Apple Developer と Xcode 側の Capability が一致しているか。

よくあるエラーと対策(抜粋)

  • invalid client / DEVELOPER_ERROR(Google Sign-In) → SHA-1 / OAuth クライアントの設定が間違い。
  • Invalid key hash(Facebook) → Key Hash が正しく登録されていない(デバッグキー / リリースキーの差)。
  • AccountExistsWithDifferentCredential → 同じメールで別プロバイダのアカウントが存在。FetchSignInMethodsForEmailAsync で手順を説明してリンク。
  • identityToken / nonce 関連エラー(Apple) → rawNonce の SHA256 を Apple 側に渡し、返却される identityToken と rawNonce 生値を Firebase に渡すこと。

ログ取り

  • Android:adb logcatFirebaseAuth / Unity のログを監視。
  • iOS:Xcode のコンソールでログ確認。
  • Unity Editor:ConsoleDebug.LogUnityMainThreadDispatcher を使って UI 更新時のログを管理。

12. リリース前チェックリスト(最終確認)

共通

  • Firebase の Authentication > Sign-in method で使う方法が有効化済みか。
  • 全プラットフォームで google-services.json / GoogleService-Info.plist を正しく配置しているか。
  • アプリのプライバシーポリシーを用意し、必要な権限と用途を記載しているか(Facebook, Apple のポリシー対応)。

Android

  • 開発用・リリース用 keystore の SHA-1 / SHA-256 を Firebase に登録。
  • Facebook の Key Hash を登録。
  • ProGuard/Minify を使うなら必要な keep 設定を追加。
  • Play App Signing を使う場合は Play Console の署名 SHA を Firebase に登録。

iOS

  • Xcode の Signing & Capabilities が正しく設定されているか(Team, Provisioning Profile)。
  • Sign in with Apple を利用する場合は App ID に機能を追加し、Xcode の Capability をオンにしているか。
  • GoogleService-Info.plist と URL Scheme が正しく Xcode に含まれているか。

Windows

  • デスクトップで Firebase の機能制限を想定しているか(REST / カスタムトークンでの補完)。
  • API キー・サーバー側の検証フローを整備しているか(重要操作はサーバーで検証)。

13. 付録:重要コマンド一覧(keytool / openssl / adb)

SHA-1 / SHA-256 の取得(debug keystore 例)

# Windows / macOS / Linux
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

Facebook Key Hash の生成(例)

# Windows / macOS
keytool -exportcert -alias <alias> -keystore <keystore> | openssl sha1 -binary | openssl base64

<keystore> に debug.keystore などを指定。openssl が必要)

adb logcat(Android ログ)

adb logcat -s Unity ActivityManager FirebaseAuth Firebase
# または全ログ: adb logcat

14. 最後に(まとめ)

ここまでで、メール認証 + Google / Facebook / Apple を Unity で扱うためのフルコードと、Android / iOS / Windows 各プラットフォームのビルド手順・注意点・デバッグ法・サーバー側補完の方法まで網羅しました。実務でハマるポイント(SHA / Key Hash / nonce / Play App Signing 等)を重点的に扱っています。

スポンサーリンク
タイトルとURLをコピーしました