提交图

36 次代码提交

作者 SHA1 备注 提交日期
XuqmGroup
3d62a6ed72 fix: docx MIME 检测 + Fingerprint 协程帧稳定性
sdk-webview:
  选文件时 DISPLAY_NAME 在 vivo content://media/external/file/ URI
  上返回 null,导致扩展名推断失效;ContentResolver.getType() 对 .docx
  返回 application/msword(错误)→ allowed 检查拒绝文件。
  修复:DISPLAY_NAME 为 null 时回退查 MediaStore.DATA 提取文件名;
  优先使用扩展名推断的 MIME 而非 ContentResolver 的返回值,
  避免厂商 ROM 返回错误 MIME 的干扰。copyUriToWebViewCache 同步修复。

sdk-bugcollect:
  Fingerprint.compute 取 top3 stack 帧,Kotlin 协程 dispatcher 的
  第 2、3 帧在每次调度时不固定,相同逻辑错误产生不同指纹 → 多条 issue。
  修改为 top1(只取抛出点帧),保证同一位置抛出的异常总被归为一条。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 15:19:51 +08:00
XuqmGroup
6d18af496b fix: 移除库模块 isMinifyEnabled 修复 Duplicate class 冲突
Android 库模块开启 isMinifyEnabled=true 时,R8 各自独立混淆,
将内部类重命名为 a.a / a.b 等短名打进 AAR;多个 AAR 合并到 App
时产生 Duplicate class 冲突。

修复:删除全部 7 个库模块 buildTypes.release 中的 isMinifyEnabled,
混淆由 App 的 R8 统一完成。将 proguard-rules.pro 中的保留规则
(manifest 注册类、反射调用入口、dontwarn)合并进各模块的
consumer-rules.pro 随 AAR 打包。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:57:22 +08:00
XuqmGroup
7169e66ee9 fix(bugcollect): flush 时修正初始化前暂存事件的 appKey
SDK 通过 ContentProvider 异步初始化(sdkScope.launch),若应用层在
initialized=true 设置前调用 captureError,事件以 appKey="pending"
存入 pendingErrors。后续 flushPendingErrors 将其原样推送给 LogQueue,
服务端找不到对应应用而丢弃,导致上报丢失。

修复:flush 时检测 appKey=="pending" 并替换为真实值(appKey、userId、
release、buildId),确保早期捕获的错误能正常上报。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:40:18 +08:00
XuqmGroup
fbe2a6b677 fix(proguard): sdk-core 保留全部类名,其余模块加 -dontwarn 避免跨模块 R8 缺类错误
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 13:44:19 +08:00
XuqmGroup
aac4bd7baa feat(proguard): 各模块开启 R8 混淆,添加 proguard-rules.pro 保留公开 API
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 13:35:10 +08:00
XuqmGroup
9d4de920a4 fix(bugcollect): 使用 manifest meta-data 传递 buildId,修复 namespace/applicationId 不一致导致反射失败
BuildConfig 反射方案在 applicationId 与 namespace 不同时(如 shijiaobao flavor)会抛出
ClassNotFoundException 导致 buildId=null。改为通过 manifestPlaceholders 注入 xuqmBuildId,
SDK 从 PackageManager.getApplicationInfo(GET_META_DATA) 读取,彻底绕开包名歧义。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 17:50:16 +08:00
XuqmGroup
06f7b9d44d feat(bugcollect): 为每次打包生成独立 buildId,支持相同版本多包溯源
- Gradle 插件在配置阶段生成 yyyyMMddHHmmss 格式的 buildId,通过
  BuildConfig.XUQM_BUILD_ID 注入 APK,并作为 buildId 字段上传 sourcemap
- SDK 通过反射读取 BuildConfig.XUQM_BUILD_ID,在所有事件
  (captureError/captureCrash/warn) 的 IssueEvent 中携带 buildId
