diff --git a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/BugCollectInitProvider.kt b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/BugCollectInitProvider.kt index 005a10e..f320718 100644 --- a/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/BugCollectInitProvider.kt +++ b/sdk-bugcollect/src/main/java/com/xuqm/sdk/bugcollect/internal/BugCollectInitProvider.kt @@ -31,15 +31,22 @@ internal class BugCollectInitProvider : ContentProvider() { override fun onCreate(): Boolean { val ctx = context?.applicationContext ?: return true - if (!XuqmSDK.isInitialized()) { - Log.w("BugCollect", "BugCollectInitProvider: XuqmSDK not initialized, skipping") + // ── Phase 1:注册崩溃拦截器(只需 appKey,无需 SDK 完全初始化)────────── + // SDK 可能正在后台初始化中,直接读取 config 文件获取 appKey + val appKey = if (XuqmSDK.isInitialized()) { + XuqmSDK.appKey + } else { + XuqmSDK.readAppKey(ctx) + } + + if (appKey.isNullOrBlank()) { + Log.w("BugCollect", "BugCollectInitProvider: no appKey available, skipping") return true } - // ── Phase 1:立即注册拦截器,只需 appKey,无需 URL ────────────────────── CrashCapture.start( appContext = ctx, - appKey = XuqmSDK.appKey, + appKey = appKey, getUserId = { XuqmSDK.getUserId() ?: XuqmSDK.deviceId }, ) diff --git a/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt b/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt index 308b5a3..1844e8d 100644 --- a/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt +++ b/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt @@ -78,6 +78,14 @@ object XuqmSDK { * 配置文件包含 `appKey` 和可选的 `serverUrl`(私有化部署平台地址)。 * App 无需调用任何初始化代码。 */ + /** + * 仅读取 config 文件中的 appKey,不做任何初始化。 + * 用于 ContentProvider 等需要快速获取 appKey 的场景。 + */ + fun readAppKey(context: Context): String? { + return runCatching { ConfigFileReader.read(context.applicationContext)?.appKey }.getOrNull() + } + fun autoInitialize(context: Context, logLevel: LogLevel = LogLevel.WARN) { val configFile = ConfigFileReader.read(context) ?: throw IllegalStateException( @@ -94,6 +102,33 @@ object XuqmSDK { initialize(context, configFile.appKey, configFile.serverUrl, logLevel) } + /** + * 异步自动初始化 — ContentProvider 调用,不阻塞主线程。 + * 同步阶段只读取 config 文件(~5ms),TokenStore / DeviceId / ApiClient 等重活移到 IO 线程。 + */ + fun autoInitializeAsync(context: Context, logLevel: LogLevel = LogLevel.WARN) { + val ctx = context.applicationContext + // 同步:读取 config(快,<10ms) + val configFile = ConfigFileReader.read(ctx) + if (configFile == null) { + Log.w("XuqmSDK", "autoInitializeAsync: no config file, skipping") + return + } + val configPackageName = configFile.packageName + if (!configPackageName.isNullOrBlank() && configPackageName != ctx.packageName) { + Log.w("XuqmSDK", "autoInitializeAsync: package name mismatch, skipping") + return + } + // 异步:TokenStore / DeviceId / ApiClient / 远端配置 + kotlinx.coroutines.CoroutineScope(kotlinx.coroutines.Dispatchers.IO + kotlinx.coroutines.SupervisorJob()).launch { + runCatching { + initialize(ctx, configFile.appKey, configFile.serverUrl, logLevel) + }.onFailure { e -> + Log.w("XuqmSDK", "autoInitializeAsync background init failed: ${e.message}") + } + } + } + /** * 方式 B:手动初始化。 * diff --git a/sdk-core/src/main/java/com/xuqm/sdk/internal/XuqmInitializerProvider.kt b/sdk-core/src/main/java/com/xuqm/sdk/internal/XuqmInitializerProvider.kt index 819af2d..e0fc111 100644 --- a/sdk-core/src/main/java/com/xuqm/sdk/internal/XuqmInitializerProvider.kt +++ b/sdk-core/src/main/java/com/xuqm/sdk/internal/XuqmInitializerProvider.kt @@ -15,9 +15,11 @@ import com.xuqm.sdk.XuqmSDK class XuqmInitializerProvider : ContentProvider() { override fun onCreate(): Boolean { val ctx = context?.applicationContext ?: return true + // 同步阶段只做最小工作:读取 config 文件设置 appKey(约 5ms) + // TokenStore / DeviceId / ApiClient 等重初始化移到后台线程 runCatching { if (!XuqmSDK.isInitialized()) { - XuqmSDK.autoInitialize(ctx) + XuqmSDK.autoInitializeAsync(ctx) } }.onFailure { e -> Log.w("XuqmSDK", "Auto-initialization skipped: ${e.message}")