From e300cbdb83c72ac5d3f543cf793138b2faaea9d1 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Thu, 18 Jun 2026 09:43:47 +0800 Subject: [PATCH] =?UTF-8?q?fix(bugcollect):=20=E4=BF=AE=E5=A4=8D=E5=B4=A9?= =?UTF-8?q?=E6=BA=83=E6=96=87=E4=BB=B6=E6=9C=AA=E5=86=99=E5=85=A5=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=20fatal=20crash=20=E4=B8=8D=E4=B8=8A=E6=8A=A5?= =?UTF-8?q?=E7=9A=84=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根本原因:CrashCapture 调用无 Context 的 LogStorage.saveCrash 重载, 该重载通过反射获取 packageName 失败时返回空字符串, 导致崩溃文件路径变为 /data/data//files/xuqm_crashes(无效), mkdirs() 静默失败,崩溃文件未写入,下次启动无数据可上报。 修复: - CrashCapture.start() 新增 appContext: Context 参数 - 改为调用带 Context 的 saveCrash 重载,依赖 context.filesDir 获取可靠路径 - BugCollect.startCrashCapture() 传入 XuqmSDK.appContext - LogStorage 删除不可靠的无 Context 重载及 getPackageName() 反射代码 Co-Authored-By: Claude Sonnet 4.6 --- .../com/xuqm/sdk/bugcollect/BugCollect.kt | 1 + .../com/xuqm/sdk/bugcollect/CrashCapture.kt | 6 ++- .../sdk/bugcollect/internal/LogStorage.kt | 41 ++----------------- 3 files changed, 8 insertions(+), 40 deletions(-) diff --git a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/BugCollect.kt b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/BugCollect.kt index 9471d3e..45ee491 100644 --- a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/BugCollect.kt +++ b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/BugCollect.kt @@ -134,6 +134,7 @@ object BugCollect { val bugCollectApiUrl = XuqmSDK.bugCollectApiUrl ?: return crashCaptureStarted = true CrashCapture.start( + appContext = XuqmSDK.appContext, logApiUrl = bugCollectApiUrl, appKey = XuqmSDK.appKey, getUserId = { XuqmSDK.getUserId() }, diff --git a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/CrashCapture.kt b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/CrashCapture.kt index f426d5f..5c0083a 100644 --- a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/CrashCapture.kt +++ b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/CrashCapture.kt @@ -1,12 +1,14 @@ package com.xuqm.sdk.bugcollect +import android.content.Context import com.xuqm.sdk.bugcollect.internal.LogStorage internal object CrashCapture { - fun start(logApiUrl: String, appKey: String, getUserId: () -> String?) { + fun start(appContext: Context, logApiUrl: String, appKey: String, getUserId: () -> String?) { val prev = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> - LogStorage.saveCrash(throwable, logApiUrl, appKey, getUserId()) + // 使用带 Context 的重载,依赖 context.filesDir 获取可靠路径 + LogStorage.saveCrash(appContext, throwable, logApiUrl, appKey, getUserId()) prev?.uncaughtException(thread, throwable) } } diff --git a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/LogStorage.kt b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/LogStorage.kt index b019e43..e332008 100644 --- a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/LogStorage.kt +++ b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/LogStorage.kt @@ -12,38 +12,9 @@ internal object LogStorage { File(context.filesDir, CRASH_DIR).also { it.mkdirs() } /** - * 同步写崩溃信息到文件系统(UncaughtExceptionHandler 中调用)。 - * 文件将在下次启动时由 [com.xuqm.sdk.bugcollect.LogQueue.uploadPendingCrashes] 上报。 - */ - fun saveCrash( - throwable: Throwable, - logApiUrl: String, - appKey: String, - userId: String?, - ) { - runCatching { - val dir = File( - // 使用系统属性获取 filesDir 替代 Context(在 UncaughtExceptionHandler 中 Context 可能不可用) - android.os.Environment.getDataDirectory().absolutePath + - "/data/${getPackageName()}/files/$CRASH_DIR" - ).also { it.mkdirs() } - val file = File(dir, "${System.currentTimeMillis()}.json") - val json = JSONObject().apply { - put("level", "fatal") - put("message", throwable.message ?: throwable.javaClass.name) - put("stack", throwable.stackTraceToString()) - put("exceptionType", throwable.javaClass.simpleName) - put("logApiUrl", logApiUrl) - put("appKey", appKey) - put("userId", userId ?: JSONObject.NULL) - put("timestamp", System.currentTimeMillis()) - } - file.writeText(json.toString()) - } - } - - /** - * 在 Application 中通过 Context 保存崩溃(更可靠)。 + * 同步写崩溃文件(在 UncaughtExceptionHandler 中调用)。 + * Application Context 在 handler 回调时仍然有效,直接用 context.filesDir 获取可靠路径。 + * 文件在下次启动时由 LogQueue.uploadPendingCrashes 上报后删除。 */ fun saveCrash( context: Context, @@ -68,10 +39,4 @@ internal object LogStorage { file.writeText(json.toString()) } } - - private fun getPackageName(): String = runCatching { - val clazz = Class.forName("android.app.ActivityThread") - val method = clazz.getMethod("currentPackageName") - method.invoke(null) as? String ?: "" - }.getOrDefault("") }