基于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
相关产品推荐
相关产品推荐

