为啥 Firebase 无法获取 PlayGames AuthCode 并将其传递到其凭据中?

Posted

技术标签:

【中文标题】为啥 Firebase 无法获取 PlayGames AuthCode 并将其传递到其凭据中?【英文标题】:Why Firebase is unable to get PlayGames AuthCode and pass it into its Credential?为什么 Firebase 无法获取 PlayGames AuthCode 并将其传递到其凭据中? 【发布时间】:2020-07-27 15:07:48 【问题描述】:

首先,我正在开发一个 Unity 游戏,我在游戏开始时对用户进行身份验证。我的构建环境是android。我正在为 Google Play 游戏服务使用 Firebase authentication 来验证用户身份。

当游戏在我的 Android 设备或模拟器中启动时,它能够验证 Play 游戏服务并能够连接 Firebase(我正在获取分析数据)。但是,当我将 PlayGames AuthCode 传递到 Firebase.Auth 凭据时,它会停止执行代码(我已经为它调试日志)。它不会在 LogCat 中抛出任何错误,除了

Firebase | server_auth_code

我尝试在网上搜索不同的问题,但没有。我在我的 Google API 控制台上检查了我的播放器设置、firebase 设置、OAuth 2.0 凭据中的密钥,甚至检查了我的 Google Play 控制台中的密钥(我在这个阶段没有使用)。我什至在游戏服务中检查了我的测试用户电子邮件地址,并尝试了多个谷歌玩游戏帐户。但问题仍然存在。

我在我的另一个统一项目中使用了类似的脚本,其中身份验证就像一个魅力。我尝试在这里使用相同的脚本并最终遇到了这个问题:here。但是,我通过删除所有包并将它们重新导入统一并更改脚本中的调用函数来解决它。现在,我被困在这个问题上。 这是cs文件:

using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;
using System.Threading.Tasks;

public class SetFirebase : MonoBehaviour

    string authCode;
    void Start()
    
        PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder().
        RequestServerAuthCode(false /* Don't force refresh */).Build();

        PlayGamesPlatform.InitializeInstance(config);
        PlayGamesPlatform.Activate();
        Social.localUser.Authenticate((bool success) =>
        
            if (success)
            
                authCode = PlayGamesPlatform.Instance.GetServerAuthCode();
                Debug.Log("PlayGames successfully authenticated!");
                Debug.Log("AuthCode: " + authCode);
            
            else
            
                Debug.Log("PlayGames SignIn Failed");
            
        );

        Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
        
            var dependencyStatus = task.Result;
            if (dependencyStatus == Firebase.DependencyStatus.Available)
            
                Debug.Log("Firebase Ready!!!");
                RunFirebase();
            
            else
            
                Debug.LogError(System.String.Format("Could not resolve all Firebase dependencies: 0", dependencyStatus));
            
        );
        

    private void RunFirebase()
        Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
        Debug.Log("init firebase auth ");

        Firebase.Auth.Credential credential = Firebase.Auth.PlayGamesAuthProvider.GetCredential(authCode);
        Debug.Log(" passed auth code ");

        auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
        
            if (task.IsCanceled)
            
                Debug.LogError("SignInOnClick was canceled.");
                return;
            
            if (task.IsFaulted)
            
                Debug.LogError("SignInOnClick encountered an error: " + task.Exception);
                return;
            
            Firebase.Auth.FirebaseUser newUser = task.Result;
            Debug.LogFormat("SignInOnClick: User signed in successfully: 0 (1)", newUser.DisplayName, newUser.UserId);
        );    
    

我的 LogCat 执行所有操作,直到 "init firebase auth" 但不执行 "passed auth code" 所以我知道在传递凭据时存在一些问题。它也不会在 auth.SignInWithCredentialAsync(credential) 内运行任何东西。

任何帮助或建议将不胜感激。谢谢。

【问题讨论】:

【参考方案1】:

我可以建议两件事:

1) 将ContinueWith 替换为ContinueWithOnMainThread。这是一个Firebase Extension,它将保证您的逻辑在 Unity 主线程上运行(这往往会解决许多 Unity 特定问题)。我将更详细地了解here。

2) 您的逻辑可能在Authenticate 回调和CheckAndFixDependenciesAsync 延续之间存在竞争条件。这些不一定会按照您在逻辑中看到的顺序运行。

如果我正在构建这个系统,我可能更喜欢使用协程和custom yield instruction:

class Authenticate : CustomYieldInstruction

    private bool _keepWaiting = true;
    public override bool keepWaiting => _keepWaiting;

    public Authenticate(Social.ILocalUser user) 
        user.Authenticate((bool success)=>
            /* old authentication code here */
            _keepWaiting = false;
        );
    


然后在协程中有类似的东西:

private IEnumerator InitializeCoroutine() 
    /* old authentication code */

    // I'm ignoring error checking for now, but it shouldn't be hard to figure in.
    // I'm mostly going from memory now anyway

    // start both authentication processes in parallel
    var authenticate = new Authenticate(Social.localUser);
    var firebaseDependenciesTask = FirebaseApp.CheckAndFixDependenciesAsync();

    // wait on social
    yield return authenticate;

    // wait on Firebase. If it finished in the meantime this should just fall through
    yield return new WaitUntil(()=>firebaseDependenciesTask.IsComplete);

    RunFirebase();

这样我的逻辑看起来大致同步,同时仍然保持你所依赖的系统的异步性(拼写检查声称我编造了那个词)并且你避免了线程相关的问题使用ContinueWith

如果有帮助,请告诉我!

--帕特里克

【讨论】:

感谢帕特里克的简短解释!没想到强大的拍拍会回复,但我们来了!无论如何,所以我确实尝试了 ContinueWithOnMainThread 但我仍然遇到同样的问题。我也尝试了 CustomYieldInstruction 但这带来了一个全新的编译问题,因为不知何故 ILocalUser 甚至 localUser 都不再被 Unity 识别。在花了足够的时间之后,我决定从现在开始摆脱检查依赖项,这对我在 Firebase 中获得我想要的结果很有用。我可能会再次回到依赖关系,但在稍后阶段。感谢您对此进行调查! 所以,CheckAndFixDependenciesAsync 的问题是它实际上只在 Android 上执行任何操作(ios 和桌面,它基本上是无操作的)。此外,在 Android 上,如果播放器已经拥有最新版本的 Google Play 服务,它不会做任何事情。只需确保将“在没有/使用过时版本的 Google Play 服务的设备/模拟器上进行测试”添加到您的发布清单中,这样您就不会忘记它(或者知道您的某些玩家群可能会在没有解释的情况下崩溃)。 也可以同步调用CheckDependencies,但不能同步修复(firebase.google.com/docs/reference/unity/class/firebase/…)。这仍然会在主线程上阻塞(还有一个CheckDependenciesAsync,但如果你已经修复了线程问题,你最好打电话给CheckAndFix)并且不会修复任何检测到的问题(提示玩家更新谷歌Play Services),但也许它比什么都不做更安全。

以上是关于为啥 Firebase 无法获取 PlayGames AuthCode 并将其传递到其凭据中?的主要内容,如果未能解决你的问题,请参考以下文章