- LogUploader 序列化时将 buildId 写入上报 JSON
- IssueEvent 新增 buildId 可选字段

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 16:46:41 +08:00
XuqmGroup
8e0193ceec fix: BugCollect.buildDeviceInfo 和 appVersion 在 SDK 未初始化时安全降级
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-19 02:17:26 +08:00
XuqmGroup
04eb0d13d3 fix: BugCollect.captureError 在 SDK 未初始化时不再崩溃
- captureError 检查 XuqmSDK.isInitialized() 再访问 appKey
- SDK 未初始化时将错误加入待处理队列,初始化后自动 flush
- captureCrash 也添加 isInitialized 检查

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-19 02:05:06 +08:00
XuqmGroup
ffafd94a1e chore(bugcollect): 清理调试日志,准备发布正式版本 2026-06-18 21:15:55 +08:00
XuqmGroup
84c9eb5e7a fix(bugcollect): 修复上传流程 - pendingErrors 队列、动态 URL、相对路径补全 2026-06-18 20:12:00 +08:00
XuqmGroup
8d0dd0a41d debug: uploadIssues 日志改为 Log.w 2026-06-18 19:45:14 +08:00
XuqmGroup
35bf96f89f debug(bugcollect): 添加 uploadIssues 日志 2026-06-18 19:40:29 +08:00
XuqmGroup
64580b4b9e debug(bugcollect): 添加 flush 日志排查上传流程 2026-06-18 19:36:17 +08:00
XuqmGroup
3f03f5c1de fix(bugcollect): 平台配置下发后延迟重试 flush,修复事件丢失
- startCrashCapture 后延迟检查 bugCollectApiUrl,就绪后再次 flush
- 添加调试日志帮助排查上传流程
2026-06-18 19:29:18 +08:00
XuqmGroup
ceaaeca1fe fix(bugcollect): LogQueue 动态获取 bugCollectApiUrl,修复上传 URL 为空问题
- LogQueue.logApiUrl 改为动态 getter,每次上传取最新 URL
- flush() 在 URL 为空时跳过,等下次定时 flush
- LogUploader.resolveUrl 自动补全相对路径
2026-06-18 19:16:02 +08:00
XuqmGroup
d742317c4d fix(bugcollect): LogUploader 自动将相对路径补全为绝对 URL
- bugCollectApiUrl 为相对路径时,基于 XuqmSDK.platformUrl 拼接完整地址
- 修复 'Expected URL scheme http or https' 异常
2026-06-18 19:06:03 +08:00
XuqmGroup
3ded960383 fix(bugcollect): captureError 在 SDK 未就绪时暂存事件,就绪后自动 flush
- 添加 pendingErrors 队列,SDK 未初始化时 captureError 不再丢弃事件
- startCrashCapture 完成后自动 flush 暂存事件到上传队列
2026-06-18 18:56:37 +08:00
XuqmGroup
d5ce5ffabb refactor(bugcollect): 移除 BugCollectInitProvider 减少框架开销
- 移除了 BugCollectInitProvider ContentProvider
- 改为通过 XuqmSDK afterInit 回调注册崩溃拦截器
- 消除了约 380ms 的 ContentProvider 框架启动开销
- 确保在 SDK 初始化完成后注册 UncaughtExceptionHandler
2026-06-18 17:07:12 +08:00
XuqmGroup
e180003386 fix(sdk-bugcollect): BugCollectInitProvider 添加 CrashCapture import
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-18 16:25:35 +08:00
XuqmGroup
b7c7a2c385 perf(sdk-core): 合并 ContentProvider + PBKDF2 缓存,冷启动从 ~350ms 降到 ~7ms
优化内容:
- 新增 XuqmMergedProvider:合并 3 个 Provider 为 1 个,主线程只读文件字节
- 新增 ConfigCache:EncryptedSharedPreferences 持久化缓存解密结果
- ConfigFileReader 新增 readRawBytes() / readWithCache(),单例内存缓存
- XuqmSDK 新增 autoInitializeFromBytes():IO 线程完成解密+初始化
- BugCollectInitProvider 改为兼容 fallback,检查 isInitialized() 跳过
- XuqmInitializerProvider 标记 @Deprecated

性能对比:
  优化前:主线程 ~350ms(PBKDF2 + 文件扫描 + 3 个 Provider 实例化)
  优化后:主线程 ~7ms(文件发现 + 读字节),后续启动 ~3ms(读缓存)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-18 15:58:53 +08:00
XuqmGroup
ba6de0a5fd perf(sdk): ContentProvider 异步初始化,减少冷启动阻塞时间
- XuqmInitializerProvider 改用 autoInitializeAsync(),TokenStore/DeviceId/ApiClient 移到 IO 线程
- XuqmSDK 新增 readAppKey() 公开方法,仅读取 config 不做初始化
- BugCollectInitProvider 适配异步初始化,直接读取 appKey 注册崩溃拦截器
- 同步阶段只做 config 文件读取(~5ms),主线程不再阻塞
2026-06-18 14:53:34 +08:00
XuqmGroup
aca0d009a8 feat(bugcollect): 使用 deviceId 作为 userId 兜底,保障影响设备数统计
- XuqmSDK 新增 deviceId 属性:首次生成 UUID 存入 SharedPreferences,后续不变
- BugCollect 上报事件时 userId 改为 getUserId() ?: deviceId,未登录也能统计影响设备数
- BugCollectInitProvider 崩溃拦截同步使用 deviceId 兜底

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 10:47:38 +08:00
XuqmGroup
77fef3a38b refactor(bugcollect): 注册与 URL 完全解耦
注册 UncaughtExceptionHandler 不需要 URL:
- CrashCapture.start 移除 logApiUrl 参数,只需 appContext + appKey
- LogStorage.saveCrash 移除 logApiUrl,崩溃文件不再存储 URL
- LogQueue.uploadPendingCrashes 上传时直接取 XuqmSDK.bugCollectApiUrl,
  URL 为 null 则跳过(下次启动重试),不依赖崩溃文件里的历史 URL
- BugCollect.startCrashCapture 移除 URL 构造逻辑
- BugCollectInitProvider Phase 1 纯粹只注册,彻底消除对 platformUrl 的依赖,
  版本兼容问题从根本上消失

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 10:18:08 +08:00
XuqmGroup
be8eeba9e1 fix(bugcollect): BugCollectInitProvider 对旧版 sdk-core 防御降级
platformUrl 是新增属性,旧版 sdk-core 没有对应的 getPlatformUrl()。
改用 runCatching 包住调用,NoSuchMethodError 时记录警告、跳过崩溃拦截,
不再因版本不一致导致 app 启动崩溃。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 10:16:05 +08:00
XuqmGroup
54b3163f53 refactor(bugcollect): 崩溃收集与上传分离,sdk-core 保持独立
设计问题:
- 之前用反射在 XuqmInitializerProvider 里调用 BugCollect,sdk-core 隐式依赖 sdk-bugcollect
- startCrashCapture 同时负责注册拦截器和触发上传,两者生命周期不同

新架构:
- sdk-core 完全干净,XuqmInitializerProvider 还原为只调用 autoInitialize
- sdk-bugcollect 自注册 BugCollectInitProvider(initOrder=89)
  - Phase 1(同步):core init 完成后立即注册 UncaughtExceptionHandler,用
    platformUrl 派生兜底 URL,落盘不依赖远端配置
  - Phase 2(异步):awaitInitialization() 后用最新 bugCollectApiUrl 上传积压崩溃
- BugCollect.uploadPendingCrashes() 公开,供 Phase 2 调用
- startCrashCapture() 保持幂等,app 侧可选择性调用,不影响自动流程

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 10:11:08 +08:00
XuqmGroup
cc1557daf0 fix(bugcollect): 修复 fatal crash 不上报——startCrashCapture 从未被调用
根本原因链:
1. XuqmInitializerProvider 只调用 XuqmSDK.autoInitialize,从不调用 startCrashCapture
2. 即使调用,startCrashCapture 检查 bugCollectApiUrl == null 即提前返回;
   而 bugCollectApiUrl 由远端配置下发,崩溃发生时往往尚未到达
3. UncaughtExceptionHandler 从未注册,崩溃文件没有写入,下次启动无数据可上报

修复:
- XuqmSDK 新增 platformUrl 属性(同步可用,初始化即有值)
- BugCollect.startCrashCapture 不再依赖 bugCollectApiUrl,
  用 platformUrl + "/api/bugcollect/" 作为兜底 URL 写入崩溃文件
