目录
  1. 1. 一、Jetpack 概述
    1. 1.1. 1.1 为什么需要 Jetpack
    2. 1.2. 1.2 Jetpack 的设计原则
    3. 1.3. 1.3 Jetpack 组件全景图
      1. 1.3.1. Architecture(架构组件)
      2. 1.3.2. Foundation(基础组件)
      3. 1.3.3. Behavior(行为组件)
      4. 1.3.4. UI(界面组件)
  2. 2. 二、AndroidX 迁移完全指南
    1. 2.1. 2.1 Support Library 到 AndroidX 的背景
    2. 2.2. 2.2 关键包名映射表
    3. 2.3. 2.3 组件 Artifact 映射表
    4. 2.4. 2.4 Jetifier 深度解析
    5. 2.5. 2.5 Android Studio 自动迁移工具
  3. 3. 三、构建系统配置
    1. 3.1. 3.1 Gradle Build 脚本配置
    2. 3.2. 3.2 Version Catalog(libs.versions.toml)
    3. 3.3. 3.3 BOM(Bill of Materials)统一版本管理
    4. 3.4. 3.4 buildSrc 约定插件
  4. 4. 四、多模块项目架构
    1. 4.1. 4.1 推荐的模块划分
    2. 4.2. 4.2 模块依赖关系
    3. 4.3. 4.3 每个模块的 build.gradle.kts 示例
  5. 5. 五、Compose vs View 体系决策指南
    1. 5.1. 5.1 何时选择 Jetpack Compose
    2. 5.2. 5.2 何时保留 View 体系
    3. 5.3. 5.3 渐进式迁移策略
    4. 5.4. 5.4 兼容性桥接代码
  6. 6. 六、项目初始化 Checklist
    1. 6.1. 6.1 环境准备
    2. 6.2. 6.2 基础配置
    3. 6.3. 6.3 架构搭建
    4. 6.4. 6.4 代码规范
  7. 7. 面试常考问题
  8. 8. 七、ProGuard / R8 与 Jetpack 配置
    1. 8.1. 7.1 Jetpack 组件的 ProGuard 规则
    2. 8.2. 7.2 R8 完全模式
  9. 9. 八、Kotlin Multiplatform 与 Jetpack 的关系
    1. 9.1. 8.1 现状与趋势
    2. 9.2. 8.2 跨平台共享策略
JetPack全家桶(一)之JetPack配置

自从 Google 在2018年推出 Jetpack 之后,它就成为了 Android 未来发展的风向标。同时 Google 也希望借助 Jetpack 统一开发者开发规范,可以说,如果还想在 Android 界驰骋沙场,Jetpack 是我们必须要掌握的杀招。

一、Jetpack 概述

1.1 为什么需要 Jetpack

在 Jetpack 诞生之前,Android 开发面临几个核心痛点:

碎片化问题:Android 生态中设备碎片化、API 级别碎片化、开发模式碎片化。同一功能(如后台任务)在不同 API 级别上需要不同的实现方式(AlarmManager、JobScheduler、Firebase JobDispatcher 等),开发者需要编写大量兼容性代码。

生命周期管理困难:Activity/Fragment 的生命周期极其复杂,在配置变更(屏幕旋转、语言切换)时数据容易丢失,异步任务回调时 Activity 可能已销毁,导致 NPE 崩溃和内存泄露。

样板代码泛滥findViewById、手动管理 FragmentTransaction 返回栈、SQLiteOpenHelper 编写重复的 CRUD 代码、为保留配置变更数据手动覆写 onSaveInstanceState 等,大量低价值的模板代码占据了开发时间。

架构不统一:缺乏官方推荐的架构指导,MVC、MVP、MVVM 各阵营争执不下,新人上手成本高,不同项目间的代码风格差异巨大。

Jetpack 正是在此背景下诞生:Google 将 Support Library 重构为 AndroidX,并在此基础上推出了一系列涵盖架构、UI、行为、基础四个领域的组件库集合,统称为 Jetpack。

1.2 Jetpack 的设计原则

Jetpack 的设计遵循四个核心原则:

  1. 向后兼容:绝大部分 Jetpack 组件兼容至 API 14(Android 4.0),个别组件(如 CameraX)需要 API 21+。Jetpack 通过内部兼容性封装,让开发者在旧设备上也能使用新 API 行为。

  2. 生命周期感知:Lifecycle 是 Jetpack 的基石。LiveData、ViewModel、WorkManager 等都是生命周期感知的,框架自动管理订阅/取消订阅,开发者无需关心生命周期同步问题。

  3. 模块化与解耦:每个 Jetpack 组件独立发布、独立语义化版本(Semantic Versioning)。开发者按需引入,不会因为引入一个组件而被强制升级整个套件。

  4. 最佳实践内置:Jetpack 组件封装了经过大量实战验证的最佳实践。例如 Room 在编译期验证 SQL 语法、Paging 内置了 DiffUtil 增量更新、WorkManager 自动选择最优调度器。

1.3 Jetpack 组件全景图

Jetpack 组件按功能分为四大类别:

Architecture(架构组件)

组件 说明
Lifecycle 生命周期感知基类,所有生命周期感知组件的基石
LiveData 生命周期感知的可观察数据持有者
ViewModel 管理 UI 数据,在配置变更时存活
Room SQLite 对象映射库,编译期 SQL 验证
Paging 分页加载库,支持本地/网络混合数据源
Navigation Fragment/Compose 导航管理
WorkManager 后台任务调度(保证执行)
DataStore 替代 SharedPreferences 的键值/类型安全存储
DataBinding 声明式 UI 数据绑定

Foundation(基础组件)

组件 说明
AppCompat 向后兼容的 Activity/Fragment 基类
Android KTX Kotlin 扩展函数集,简化 API 调用
Multidex 突破 64K 方法数限制
Test Android 测试库
Security 加密 SharedPreferences 和文件
Startup 应用启动时初始化依赖

Behavior(行为组件)

组件 说明
CameraX 相机 API 封装,向后兼容
DownloadManager 长时间下载任务管理
Media & Playback 媒体播放(Media3/ExoPlayer)
Notifications 通知栏管理与样式化
Permissions 权限请求封装
Preferences/Settings 用户偏好设置
Sharing 分享操作

UI(界面组件)

组件 说明
Fragment 模块化 UI 容器
Layout (ConstraintLayout) 高性能布局
Animation & Transitions 动画与过渡
Emoji 新版 Emoji 兼容
WebView 系统 WebView 封装
Compose 声明式 UI 工具包(下一代 UI 框架)
Palette 从图片提取配色方案

二、AndroidX 迁移完全指南

2.1 Support Library 到 AndroidX 的背景

从 Android 1.0 开始,Google 提供了 android.support.* 包(Support Library)来向旧版本设备提供新 API 功能。但随着时间推移,Support Library 暴露出严重问题:

  • 统一版本号枷锁:所有 Support Library 库共享同一个版本号(如 28.0.0),即使某个库没有变更也必须跟着升级。
  • 包名与系统类冲突android.support.v4.app.Fragment 与系统 android.app.Fragment 名称相似,容易混淆。
  • 维护成本高:Support Library 被大量第三方库依赖,升级一个库可能触发连锁依赖冲突。

AndroidX 是 Support Library 的重写版本,使用 androidx.* 包命名空间,每个组件独立语义化版本控制。AndroidX 从 Android 9.0(API 28)开始被积极推广,Support Library 28.0.0 是最后一个版本,之后停止维护。

2.2 关键包名映射表

从 Support Library 迁移到 AndroidX 最核心的工作是包名替换:

Support Library 包名 AndroidX 包名
android.support.v4.app.Fragment androidx.fragment.app.Fragment
android.support.v4.app.FragmentActivity androidx.fragment.app.FragmentActivity
android.support.v7.app.AppCompatActivity androidx.appcompat.app.AppCompatActivity
android.support.v7.widget.RecyclerView androidx.recyclerview.widget.RecyclerView
android.support.v7.widget.Toolbar androidx.appcompat.widget.Toolbar
android.support.v7.widget.CardView androidx.cardview.widget.CardView
android.support.design.widget.CoordinatorLayout androidx.coordinatorlayout.widget.CoordinatorLayout
android.support.design.widget.FloatingActionButton com.google.android.material.floatingactionbutton.FloatingActionButton
android.support.constraint.ConstraintLayout androidx.constraintlayout.widget.ConstraintLayout
android.support.v4.content.LocalBroadcastManager androidx.localbroadcastmanager.content.LocalBroadcastManager
android.support.test.runner.AndroidJUnitRunner androidx.test.runner.AndroidJUnitRunner
android.support.v4.view.ViewPager androidx.viewpager.widget.ViewPager
android.support.v4.widget.SwipeRefreshLayout androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android.arch.lifecycle.LiveData androidx.lifecycle.LiveData
android.arch.lifecycle.ViewModel androidx.lifecycle.ViewModel
android.arch.persistence.room.RoomDatabase androidx.room.RoomDatabase

2.3 组件 Artifact 映射表

除了包名变化外,Gradle 的依赖坐标也需要对应迁移:

Support Library Artifact AndroidX Artifact
com.android.support:appcompat-v7:28.0.0 androidx.appcompat:appcompat:1.7.0
com.android.support:recyclerview-v7:28.0.0 androidx.recyclerview:recyclerview:1.3.2
com.android.support:cardview-v7:28.0.0 androidx.cardview:cardview:1.0.0
com.android.support:design:28.0.0 com.google.android.material:material:1.12.0
com.android.support:support-v4:28.0.0 androidx.legacy:legacy-support-v4:1.0.0
com.android.support.constraint:constraint-layout:1.1.3 androidx.constraintlayout:constraintlayout:2.1.4
com.android.support:multidex:1.0.3 androidx.multidex:multidex:2.0.1
android.arch.lifecycle:extensions:1.1.1 androidx.lifecycle:lifecycle-extensions:2.2.0(已废弃,改用具体组件)
android.arch.persistence.room:runtime:1.1.1 androidx.room:room-runtime:2.6.1
android.arch.navigation:navigation-fragment:1.0.0 androidx.navigation:navigation-fragment:2.7.7

注意 Design 库的迁移路径:com.android.support:design 不仅改了包名,还改了 GroupId —— 变成 com.google.android.material:material。这是 Google 将 Material Design 组件从 AppCompat 中独立出来的产物。

2.4 Jetifier 深度解析

Jetifier 是 Android Gradle Plugin(AGP)内置的一个构建期字节码转换工具。当启用 android.enableJetifier=true 后,AGP 在编译过程中会扫描所有依赖(包括 AAR 和 JAR)的字节码,将 Support Library 类名、包名、资源引用自动迁移到 AndroidX 对应项。

Jetifier 的工作原理:

  1. 解析所有传递依赖的 .jar.aar 文件
  2. 对每个 class 文件执行 ASM 字节码扫描
  3. 匹配预定义的转换规则表(由 Google 维护)
  4. 改写类名、方法签名、字段类型中的 Support 引用
  5. 改写布局 XML 和资源引用
  6. 输出转换后的依赖给后续编译流程

Jetifier 的配置:

# gradle.properties
android.useAndroidX=true
android.enableJetifier=true

注意:Jetifier 会增加构建时间(每个依赖都需要扫描转换),因此一旦项目中所有依赖都已原生支持 AndroidX,应该关闭 Jetifier:

android.enableJetifier=false

可以通过 Gradle 的 dependencies 任务检查是否有依赖仍引用 Support Library:

./gradlew :app:dependencies --configuration releaseRuntimeClasspath | grep "com.android.support"

2.5 Android Studio 自动迁移工具

Android Studio 提供了 “Refactor → Migrate to AndroidX” 一键迁移功能。该工具会:

  • 将所有依赖坐标从 Support 替换为 AndroidX
  • 替换源代码中所有 import 语句和类引用
  • 替换 XML 布局中的控件类名
  • 替换 Gradle 文件中的依赖声明
  • 生成 .idea/migrateToAndroidX.xml 记录迁移状态

迁移前务必:

  1. 将项目完全 commit 到版本控制
  2. 备份 gradle.properties
  3. 更新 AGP 到 3.2.0 以上
  4. 确保 compileSdkVersion >= 28

迁移后验证:

  1. 检查 build.gradle 中是否仍有 com.android.support 坐标
  2. 搜索源代码中是否仍有 android.support import
  3. 搜索布局 XML 中是否仍有 android.support.* 类名
  4. Gradle Sync + Build 看是否报错
  5. 运行 Lint 检查:./gradlew lint

三、构建系统配置

3.1 Gradle Build 脚本配置

根项目 build.gradle.kts:

// 根项目 build.gradle.kts
plugins {
id("com.android.application") version "8.5.0" apply false
id("com.android.library") version "8.5.0" apply false
id("org.jetbrains.kotlin.android") version "2.0.0" apply false
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0" apply false
id("com.google.dagger.hilt.android") version "2.51.1" apply false
id("androidx.navigation.safeargs.kotlin") version "2.7.7" apply false
id("com.google.devtools.ksp") version "2.0.0-1.0.22" apply false
}

tasks.register("clean", Delete::class) {
delete(rootProject.layout.buildDirectory)
}

gradle.properties 关键配置:

# AndroidX 必需
android.useAndroidX=true
android.enableJetifier=false

# Kotlin 编译选项
kotlin.code.style=official
kotlin.daemon.jvmargs=-Xmx2g

# Gradle 性能优化
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true

# Android 构建配置
android.nonTransitiveRClass=true
android.enableR8.fullMode=true

3.2 Version Catalog(libs.versions.toml)

Gradle 7.0+ 引入 Version Catalog 作为官方推荐的依赖版本管理方案。在 gradle/libs.versions.toml 中集中管理:

# gradle/libs.versions.toml
[versions]
agp = "8.5.0"
kotlin = "2.0.0"
ksp = "2.0.0-1.0.22"

# AndroidX Core
core-ktx = "1.13.1"
activity-ktx = "1.9.0"
fragment-ktx = "1.8.1"

# Jetpack Architecture
lifecycle = "2.8.3"
navigation = "2.7.7"
room = "2.6.1"
paging = "3.3.0"
work = "2.9.0"
datastore = "1.1.1"

# Jetpack UI
appcompat = "1.7.0"
material = "1.12.0"
constraintlayout = "2.1.4"
recyclerview = "1.3.2"
viewpager2 = "1.1.0"
compose-bom = "2024.06.00"
compose-compiler = "1.5.14"

# Network
retrofit = "2.11.0"
okhttp = "4.12.0"
moshi = "1.15.1"

# DI
hilt = "2.51.1"

# Image loading
coil = "2.6.0"

# Testing
junit = "4.13.2"
mockk = "1.13.12"
turbine = "1.1.0"

[libraries]
# Core
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "core-ktx" }
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activity-ktx" }
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx" }

# Lifecycle
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle" }
androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" }
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }

# Navigation
androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" }
androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" }
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation" }

# Room
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
androidx-room-paging = { module = "androidx.room:room-paging", version.ref = "room" }

# Paging
androidx-paging-runtime-ktx = { module = "androidx.paging:paging-runtime-ktx", version.ref = "paging" }
androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging" }

# WorkManager
androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "work" }
androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "work" }

# DataStore
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" }
androidx-datastore-proto = { module = "androidx.datastore:datastore-proto", version.ref = "datastore" }

# UI
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
material = { module = "com.google.android.material:material", version.ref = "material" }
androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" }
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" }

# Compose BOM
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose-bom" }
compose-ui = { module = "androidx.compose.ui:ui" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
compose-material3 = { module = "androidx.compose.material3:material3" }
compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }

# Network
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
moshi = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi" }
moshi-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshi" }

# Hilt
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" }

# Image
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }

# Test
junit = { module = "junit:junit", version.ref = "junit" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
androidx-test-core = { module = "androidx.test:core-ktx", version = "1.5.0" }
androidx-test-runner = { module = "androidx.test:runner", version = "1.5.2" }
androidx-test-espresso = { module = "androidx.test.espresso:espresso-core", version = "3.5.1" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
safeargs = { id = "androidx.navigation.safeargs.kotlin", version.ref = "navigation" }

3.3 BOM(Bill of Materials)统一版本管理

对于 Jetpack 中版本高度耦合的组件(如 Compose、Lifecycle),Google 提供了 BOM 依赖。BOM 本质上是一个 POM 文件,声明了一组库的统一版本:

// 使用 Compose BOM,无需逐个指定 Compose 组件版本
dependencies {
implementation(platform("androidx.compose:compose-bom:2024.06.00"))
implementation("androidx.compose.ui:ui") // 版本由 BOM 指定
implementation("androidx.compose.material3:material3") // 版本由 BOM 指定
implementation("androidx.compose.ui:ui-tooling-preview") // 版本由 BOM 指定
androidTestImplementation(platform("androidx.compose:compose-bom:2024.06.00"))
debugImplementation("androidx.compose.ui:ui-tooling") // 版本由 BOM 指定
}

Compose 的 BOM 使用 platform() 声明,这样所有 Compose 组件的版本都来自同一个 BOM,保证兼容性。

Lifecycle 也有类似的 BOM 机制(通过版本号对齐),也可以通过定义 ext 变量的方式批量管理:

// build.gradle.kts 中 ext 方式(适用于版本一致的系列)
val lifecycleVersion = "2.8.3"
implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion")

3.4 buildSrc 约定插件

对于大型多模块项目,推荐创建 buildSrc 目录管理公共构建配置。但更现代的做法是创建包含约定插件(Convention Plugin)的独立模块。

.
├── build.gradle.kts
├── settings.gradle.kts
├── gradle/
│ └── libs.versions.toml
├── build-logic/
│ ├── settings.gradle.kts
│ └── convention/
│ ├── build.gradle.kts
│ └── src/main/kotlin/
│ ├── android-application.gradle.kts
│ ├── android-library.gradle.kts
│ ├── android-hilt.gradle.kts
│ └── android-compose.gradle.kts
└── app/
└── build.gradle.kts

android-application.gradle.kts(约定插件示例):

// build-logic/convention/src/main/kotlin/android-application.gradle.kts
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}

android {
compileSdk = 34

defaultConfig {
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}

buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
isMinifyEnabled = false
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = "17"
}
}

四、多模块项目架构

4.1 推荐的模块划分

Google 推荐的架构中,应将应用划分为多个 Gradle Module:

:app                    # Application 入口,依赖注入装配
:feature:home # 首页 Feature
:feature:detail # 详情页 Feature
:feature:settings # 设置页 Feature
:core:data # 数据层(Repository、DataSource)
:core:domain # 领域层(UseCase、Domain Model)
:core:network # 网络层(OkHttp、Retrofit 配置)
:core:database # 数据库层(Room Database、DAO)
:core:ui # UI 公共组件(主题、通用控件)
:core:model # 跨模块共享的数据模型
:core:testing # 测试工具(TestDispatcher、Fake Repository)

4.2 模块依赖关系

:app
├── :feature:home ──────┐
├── :feature:detail ────┤
└── :feature:settings ──┤

┌────────────────┘

:core:domain ───── :core:model


:core:data ─────── :core:database, :core:network


:core:ui (仅 UI 公共组件)
:core:testing (testImplementation)

核心约束:

  • :feature:* 模块只依赖 :core:domain:core:ui
  • :core:domain 不依赖任何 Android 框架(纯 Kotlin/Java 模块)
  • :core:data 实现 :core:domain 中定义的接口(依赖反转)
  • :app 通过 Hilt 完成依赖注入的装配

4.3 每个模块的 build.gradle.kts 示例

:core:domain(纯 Kotlin 模块):

plugins {
alias(libs.plugins.kotlin.android) // 或者直接 id("kotlin")
}

dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.core)
testImplementation(libs.junit)
testImplementation(libs.mockk)
testImplementation(libs.turbine)
testImplementation(libs.kotlinx.coroutines.test)
}

:core:data(Android Library):

plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.hilt)
}

android {
namespace = "com.example.core.data"
}

dependencies {
implementation(project(":core:domain"))
implementation(project(":core:database"))
implementation(project(":core:network"))

implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)

implementation(libs.retrofit)
implementation(libs.moshi)
ksp(libs.moshi.codegen)

implementation(libs.hilt.android)
ksp(libs.hilt.compiler)

implementation(libs.androidx.datastore.preferences)
}

五、Compose vs View 体系决策指南

5.1 何时选择 Jetpack Compose

适合 Compose 的场景:

  • 全新项目,没有历史遗留代码
  • UI 复杂度高,状态管理需求突出
  • 需要大量动画与自定义绘制
  • 团队已熟悉 Kotlin 与声明式 UI 范式
  • 需要跨平台(Compose Multiplatform)

Compose 的核心优势:

  • 声明式 UI:描述 UI 应该是什么样,框架负责增量更新
  • 无 XML:代码即 UI,减少文件跳转,重构更安全
  • 强大的状态管理:remembermutableStateOfStateFlow.collectAsState()
  • 原生性能:Compose 编译器将 Composable 编译为高效的树更新逻辑
  • 与 View 互操作:AndroidView / ComposeView 双向嵌入

5.2 何时保留 View 体系

适合传统 View 体系的场景:

  • 大型存量项目,已有大量 XML 布局和自定义 View
  • 团队尚未掌握 Compose(学习曲线)
  • 需要使用尚未 Compose 友好的第三方库(如某些地图 SDK)
  • 需要 WebView 重交互场景(Compose 的 WebView 封装仍不够完善)
  • 有大量使用 DataBinding 的已有代码

5.3 渐进式迁移策略

从 View 向 Compose 渐进迁移的路线图:

  1. 底部 Sheet / 弹窗:先用 Compose 编写 Dialog、BottomSheet,通过 DialogFragment + ComposeView 桥接。
  2. 列表 Item:在 RecyclerView 中通过 ComposeView 渲染单个 item。
  3. 独立页面:新建功能页面直接用 Compose Fragment(fragment-compose 提供了 ComponentActivity.setContent 等价物)。
  4. 主页面:将主要的 Fragment 逐步替换为 Compose。
  5. Navigation:迁移到 navigation-compose,告别 Fragment。

5.4 兼容性桥接代码

在 XML 中嵌入 Compose:

<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
binding.composeView.setContent {
MyComposeTheme {
MyComposableContent()
}
}

在 Compose 中嵌入 View:

@Composable
fun MyScreen() {
AndroidView(
factory = { context ->
WebView(context).apply {
settings.javaScriptEnabled = true
loadUrl("https://example.com")
}
},
update = { webView ->
webView.evaluateJavascript("updateContent()", null)
}
)
}

六、项目初始化 Checklist

启动一个 Jetpack 新项目的完整检查清单:

6.1 环境准备

  • Android Studio Hedgehog (2023.1.1) 或更新版本
  • Gradle 8.5+ / AGP 8.5+
  • Kotlin 2.0+
  • compileSdk = 34, targetSdk = 34, minSdk = 24
  • 创建 Version Catalog (gradle/libs.versions.toml)

6.2 基础配置

  • gradle.properties:android.useAndroidX=true
  • 引入 AppCompat、Material Design、ConstraintLayout
  • 引入 Lifecycle + ViewModel + LiveData KTX
  • 引入 Navigation + Safe Args 插件
  • 配置 Hilt 依赖注入
  • KSP 替代 kapt(提升编译速度)

6.3 架构搭建

  • 创建多模块目录结构
  • 配置 build-logic 约定插件
  • 创建 Application 类,添加 @HiltAndroidApp
  • 实现 Single Activity 架构(MainActivity + NavHost)
  • 定义 Theme / 颜色系统
  • 配置 CI pipeline(GitHub Actions / Jenkins)

6.4 代码规范

  • ktlintdetekt 静态检查
  • .editorconfig 统一代码风格
  • Git hooks pre-commit 检查
  • 编写 README 与架构文档(建议使用 PlantUML 或 Mermaid)

面试常考问题

Q1:AndroidX 与 Support Library 的区别?

AndroidX 是 Support Library 的升级版,核心区别:

  • 包名从 android.support.* 变为 androidx.*
  • 独立语义化版本控制,每个组件可独立升级
  • Support 28.0.0 之后停止维护
  • Jetifier 工具可在编译期将 Support 引用自动转换为 AndroidX
  • Design 库拆分为独立的 Material Components(com.google.android.material:material
  • ViewPager 拆分为 ViewPager2(基于 RecyclerView,支持垂直滑动和 RTL)

Q2:enableJetifier 的作用是什么?

Jetifier 在构建过程中扫描所有依赖的字节码,将 Support Library 类名、包名、资源引用自动迁移到 AndroidX 对应项:

  1. 解析 AAR/JAR 文件中的 class 字节码
  2. 查找 Support Library 类引用(如 android.support.v7.app.AppCompatActivity
  3. 替换为对应 AndroidX 类引用(如 androidx.appcompat.app.AppCompatActivity
  4. 同时改写资源引用和布局 XML

适用于依赖了尚未迁移 AndroidX 的第三方库的场景。当所有依赖都原生支持 AndroidX 后应关闭以提升构建速度。AOSP 源码路径:frameworks/support/ 目录(现已整体迁移为 AndroidX 仓库)。

Q3:Jetpack Compose 与传统 View 体系如何共存?

  • Compose → View:通过 ComposeView(一个 ViewGroup 子类)将 Composable 内容嵌入传统布局,调用 composeView.setContent { ... }
  • View → Compose:通过 AndroidView Composable 将传统 View 嵌入 Compose 树
  • Activity:ComponentActivity.setContent { ... } 替代 setContentView()
  • Fragment:引入 androidx.fragment:fragment-compose,Fragment 中使用 onCreateView 返回 ComposeView
  • Navigation:navigation-compose 提供 NavHost Composable,无需 Fragment
  • 推荐策略:新页面用 Compose,存量页面保持 View,通过互操作机制渐进迁移

Q4:Version Catalog 相比 buildSrc 的优势?

Version Catalog(libs.versions.toml)是 Gradle 7.0 引入的官方方案:

  • 声明式配置,无需编译,IDE 自动提示
  • Gradle 原生支持,不需要额外插件
  • 可通过 libs.versions.xxx 在 settings.gradle.kts 中访问
  • buildSrc 每次变更都要重新编译整个构建逻辑,Version Catalog 则无需
  • 两者可以共存:Version Catalog 管理版本号,buildSrc/convention plugins 管理构建逻辑

Q5:DataBinding vs ViewBinding 如何选择?

  • ViewBinding:轻量、编译快,仅生成 View 引用类,无布局表达式,适合不需要数据驱动的场景
  • DataBinding:功能全(布局表达式、双向绑定、BindingAdapter),构建速度较慢,适合 MVVM 中数据需要驱动 UI 的场景
  • 底线:如果不需要布局表达式和双向绑定,直接用 ViewBinding,切勿为了 DataBinding 而 DataBinding
  • Compose 项目中两者都不需要 —— Compose 本身通过状态驱动 UI 更新

Q6:KSP 与 kapt 的区别?为何推荐迁移到 KSP?

KSP(Kotlin Symbol Processing)是 Google 开发的 Kotlin 编译期注解处理器,作为 kapt 的替代方案:

  • 性能:KSP 比 kapt 快 2~3 倍。kapt 需要先将 Kotlin 代码编译为 Java Stub(为了兼容 Javac 注解处理器),这一步骤非常耗时;KSP 直接解析 Kotlin 源码 AST,无中间产物
  • 实现语言:kapt 底层是 Java 注解处理器(JSR 269),用 Java 编写处理器;KSP 提供原生 Kotlin API,处理器用 Kotlin 编写
  • 内存占用:kapt 的 Java Stub 生成阶段占用大量内存;KSP 增量处理,内存开销更小
  • 支持状态:Google 已明确 KSP 是长期方向,Room 2.5+、Moshi 1.14+ 已支持 KSP
  • 迁移路径:将 kapt 依赖替换为 ksp,编译器实现从 @AutoService(Processor::class) 改为实现 SymbolProcessor 接口

七、ProGuard / R8 与 Jetpack 配置

7.1 Jetpack 组件的 ProGuard 规则

大部分 Jetpack 组件在 AAR 中内嵌了 proguard.txt(通过 consumerProguardFiles 声明),AGP 会自动应用这些规则。但以下组件需要手动添加:

# Lifecycle - 保持 LifecycleObserver 方法不被混淆
-keep class * implements androidx.lifecycle.LifecycleObserver {
@androidx.lifecycle.OnLifecycleEvent(...);
}

# Room - 保持 Entity 和 DAO
-keep class * extends androidx.room.RoomDatabase
-keep @androidx.room.Entity class *
-keep @androidx.room.Dao interface *

# DataBinding - 保持 BR 类和生成的 Binding 类
-keep class androidx.databinding.DataBindingComponent { *; }
-keep class * extends androidx.databinding.ViewDataBinding
-keepclassmembers class * extends androidx.databinding.ViewDataBinding {
<init>(...);
}

# Navigation - 保持 NavArgs
-keep class * extends androidx.navigation.NavArgs

# Hilt
-keep class dagger.hilt.** { *; }
-keep class javax.inject.** { *; }
-keep class * extends dagger.hilt.android.internal.managers.ViewComponentManager$FragmentContextWrapper { *; }

7.2 R8 完全模式

AGP 7.0+ 默认启用 R8 进行代码压缩、混淆和优化。在 gradle.properties 中开启 R8 完全模式:

android.enableR8.fullMode=true

完全模式下 R8 会进行更激进的优化(方法内联、分支裁剪、类合并),但可能与某些反射调用冲突。如果遇到问题,可以通过 -keep 规则保留关键类。

Jetpack 组件大多已经过 R8 完全模式测试,但需要注意:

  • Room 的 @Entity@ColumnInfo 注解类不应被混淆(AAR 自带规则会处理)
  • Paging 使用反射处理 LoadStateAdapter,需要保留相关类
  • DataBinding 在运行时通过反射访问生成类,必须 -keep

八、Kotlin Multiplatform 与 Jetpack 的关系

8.1 现状与趋势

Google 正在将 Jetpack 逐步向 Kotlin Multiplatform (KMP) 迁移:

  • **Room 2.7+**:已支持 KMP,可在 Android 和 iOS 上共享数据库层
  • **DataStore 1.2+**:支持 KMP Preferences DataStore
  • Lifecycle / ViewModel:已有 lifecycle-viewmodel-compose 用于 Compose Multiplatform
  • Navigationnavigation-compose 逐步解耦 Fragment 依赖

8.2 跨平台共享策略

shared/                         # KMP 共享模块
├── commonMain/ # 跨平台共享代码
│ ├── data/ # Room Database (共享)
│ ├── domain/ # UseCase (共享)
│ └── util/ # 工具类 (共享)
├── androidMain/ # Android 平台实现
│ └── di/ # Hilt 依赖注入 (Android only)
└── iosMain/ # iOS 平台实现
└── di/ # iOS DI(非 Hilt,如 Koin)

androidApp/ # Android UI(Jetpack Compose)
iosApp/ # iOS UI(SwiftUI 或 Compose Multiplatform)

这种架构下,Room Database、Repository、UseCase、数据验证逻辑全部在 shared/commonMain 中实现,Android 和 iOS 两侧共享。UI 层各自用原生框架实现(Android 用 Jetpack Compose,iOS 用 SwiftUI)。

打赏
  • 微信
  • 支付宝

评论