3. 埋点 SDK 初始化与依赖注入:Gradle 配置、Application 初始化、Hilt/手动注入

埋点 SDK 的初始化是数据采集的起点,决定了事件能否正常上报、生命周期是否对齐、模块间是否可解耦。本章围绕 Gradle 依赖声明、Application 启动阶段初始化、依赖注入(Hilt / 手动注入) 三条主线,给出可落地的实现方案与调试要点。

本章目标:
✅ 理解 SDK 初始化时机对埋点质量的影响
✅ 掌握 Gradle 依赖管理与版本统一技巧
✅ 完成 Application 中安全的初始化流程
✅ 使用 Hilt 或手动注入将埋点实例注入到 ViewModel / Compose 层

3.1 Gradle 依赖配置与版本管理

埋点 SDK(以开源组件 TrackerSDK 为例)需作为 module 级别依赖引入。建议在项目根 build.gradle.kts 统一版本号,避免多 module 冲突。

// 项目级 build.gradle.kts
ext {
    set("trackerVersion", "2.1.0")
    set("hiltVersion", "2.48")
}
// app/build.gradle.kts
dependencies {
    implementation("com.example:tracker-sdk:${rootProject.ext["trackerVersion"]}")
    implementation("com.google.dagger:hilt-android:${rootProject.ext["hiltVersion"]}")
    kapt("com.google.dagger:hilt-compiler:${rootProject.ext["hiltVersion"]}")
}
模块作用典型版本
tracker-sdk核心埋点库,提供 TrackManager2.1.0
tracker-sdk-composeCompose 扩展(自动采集点击/曝光)2.1.0
hilt-android依赖注入框架2.48
常见错误: 若 Compose 模块与 SDK 版本不匹配,会导致 ComponentActivity 初始化异常。始终通过 ./gradlew app:dependencies 检查冲突。

3.2 Application 初始化埋点 SDK

在 onCreate() 中尽早初始化,但需注意不要阻塞主线程。推荐使用 ContentProvider 启动方式(SDK 内置)或手动调用。

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        // 手动初始化(适用于未使用自动启动的 SDK)
        val config = TrackerConfig.Builder()
            .appId("com.example.app")
            .channel("GooglePlay")
            .enableAutoPageTrack(true)
            .build()
        TrackerManager.init(this, config)
        // 注册 Activity 生命周期回调(自动采集页面停留)
        registerActivityLifecycleCallbacks(TrackerLifecycleCallbacks())
    }
}
调试技巧: 初始化后立即调用 TrackerManager.isInitialized() 确认状态;日志级别在 Debug 时设为 LogLevel.VERBOSE。

3.3 Hilt 注入实现

将 TrackerManager 封装为 Hilt 单例,便于在 ViewModel / UseCase 中直接注入。

// TrackerModule.kt
@Module
@InstallIn(SingletonComponent::class)
object TrackerModule {

    @Provides
    @Singleton
    fun provideTrackerManager(@ApplicationContext context: Context): TrackerManager {
        return TrackerManager.getInstance(context)
    }

    @Provides
    @Named("trackerConfig")
    fun provideTrackerConfig(): TrackerConfig {
        return TrackerConfig.Builder()
            .appId("com.example.app")
            .channel("GooglePlay")
            .enableAutoPageTrack(true)
            .build()
    }
}
// 在 ViewModel 中使用
@HiltViewModel
class HomeViewModel @Inject constructor(
    private val trackerManager: TrackerManager
) : ViewModel() {
    fun onButtonClicked(buttonId: String) {
        trackerManager.track(
            Event("button_click")
                .put("button_id", buttonId)
        )
    }
}

3.4 手动注入(无 Hilt 场景)

在不引入 Dagger/Hilt 的旧项目或小型 Demo 中,通过 Application 单例或 ServiceLocator 模式手动传递。

object TrackerLocator {
    private lateinit var trackerManager: TrackerManager

    fun init(context: Context) {
        val config = TrackerConfig.Builder()
            .appId("com.example.app")
            .build()
        trackerManager = TrackerManager.init(context, config)
    }

    fun getTracker(): TrackerManager = trackerManager
}

// 初始化
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        TrackerLocator.init(this)
    }
}

// ViewModel 中获取
class HomeViewModel : ViewModel() {
    private val tracker = TrackerLocator.getTracker()
    fun trackEvent() { tracker.track(Event("test")) }
}
稳定性提醒: 手动注入易出现 UninitializedPropertyAccessException。务必在 Application.onCreate() 结束后再访问 TrackerLocator.getTracker()。建议在 ViewModel 的 init 块中调用并捕获异常。

3.5 初始化时序与性能优化

埋点 SDK 初始化通常涉及文件读写、网络配置请求(如动态开关)。建议遵循以下流程:

  1. 第一阶段(onCreate):加载本地缓存配置 + 创建核心实例(< 10ms)
  2. 第二阶段(ContentProvider onCreate):如果 SDK 支持自动启动,可在 ContentProvider 中初始化,优先级高于 Application(但需注意 ContentProvider 生命周期)
  3. 第三阶段(首帧之后):发起远程配置请求、初始化定时上传任务(使用 frameCallback 或 Handler.postDelayed 延迟 500ms)
// 延迟初始化示例(适用于非关键模块)
Handler(Looper.getMainLooper()).postDelayed({
    TrackerManager.fetchRemoteConfig()
    TrackerManager.startUploadScheduler()
}, 500L)

3.6 本章核心流程图

埋点 SDK 初始化与依赖注入流程 Gradle 依赖声明 Application onCreate() ContentProvider 自动启动 TrackerConfig 构建 TrackerManager.init() 生命周期回调注册 Hilt Module 定义 手动 ServiceLocator ViewModel 注入/获取 Compose 层埋点调用

3.7 常见问题与调试

问题原因解决方案
初始化后事件不上报SDK 未收到配置或网络权限检查 AndroidManifest.xml 中 INTERNET 权限;打印日志观察配置回调
Hilt 注入报 @Inject field cannot be provided未在 @Module 提供 Provider确认 @Module 被 @InstallIn 声明,并检查 @Provides 方法签名
Compose 组件曝光重复采集同一组件多次注册生命周期使用 DisposableEffect 确保注册与反注册成对出现
部署检查清单:
□ Gradle 依赖版本与远程仓库一致
□ Application 中初始化置于 super.onCreate() 之后
□ Hilt 注入时标注 @Singleton 避免内存泄漏
□ 手动注入时添加 lateinit 判空保护