- LogQueue.uploadPendingCrashes 优先使用崩溃文件内保存的 logApiUrl
- XuqmInitializerProvider 通过反射调用 BugCollect.startCrashCapture,
  在 SDK 初始化后立即注册 UncaughtExceptionHandler

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 10:05:43 +08:00
XuqmGroup
e300cbdb83 fix(bugcollect): 修复崩溃文件未写入导致 fatal crash 不上报的 bug
根本原因: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 <noreply@anthropic.com>
2026-06-18 09:43:47 +08:00
XuqmGroup
3959da7693 fix: bugcollect 模块 Java 11 → 17(Jenkins agent 无法下载 Java 11) 2026-06-17 18:39:34 +08:00
XuqmGroup
da6c5f59e5 fix(bugcollect): remove invalid sdk param from IssueEvent in LogQueue
IssueEvent does not have a sdk parameter; sdk info belongs to LogEvent only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:59:37 +08:00
XuqmGroup
43e7c5655e fix(bugcollect): IssueEvent 补充 SdkInfo nested class,BugCollect 移除 IssueEvent 无效 sdk 参数
IssueEvent 没有 sdk 字段导致 Kotlin 编译失败:
- IssueEvent.kt: 补充 SdkInfo 嵌套类(LogEvent.sdk 引用它)
- BugCollect.kt: captureError/captureCrash/warn 的 IssueEvent() 调用中删除
  sdk = IssueEvent.SdkInfo(...)(IssueEvent 无此参数,sdk 信息由 LogUploader 封装到 envelope 层)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:38:27 +08:00
XuqmGroup
4896f24af8 feat(bugcollect): SDK v1.1.0 — 修复 packageName 缺失导致 captureError 静默失败
Root cause: SdkPlatformConfigApi.fetchConfig 未传 packageName → 服务端返回400
→ bugCollectEnabled=false → captureError 是空操作

修复内容:
- SdkPlatformConfigApi: 增加 packageName 查询参数
- SdkPlatformConfig: 修正字段名 bugCollectApiUrl/features.bugCollect
- XuqmSDK: 传入 appContext.packageName,读取 features?.bugCollect
- Fingerprint: 使用 exceptionType(类名)替代 level 字符串,避免同一崩溃按级别分桶
- IssueEvent: 增加 eventId、breadcrumbs、DeviceInfo 扩展字段
- BugCollect: 增加 addBreadcrumb(),captureError/captureCrash 附加面包屑和设备信息
- LogUploader: 序列化 eventId/breadcrumbs/expanded device
- LogQueue: 崩溃恢复使用 exceptionType 重建 fingerprint

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:30:40 +08:00
XuqmGroup
7b52d09758 refactor(sdk-bugcollect): 将 Gradle 插件拆分为独立 JVM 模块 sdk-bugcollect-plugin
AAR 无法作为 Gradle 插件 classpath,plugins{} 块也需要独立的 plugin marker artifact。
将 XuqmBugCollectPlugin/XuqmUploadMappingTask 迁移到新的 sdk-bugcollect-plugin 模块,
使用 java-gradle-plugin 自动生成 com.xuqm.bugcollect 插件标记并发布到 Nexus。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 10:41:29 +08:00
XuqmGroup
8db0d353de feat(sdk-bugcollect): Gradle plugin 支持从 config.xuqm 自动解密读取配置
Mode A 项目放置了 assets/xuqm/config.xuqm(PBKDF2+AES-256-GCM 加密),
Gradle plugin 现可直接解密读取 appKey / platformUrl,无需额外的
xuqm.config.json。优先级:config.xuqm > xuqm.config.json > gradle.properties。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 19:14:49 +08:00
XuqmGroup
dff226ae71 feat(sdk-bugcollect): Gradle plugin 支持从 xuqm.config.json 读取配置
- 读取优先级:xuqm.config.json > XUQM_APP_KEY(gradle.properties)
- 默认 platformUrl 改为 https://dev.xuqinmin.com(SaaS 平台)
- 移除 51szyx.com 硬编码

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 19:02:39 +08:00
XuqmGroup
c8a482a5c0 refactor: sdk-log → sdk-bugcollect
- 目录/包名/类名/Gradle plugin 全部重命名
- XLog → BugCollect
- logApiUrl/logEnabled → bugCollectApiUrl/bugCollectEnabled
- assembleDebug 通过

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-16 17:39:23 +08:00