
Unity+Firebase+Googleでログイン機能を実装する
-
2022年12月8日
cocone connectでクライアントエンジニアをしている田中です。
ログイン機能を実装する際にGoogle,Twitter,Instagramアカウントとの連携を行いました。
長くなるので今回はFirebaseとGoogle連携について要点のみ共有させていただければと思います。
※FirebaseやGoogleのサービス登録は済んでいる前提となります。
シーケンス図
使用するSDK
unitypackageが欲しい場合は以下を参照してください。
https://github.com/googlesamples/google-signin-unity/pull/126#issuecomment-702019117
インストールの注意点
依存関係パッケージ(External Dependency Manager)が上記2つのパッケージに入っているので、firebase-unity-sdkに内包されたもののみインストールしてください。
google-signin-unityはバージョンが古いので両方いれると重複エラーが発生します。
注意点
- FirebaseSDKとUnityバージョンは依存関係にあるので、うまくいかない場合はFirebaseSDKのバージョンを変える必要があります。
- google-signin-unityは公式サポートが終了しているので、フォークされたものを使用します。
- Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xmlの15行目のversionを5.0.2で固定します。
- cocoapodsはgem製を使用します。
-
sudo gem install cocoapods -n /usr/local/bin
-
実装例
using UnityEngine;
using System.Threading.Tasks;
using Google;
using UniRx;
public class FirebaseManager
{
public static readonly string GOOGLE_CLIENT_ID = "クライアントID";
static FirebaseManager _fm = new FirebaseManager();
// Auth.CurrentUserに認証情報
public Firebase.Auth.FirebaseAuth Auth { get; private set; }
// Android向け 最新のGooglePlay開発者サービスアプリがインストールされているかチェックに使用する
#if UNITY_ANDROID && !UNITY_EDITOR
Firebase.DependencyStatus _dependencyStatus = Firebase.DependencyStatus.UnavailableOther;
#endif
public static FirebaseManager Instance()
{
return _fm;
}
/// <summary>
/// Google SignIn、Firebaseの初期化
/// </summary>
public void Init()
{
#if !UNITY_EDITOR
StartWithSignInGoogle();
#endif
#if UNITY_ANDROID && !UNITY_EDITOR
// GooglePlay開発者サービスアプリがインストールされているかチェックする
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
{
_dependencyStatus = task.Result;
if (_dependencyStatus == Firebase.DependencyStatus.Available)
{
// Firebase認証の初期化処理
Auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
Debug.Log("Setting up Firebase Auth");
}
else
{
Debug.LogError("Could not resolve all Firebase dependencies: " + _dependencyStatus);
}
});
#elif UNITY_IOS && !UNITY_EDITOR
Auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
#endif
}
/// <summary>
/// Google SignInの設定
/// </summary>
private void StartWithSignInGoogle()
{
GoogleSignIn.Configuration = new GoogleSignInConfiguration
{
RequestIdToken = true,
// Copy this value from the google-service.json file.
// oauth_client with type == 3
RequestEmail = true,
WebClientId = GOOGLE_CLIENT_ID
};
}
/// <summary>
/// Google認証
/// </summary>
public void SignInGoogle()
{
GoogleSignIn.DefaultInstance.SignIn().ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("GoogleSignIn was canceled.");
}
else if (task.IsFaulted)
{
Debug.LogError("GoogleSignIn was error.");
}
else
{
Firebase.Auth.Credential credential = Firebase.Auth.GoogleAuthProvider.GetCredential(((Task<GoogleSignInUser>)task).Result.IdToken, null);
Auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("SignInWithCredentialAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("SignInWithCredentialAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
SignUpServerWithFirebaseToken(newUser);
});
}
});
}
/// <summary>
/// FirebaseのIDトークンを更新してサーバーにサインアップorサインインする
/// </summary>
/// <param name="user">Firebase認証で取得できる認証情報</param>
void SignUpServerWithFirebaseToken(Firebase.Auth.FirebaseUser user)
{
user.TokenAsync(true).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("TokenAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("TokenAsync encountered an error: " + task.Exception);
return;
}
string token = task.Result;
// メインスレッドに戻す
MainThreadDispatcher.Post(_ => /*tokenを使用してログイン*/Debug.Log(token), null);
});
}
/// <summary>
/// IDトークンの更新を行う
/// </summary>
/// <remarks>
/// CurrentUserに更新トークンがあり、そこからIDトークンを取得できる(IDトークンの期限は1時間)
/// CurrentUserは一度認証されるとローカル端末に保存されて永続化されている
/// </remarks>
public void UpdateToken()
{
Auth.CurrentUser.TokenAsync(true).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("TokenAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("TokenAsync encountered an error: " + task.Exception);
return;
}
string token = task.Result;
MainThreadDispatcher.Post(_ => /*IDtokenをローカルに保存する*/Debug.Log(token), null);
});
}
}
使用例
アプリ開始時
FirebaseManager().Instance().Init()
Googleログイン時
SignInGoogle()
IDを更新したいタイミング(例えば自社サーバーからトークン切れのエラーが返却された際など)
UpdateToken()
所感
Firebaseのドキュメントを確認しても、各プラットフォームのTokenをどうやって取得するのかについて書かれていません。
Web版のSDKはFirebaseのログインに成功するとRefreshTokenを返すのですが、
「Unity版はRefreshTokenにあたるものがCurrentUserに保存されて永続化されている」
という事は明記してほしかった。。。
(RefreshTokenを保存しようとしてプロパティを探していました)
Googleログインをネイティブコードで実装するのは実装コストが高いこともあってSDKを使用したのですが、依存関係の問題でかなり調査が必要になりました。
色々とエラーが出ていたわけですが、上記の方法で解決出来ます。
お役に立てば幸いです。
ココネでは一緒に働く仲間を募集中です。
ご興味のある方は、ぜひこちらの採用特設サイトをご覧ください。