安卓使用 Startup 管理三方 SDK 初始化

安卓使用 Startup 管理三方 SDK 初始化

一、为什么要使用 Startup?

1. 第三方 SDK 是怎么 "悄悄初始化" 的?

很多 popular SDK(如 Bugly、友盟、高德地图、MMKV、各类推送与统计 SDK)都在自己的 AAR 包里内置了一个 ContentProvider

它会在 AndroidManifest.xml 中注册类似这样的配置:

xml 复制代码
<provider
    android:name="com.xxx.XXXProvider"
    android:authorities="${applicationId}.xxx"
    android:exported="false" />

而在这个 Provider 的 onCreate() 里,它会偷偷执行 SDK 初始化:

java 复制代码
@Override
public void onCreate() {
    XXXSDK.init(getContext()); // 自动初始化
}

你什么都不用做,App 一启动,几十个 SDK 就在主线程排队初始化,直接拖慢冷启动速度。

2. 为什么 ContentProvider 会自动执行?

系统启动 App 的流程是固定的:

  1. Zygote 孵化出 App 进程
  2. 创建 Application,执行 attachBaseContext()
  3. 实例化并执行所有 Manifest 中注册的 ContentProvider
  4. 执行 Application.onCreate()
  5. 启动第一个 Activity

关键点:

ContentProvider 的 onCreate () 会在 Application.onCreate () 之前自动执行!

所以 SDK 利用这个 "系统钩子" 实现自动初始化,结果就是:

App 还没进入你的代码,已经被一堆 SDK 卡死在启动阶段。

3. Jetpack Startup 解决了什么问题?

App Startup 的核心使命非常简单:

用一个统一的 ContentProvider,替代所有 SDK 各自为政的 N 个 ContentProvider。

只保留一个:

xml 复制代码
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false" />

好处:

  1. 减少大量组件创建开销
  2. 统一管理 SDK 初始化顺序
  3. 支持依赖声明 → 自动拓扑排序
  4. 支持手动 / 懒加载控制

它不是禁用 ContentProvider,而是把被滥用的 "自动初始化钩子" 重新收归统一管理。

4.Startup 的核心作用总结

  1. 取消每个 SDK 自己私有的 Provider
  2. 把所有初始化逻辑集中到你写的 Initializer
  3. 通过 dependencies () 声明依赖 → 自动按顺序执行
  4. 不会乱并发、不会乱序、不会阻塞主线程

二、使用startup

1. 引入依赖

groovy 复制代码
implementation "androidx.startup:startup-runtime:1.2.0"

2. 新建多个Initializer类

MainInitializer.kt

备注:统一入口,可选

kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.AppInitializer
import androidx.startup.Initializer

class MainInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // ========== 这里写所有需要启动初始化的库 ==========
        println("初始化:MainInitializer")
        initNetwork(context)
        initPush(context)
//        initBugly(context)
//        initMMKV(context)
//        initRouter(context)
    }

    // 网络
    private fun initNetwork(context: Context) {
        AppInitializer.getInstance(context)
            .initializeComponent(NetworkInitializer::class.java)
    }

    // 推送
    private fun initPush(context: Context) {
        AppInitializer.getInstance(context)
            .initializeComponent(PushInitializer::class.java)
    }

    // 依赖:如果没有依赖其他Initializer,就空
    override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
CrashInitializer.kt
kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.Initializer

class CrashInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // 执行崩溃库初始化
        println("初始化:崩溃监控")
    }

    /**
     * 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
     * App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
     */
    override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
NetworkInitializer.kt
kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.Initializer

class NetworkInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // 执行网络库初始化
        println("初始化:网络框架")
    }

    /**
     * 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
     * App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
     */
    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(CrashInitializer::class.java)
}
PushInitializer.kt
kotlin 复制代码
package com.example.startupdemo.initializer

import android.content.Context
import androidx.startup.Initializer

class PushInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        // 执行推送初始化
        println("初始化:推送服务")
    }

    /**
     * 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
     * App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
     */
    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(NetworkInitializer::class.java)
}

3. 初始化

方式 A:代码手动初始化(推荐)

更灵活、不抢启动、最安全:

kotlin 复制代码
// 在 Application 或 MainActivity 中
AppInitializer.getInstance(this)
    .initializeComponent(MainInitializer::class.java)

方式 B:XML 自动初始化(不推荐)

xml 复制代码
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">

    <meta-data
        android:name="com.example.startupdemo.initializer.MainInitializer"
        android:value="androidx.startup" />
</provider>

警告:如果不用 XML 配置,可以删除 <meta-data>,或使用 tools:node="remove" 让它失效。

4. 运行结果与demo

下载demo

复制代码
初始化:MainInitializer
初始化:崩溃监控
初始化:网络框架
初始化:推送服务

为什么顺序是这样?

  • NetworkInitializer 依赖 CrashInitializer
  • PushInitializer 依赖 NetworkInitializer
  • Startup 自动执行 拓扑排序 → 先依赖,后当前

由此实现:

  1. 初始化顺序完全可控
  2. 自动初始化 vs 懒加载 二选一
  3. 启动速度显著提升(减少 ContentProvider 数量)
  4. 代码结构更清晰、更好维护
相关推荐
千里马学框架20 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台20 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone20 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc21 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui