Unity接入Firebase双管理类并行初始化出现竞态仅单实例生效
问题根因
你遇到的竞态问题核心来源是两个Manager类的Awake中同时调用了FirebaseApp.CheckAndFixDependenciesAsync():
- Firebase的依赖检查与修复是全局独占操作,官方明确要求整个应用生命周期内仅能执行一次,并发调用会破坏FirebaseApp全局实例的内部状态
- 其次
ContinueWith默认返回的是后台工作线程,直接在后台线程调用Firebase Auth/Database的DefaultInstance属性也有概率触发线程安全问题导致空引用
解决方案
方案1:抽离全局统一初始化入口(推荐)
新增全局唯一的Firebase初始化单例,等依赖准备完成后再分别触发两个业务Manager的初始化逻辑,既避免并发调用依赖检查,也保持你原来的业务逻辑拆分的架构。
1. 新增FirebaseInitializer.cs
public class FirebaseInitializer : MonoBehaviour { public static FirebaseInitializer instance; public DependencyStatus dependencyStatus; // 依赖准备完成的回调事件 public event Action OnFirebaseDependenciesReady; void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(gameObject); // 全局仅执行一次依赖检查 FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => { dependencyStatus = task.Result; if (dependencyStatus == DependencyStatus.Available) { // 通知所有订阅的Manager执行初始化 OnFirebaseDependenciesReady?.Invoke(); } else { Debug.LogError("Firebase依赖修复失败: " + dependencyStatus); } }); } else { Destroy(gameObject); } } }
2. 修改FirebaseManagerAuth.cs
删除Awake中的依赖检查逻辑,改为订阅初始化事件:
public class FirebaseManagerAuth : MonoBehaviour { public static FirebaseManagerAuth instance; [SerializeField] private PlayerDataSO playerData; [Header("Firebase")] public FirebaseAuth fbAuth; public FirebaseUser fbUser; void Awake() { if (instance == null) { instance = this; // 订阅依赖准备完成事件 FirebaseInitializer.instance.OnFirebaseDependenciesReady += InitializeFirebase; } else { Destroy(gameObject); } } private void InitializeFirebase() { try { fbAuth = FirebaseAuth.DefaultInstance; Debug.Log("Firebase Auth初始化完成"); } catch (Exception e) { Debug.LogError("AUTH初始化失败: " + e.Message); } } }
3. 修改FirebaseManagerGame.cs
和Auth类逻辑一致,改为订阅初始化事件:
public class FirebaseManagerGame : MonoBehaviour { public static FirebaseManagerGame instance; [SerializeField] private PlayerDataSO playerData; [Header("Firebase")] public DatabaseReference DBreference; void Awake() { if (instance == null) { instance = this; // 订阅依赖准备完成事件 FirebaseInitializer.instance.OnFirebaseDependenciesReady += InitializeFirebase; } else { Destroy(gameObject); } } private void InitializeFirebase() { try { DBreference = FirebaseDatabase.DefaultInstance.RootReference; Debug.Log("Firebase Database初始化完成,引用: " + DBreference.ToString()); } catch (Exception e) { Debug.LogError("GAME初始化失败: " + e.Message); } } }
场景配置说明
把FirebaseInitializer挂载到场景中优先级最高的GameObject上,调整脚本执行顺序,保证FirebaseInitializer的Awake早于两个Manager的Awake执行即可。
方案2:加静态标记位避免重复调用依赖检查
如果不想新增类,也可以给两个Manager加静态的依赖检查标记:
// 新增静态全局标记 private static bool _isDependenciesChecked = false; private static readonly object _lockObj = new object(); void Awake() { // 单例逻辑保持不变 if (instance == null) { instance = this; lock(_lockObj) { if (!_isDependenciesChecked) { _isDependenciesChecked = true; FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => { // 初始化逻辑和原来一致 }); } } } else { Destroy(gameObject); } }
内容的提问来源于stack exchange,提问作者oetzi
相关产品推荐
相关产品推荐

