Firebase Crashlytics安卓端用户ID偶尔不显示问题求助
Flutter Crashlytics Android端用户ID偶尔不显示的问题排查与解决
问题背景
我通过以下Flutter代码设置Crashlytics用户ID:
Future<void> handleError(Object error, StackTrace? stack) async { if (!error.toString().contains('Invalid argument(s)') && !error.toString().contains('Invalid statusCode')) { final userSession = Modular.get<UserSession>(); if (userSession.userId != null) { await FirebaseCrashlytics.instance.setUserIdentifier(userSession.userId!); } await FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); Modular.get<ErrorBloc>().add(const ShowError()); } }
目前iOS端Crashlytics控制台始终能正常显示用户ID,但Android端仅偶尔出现该字段。
附显示用户ID的控制台截图:
附未显示用户ID的控制台截图:
差异原因
- 异步执行顺序差异:
setUserIdentifier是异步操作,Android平台的异步调度可能导致recordError先于用户ID设置完成执行,此时上报的错误不会携带用户ID;而iOS的异步调度机制更稳定,能保证顺序执行。 - 初始化时机问题:Android端Crashlytics初始化可能晚于错误上报触发时机,导致用户ID还未被持久化就完成了错误上报。
- 线程安全隐患:Android多线程环境下,
Modular.get<UserSession>()获取用户ID的操作若在非主线程执行,可能因线程安全问题获取到空值,进而跳过用户ID设置。
解决方法
1. 强制保证用户ID设置完成后再上报错误
调整代码逻辑,确保recordError在setUserIdentifier执行完成后调用,即使userId为空也维持异步流程的顺序:
Future<void> handleError(Object error, StackTrace? stack) async { if (!error.toString().contains('Invalid argument(s)') && !error.toString().contains('Invalid statusCode')) { final userSession = Modular.get<UserSession>(); final userId = userSession.userId; // 无论userId是否为空,都完成异步设置操作 if (userId != null) { await FirebaseCrashlytics.instance.setUserIdentifier(userId); } else { // 可选:清空用户ID,避免残留旧数据 await FirebaseCrashlytics.instance.setUserIdentifier(''); } // 等待用户ID设置完成后再上报错误 await FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); Modular.get<ErrorBloc>().add(const ShowError()); } }
2. 提前初始化用户ID
在用户登录成功或App启动阶段就设置用户ID,而非等到错误发生时临时设置,确保错误上报时用户ID已存在于Crashlytics实例中:
// 用户登录成功后立即设置 void onUserLoginSuccess(String userId) { FirebaseCrashlytics.instance.setUserIdentifier(userId); Modular.get<UserSession>().userId = userId; } // App启动时(若用户已登录)初始化 void initCrashlyticsUser() async { final userSession = Modular.get<UserSession>(); if (userSession.userId != null) { await FirebaseCrashlytics.instance.setUserIdentifier(userSession.userId!); } }
3. 保证用户ID获取的线程安全
修改UserSession类,确保userId的读写操作线程安全,避免多线程环境下获取空值:
import 'package:synchronized/synchronized.dart'; class UserSession { String? _userId; final _lock = Lock(); Future<String?> get userId async { return _lock.synchronized(() => _userId); } Future<void> setUserId(String? id) async { await _lock.synchronized(() => _userId = id); } } // 在handleError中异步获取userId final userSession = Modular.get<UserSession>(); final userId = await userSession.userId; if (userId != null) { await FirebaseCrashlytics.instance.setUserIdentifier(userId); }
4. 提前完成Android端Crashlytics初始化
确保Android端Crashlytics在App启动早期完成初始化,比如在MainActivity的onCreate方法中配置:
// Android端MainActivity.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true) // 其他初始化逻辑 }
内容的提问来源于stack exchange,提问作者Wutipong Thabsuwan
相关产品推荐
相关产品推荐

