feat(bugcollect): 使用 deviceId 作为 userId 兜底,保障影响设备数统计

- XuqmSDK 新增 deviceId 属性:首次生成 UUID 存入 SharedPreferences,后续不变
- BugCollect 上报事件时 userId 改为 getUserId() ?: deviceId,未登录也能统计影响设备数
- BugCollectInitProvider 崩溃拦截同步使用 deviceId 兜底

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-18 10:47:38 +08:00
父节点 77fef3a38b
当前提交 aca0d009a8
共有 3 个文件被更改,包括 25 次插入9 次删除

查看文件

@ -45,7 +45,7 @@ object BugCollect {
if (!isReady()) return
queue().push(LogEvent(
name = name, properties = properties,
appKey = XuqmSDK.appKey, userId = XuqmSDK.getUserId(),
appKey = XuqmSDK.appKey, userId = XuqmSDK.getUserId() ?: XuqmSDK.deviceId,
platform = "android", release = appVersion(), environment = environment,
sdk = IssueEvent.SdkInfo(SDK_NAME, SDK_VERSION),
))
@ -73,8 +73,8 @@ object BugCollect {
breadcrumbs = crumbs,
release = appVersion(),
environment = environment,
userId = XuqmSDK.getUserId(),
user = IssueEvent.UserInfo(id = XuqmSDK.getUserId()),
userId = XuqmSDK.getUserId() ?: XuqmSDK.deviceId,
user = IssueEvent.UserInfo(id = XuqmSDK.getUserId() ?: XuqmSDK.deviceId),
device = buildDeviceInfo(),
tags = tags,
))
@ -100,8 +100,8 @@ object BugCollect {
breadcrumbs = crumbs,
release = appVersion(),
environment = environment,
userId = XuqmSDK.getUserId(),
user = IssueEvent.UserInfo(id = XuqmSDK.getUserId()),
userId = XuqmSDK.getUserId() ?: XuqmSDK.deviceId,
user = IssueEvent.UserInfo(id = XuqmSDK.getUserId() ?: XuqmSDK.deviceId),
device = buildDeviceInfo(),
tags = tags,
))
@ -118,8 +118,8 @@ object BugCollect {
exception = IssueEvent.ExceptionInfo(type = "Warning", value = message),
release = appVersion(),
environment = environment,
userId = XuqmSDK.getUserId(),
user = IssueEvent.UserInfo(id = XuqmSDK.getUserId()),
userId = XuqmSDK.getUserId() ?: XuqmSDK.deviceId,
user = IssueEvent.UserInfo(id = XuqmSDK.getUserId() ?: XuqmSDK.deviceId),
tags = tags,
))
}
@ -141,7 +141,7 @@ object BugCollect {
CrashCapture.start(
appContext = XuqmSDK.appContext,
appKey = XuqmSDK.appKey,
getUserId = { XuqmSDK.getUserId() },
getUserId = { XuqmSDK.getUserId() ?: XuqmSDK.deviceId },
)
queue().uploadPendingCrashes()
}

查看文件

@ -40,7 +40,7 @@ internal class BugCollectInitProvider : ContentProvider() {
CrashCapture.start(
appContext = ctx,
appKey = XuqmSDK.appKey,
getUserId = { XuqmSDK.getUserId() },
getUserId = { XuqmSDK.getUserId() ?: XuqmSDK.deviceId },
)
// ── Phase 2远端配置就绪后上传 ─────────────────────────────────────────

查看文件

@ -43,6 +43,11 @@ object XuqmSDK {
/** 初始化时使用的平台地址(同步可用,远端配置到达前即有值)。 */
val platformUrl: String get() = resolvedPlatformUrl
/** 持久设备 IDUUID,首次生成后永不变更。未上报 userId 的场景可用此 ID 追踪影响设备数。 */
@Volatile var deviceId: String = ""
private set
@Volatile private var loginSession: XuqmLoginSession? = null
@Volatile private var userInfoValue: XuqmUserInfo? = null
@Volatile var platformConfig: SdkPlatformConfig? = null
@ -121,6 +126,7 @@ object XuqmSDK {
config = SDKConfig(appKey, logLevel)
appContext = applicationContext
tokenStore = TokenStore(applicationContext)
deviceId = resolveDeviceId(applicationContext)
ApiClient.init(config, tokenStore)
initializedAppKey = appKey
initialized = true
@ -217,6 +223,16 @@ object XuqmSDK {
)
}
private fun resolveDeviceId(context: Context): String {
val prefs = context.getSharedPreferences("xuqm_sdk_core", android.content.Context.MODE_PRIVATE)
val key = "device_id"
val stored = prefs.getString(key, null)
if (!stored.isNullOrBlank()) return stored
val generated = java.util.UUID.randomUUID().toString()
prefs.edit().putString(key, generated).apply()
return generated
}
private fun platformInitException(platformUrl: String, appKey: String, cause: Throwable): Throwable {
val kind = if (platformUrl == DEFAULT_PLATFORM_URL) "公有平台" else "私有化平台 $platformUrl"
return IllegalStateException(