You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Netcode/Relay/Lobby的多人游戏Firebase异步登录挂起问题

Firebase异步登录await挂起问题解决方案(场景切换后)

核心问题定位

场景切换(Relay/Lobby操作后返回菜单)后,SignInWithEmailAndPasswordAsync的await永久挂起,主线程无法继续执行后续代码,本质是Firebase Auth实例生命周期异常或Unity同步上下文丢失导致异步任务回调无法触发。

具体修复方案

1. 全局单例化Firebase Auth管理类

场景切换时保留Firebase核心实例,避免重复初始化或实例丢失:

public class FirebaseAuthManager : MonoBehaviour
{
    public static FirebaseAuthManager Instance { get; private set; }
    public FirebaseAuth Auth { get; private set; }

    void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
        
        // 异步初始化Firebase依赖
        FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
        {
            if (task.Result == DependencyStatus.Available)
            {
                Auth = FirebaseAuth.DefaultInstance;
                // 开启会话持久化,避免场景切换丢失登录状态
                Auth.SetPersistenceAsync(Persistence.Session);
            }
            else
            {
                Debug.LogError("Firebase依赖初始化失败: " + task.Result);
            }
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

2. 显式绑定主线程同步上下文

在await时强制指定回到主线程,避免场景切换后上下文丢失:

// 修改登录代码中的await调用
AttemptedUser = await auth.SignInWithEmailAndPasswordAsync(_email, _password)
    .ConfigureAwait(true);

3. 场景切换前清理未完成任务

添加取消令牌,防止场景切换时遗留的异步任务阻塞后续操作:

private CancellationTokenSource _loginCts;

public async void OnLoginButtonClick()
{
    _loginCts?.Cancel();
    _loginCts?.Dispose();
    _loginCts = new CancellationTokenSource();

    FirebaseUser AttemptedUser = null;
    var auth = FirebaseAuthManager.Instance.Auth;
    
    try
    {
        Debug.Log("about to try to log in with email and password"); // LINE 1
        AttemptedUser = await auth.SignInWithEmailAndPasswordAsync(_email, _password)
            .WithCancellation(_loginCts.Token)
            .ConfigureAwait(true);
        Debug.Log("finished awaiting SignInWithEmailAndPasswordAsync"); // LINE 2

        // 登录成功逻辑移至try块内,避免finally执行异步操作
        User = AttemptedUser;
        Debug.LogFormat("User signed in successfully: {0} ({1})", User.DisplayName, User.Email);
        warningLoginText.text = "";
        confirmLoginText.text = "Logged In";

        Debug.Log("about to call UnityLogin");
        await UnityLogin(anonymous: false).ConfigureAwait(true);
        Debug.Log("finished calling UnityLogin");
    }
    catch (OperationCanceledException)
    {
        Debug.Log("登录任务已取消");
    }
    catch (Exception e)
    {
        Debug.Log(e.GetType());
        Debug.Log(e.Message);
    }
    finally
    {
        Debug.Log("in FAM finally");
        // 仅执行同步清理操作
        _loginCts?.Dispose();
    }
}

// 场景切换时调用此方法
public void OnSceneSwitch()
{
    _loginCts?.Cancel();
}

4. 移除finally块中的异步操作

原代码中finally块包含await UnityLogin,异步操作在finally中可能因上下文异常导致挂起,建议将成功逻辑移至try块内执行。

内容的提问来源于stack exchange,提问作者yusefwilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 06:10:37