Unity打包后Firebase RTDB事务报空引用异常无法正常工作
问题环境
- 开发引擎:Unity 2020.3.22f1
- 依赖版本:基于dotnet4的Firebase SDK 9.0.0,已同时导入Analytics、Real-Time Database(简称RTDB)两个功能模块
- 功能现状:Analytics模块在所有运行场景下工作完全正常
- 异常场景:三类正式发布包均触发RTDB相关报错:
- 打包Android App Bundle上传至内部测试渠道
- 打包APK直接安装到Android真机
- 打包iOS版本上传至TestFlight
相关代码实现
Firebase初始化逻辑
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => { // 初始化Analytics FirebaseAnalytics.SetAnalyticsCollectionEnabled(true); DatabaseReference = FirebaseDatabase.DefaultInstance.RootReference; Debug.Log(JsonConvert.SerializeObject(DatabaseReference.Database.App.Options)); });
RTDB自增事务逻辑(关卡通关数统计)
DatabaseReference.Child("Levels").Child($"Level{levelNum}").Child("Wins").RunTransaction((mutableData) => { mutableData.Value = Int32.Parse(mutableData.Value.ToString()) + 1; return TransactionResult.Success(mutableData); });
问题现象
- Unity编辑器内运行无异常:初始化DatabaseReference后打印的Options配置可完整展示databaseUrl、apikey、AppId等所有属性
- 真机/发布包运行异常:
- Android真机调试APK时,打印的Options属性仅包含databaseUrl字段
- 执行数据库事务操作时抛出如下空引用错误:
W/Unity: Exception in transaction delegate, aborting transaction System.NullReferenceException: Object reference not set to an instance of an object. at ....(Firebase.Database.MutableData mutableData)
已完成排查操作
- 已配置调试密钥库、Google控制台应用完整性对应的SHA1/SHA256值
- 已确认配置文件生成正常:streamingAssets文件夹、
Assets\Plugins\Android\FirebaseApp.androidlib\res\values\google-services.xml路径下的XML配置均存在,且包含全部配置项 - 已尝试手动初始化Firebase App:操作后Debug.Log可打印全部Options参数,但空引用报错仍存在;分别测试保留配置文件、完全删除配置文件两种场景,问题均未解决
- 已尝试重写默认App实例的Options配置,问题未修复
- 怀疑Proguard混淆可能引发Firebase相关错误,但未找到Unity平台对应的配置说明
解决思路
你遇到的空引用报错和配置、密钥、Proguard混淆都没有关系,核心问题是RTDB事务回调的写法不符合SDK的运行逻辑:
Firebase RTDB的RunTransaction触发后,第一次回调传入的mutableData.Value一定是null:SDK不会等拉取到服务端最新值才执行回调,会先传空值做一次本地预判,等拿到最新数据后才会第二次传入有效值进回调。你直接对null值调用ToString(),必然触发空引用异常。编辑器下不报错是因为本地存在之前连接的缓存值,跳过了首次空值回调的流程,真机首次启动无缓存就会必现报错。
直接修正事务逻辑,增加空值判断和类型兼容即可:
DatabaseReference.Child("Levels").Child($"Level{levelNum}").Child("Wins").RunTransaction((mutableData) => { // 首次空值回调直接返回,SDK拉取到最新数据后会再次触发回调 if (mutableData.Value == null) { return TransactionResult.Success(mutableData); } int currentWins = 0; // Firebase存储数字类型默认返回long,直接强转int/Parse容易触发类型转换错误,做兼容处理 if (mutableData.Value is long winsCount) { currentWins = (int)winsCount; } else { int.TryParse(mutableData.Value.ToString(), out currentWins); } mutableData.Value = currentWins + 1; return TransactionResult.Success(mutableData); });
关于真机打印Options仅显示databaseUrl的现象,是Firebase Unity SDK在移动端的序列化逻辑做了内部字段裁剪,只要初始化流程不报错、数据库请求能正常发出,这个打印缺字段的现象不影响实际功能,不需要额外处理。
如果修正事务逻辑后仍存在连通问题,再补充Android端Proguard规则即可:在Player Settings中开启自定义Proguard配置文件,添加Firebase相关类的keep规则;iOS端不存在代码混淆问题,只要确保Firebase控制台下载的GoogleService-Info.plist放在项目Assets目录下即可。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

