Android版本管理+混淆
今日核心目标
- 掌握组件化工程中依赖管理的核心方法(版本统一、依赖隔离),彻底解决依赖冲突痛点。
- 精通组件化混淆的完整配置(全局混淆+组件混淆),确保release模式下工程正常运行。
- 规避依赖管理和混淆的高频踩坑点。
依赖管理
围绕以下几点
- 依赖管理认知
- 依赖管理实战(基于Version Catalog)
依赖管理认知
价值
- 解决组件化工程中“依赖版本混乱、依赖冲突、重复引入、依赖冗余”等痛点。
- 实现依赖的统一管理和隔离,提升工程稳定性、可维护性和可扩展性,减少因依赖问题导致的编译报错、运行崩溃。
概念
明确3个核心依赖类型
- implementation(""):推荐优先使用
- api("")
- compileOnly("")
implementation(""):推荐优先使用
- 依赖仅在当前组件内部可见
- 不传递给依赖当前组件的其他组件
- 用于组件内部依赖,降低耦合
api("")
- 依赖会传递给依赖当前组件的其他组件
- 用于base基础组件对外提供的公共依赖(如ARouter、Hilt核心依赖),避免重复引入
compileOnly("")
- 仅在编译期生效,运行期不打包,用于解决“编译期依赖但运行期无需打包”的场景
- 例:系统中间件依赖、注解处理器、编译期工具
原则
- 版本统一:所有组件的相同依赖(如ARouter、Hilt)使用同一版本,通过Version Catalog统一管理。
- 依赖隔离:不同组件的内部依赖使用implementation,公共依赖通过base组件用api暴露,避免交叉依赖。
- 避免冗余:不重复引入同一依赖,删除无用依赖,减少工程体积。
- 版本兼容:确保Hilt、ARouter等插件与Android Gradle插件版本兼容。
依赖管理实战(基于Version Catalog)
Version Catalog为当前主流的版本管理方案,也是Android Studio新建项目默认的版本管理方案。
- 依赖版本统一定义在
gradle/libs.versions.toml文件。
围绕以下几点
- Version Catalog基础配置
- 依赖隔离与冗余清理
- 依赖冲突解决实战
- 依赖管理小结
Version Catalog基础配置
- 1.创建Version Catalog配置文件(旧项目,新项目默认采用Version Catalog)
- 在工程根目录gradle目录下,新建
libs.versions.toml文件(Android Studio4.2+会自动识别该文件) - 配置versions(版本号)、libraries(依赖库)、plugins(插件),统一管理所有依赖
- 在工程根目录gradle目录下,新建
[versions] # 版本
# Android基础版本
compileSdk = "36"
minSdk = "30"
targetSdk = "36"
# 插件版本
agp = "8.12.3" # Android Gradle插件版本
kotlin = "2.0.21" # 与项目Kotlin版本保持一致
hilt = "2.57.2" # Hilt插件版本
# 依赖库版本
coreKtx = "1.17.0"
junit = "4.13.2"
junitVersion = "1.3.0"
espressoCore = "3.7.0"
appcompat = "1.7.1"
material = "1.13.0"
constraintlayout = "2.2.1"
[libraries] # 依赖库
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
[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" }
hilt-android-gradle = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
- 2.项目根目录
build.gradle.kts配置
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
}
- 3.组件或模块
build.gradle.kts配置
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.hilt.android.gradle)
}
android {
namespace = "com.xxx.xxx"
compileSdk = libs.versions.compileSdk.get().toInt()
defaultConfig {
applicationId = "com.xxx.xxx"
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.targetSdk.get().toInt()
...
}
...
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
...
}
依赖隔离与冗余清理
优化依赖引用方式,结合Version Catalog的规范,实现依赖隔离,删除冗余依赖,降低组件间耦合。
依赖隔离优化
- 检查base组件:仅保留公共依赖,在libs.versions.toml的libraries中配置,用api暴露;
- 组件内部专用依赖,单独在base的build.gradle中用implementation引用(或添加到libs.toml后引用)
- 检查user组件:所有依赖均使用implementation(除了依赖base组件),不使用api(避免依赖传递);
- 所有依赖均通过Version Catalog引用,不硬编码版本,确保版本统一
- 确保user组件的依赖不会传递给壳工程或其他组件,实现依赖隔离
- 检查壳工程:仅依赖base和user组件,不直接引入ARouter、Hilt核心依赖(避免重复引入);
- 壳工程内部依赖,通过Version Catalog引用,规范管理
冗余依赖清理
- 删除所有组件中未使用的依赖(如测试依赖、无用第三方依赖),同步删除libs.versions.toml中对应的配置
- 检查是否有重复引入的依赖(如base组件已通过api暴露ARouter,user和壳工程无需再引入)
- 清理步骤
- 打开各组件的
build.gradle.kts,删除“unused”标记的依赖(Android Studio会自动提示) - 同步工程,检查无报错,打包确认功能正常
- 重点清理:重复引入的ARouter、Hilt依赖,无用的测试依赖(testImplementation相关),并同步清理libs.toml中的冗余配置
- 打开各组件的
依赖冲突解决实战
场景1:ARouter/Hilt版本不统一导致的冲突
- 现象:编译报错,提示“Duplicate class com.alibaba.android.arouter.xxx”。
- 原因:各组件手动硬编码不同版本的ARouter/Hilt。
- 修复:所有组件均通过Version Catalog的libs.xxx引用依赖,不硬编码版本;若有组件硬编码版本,修改为libs引用,确保所有组件版本统一,删除重复引入。
场景2:Hilt插件与Android Gradle插件版本不兼容
- 现象:编译报错,提示“Could not find com.google.dagger:hilt-android-gradle-plugin:xxx”或“Plugin compatibility error”
- 原因:Hilt插件版本与Android Gradle插件版本不匹配(例:本项目中Hilt 2.57.2 适配Android Gradle 8.7.2)
- 修复
- 查看Hilt官方文档,确认适配的Android Gradle插件版本
- 在libs.versions.toml中调整agp(Android Gradle插件)或hilt(Hilt版本),确保兼容
- 同步工程,确保插件引用均通过Version Catalog,无硬编码版本
场景3:重复引入同一依赖导致的冲突
- 现象:编译报错,提示“Duplicate entry: xxx”
- 原因:多个组件重复引入了同一依赖(如base和user组件都直接引入ARouter)
- 修复
- 在base组件中通过api libs.arouter-api暴露公共依赖,其他组件依赖base组件,间接获取该依赖
- 若无法避免重复引入,使用exclude排除重复依赖
// 例:壳工程重复引用ARouter依赖,排除
implementation(project(":user")) {
exclude(group = "com.alibaba", module = "arouter-api") // 排除user组件中的ARouter依赖
}
依赖管理小结
-
版本统一是基础,通过Version Catalog(gradle/libs.versions.toml)管理所有依赖版本和插件,避免版本混乱;
-
依赖隔离是关键,用implementation实现组件内部依赖隔离,用api暴露公共依赖;
-
冗余清理是习惯,定期删除无用依赖,同步清理Version Catalog中的冗余配置,避免工程体积膨胀;
-
冲突解决是能力,掌握常见冲突场景的解决方案,结合Version Catalog的特性,提升问题排查效率。
-
实践技巧
- 大型项目中,必须使用Version Catalog管理依赖,规范依赖引用,避免硬编码版本;
- 每新增一个依赖,先添加到Version Catalog的libraries中,再通过libs.xxx引用,确保版本统一;
- 优先使用implementation,减少api的使用,降低依赖传递带来的耦合;
- 定期同步依赖版本,在Version Catalog中统一更新,及时修复版本兼容问题,提升工程稳定性;
- 多人协作时,Version Catalog可实现依赖版本统一,避免因版本不一致导致的协作问题。
混淆
围绕以下几点
- 混淆认知
- 全局混淆配置
- 组件混淆配置
混淆认知
价值
- 混淆的核心作用是“代码加密、压缩体积、防止反编译”。
- 商用版本必须配置混淆,这是项目安全和合规的基本要求,是开发者的必备技能。
特点
- 组件化项目的混淆分为“全局混淆(壳工程)+组件混淆(各子组件模块)”。
- 全局混淆统一配置公共规则。
- 组件混淆配置自身专属规则。
- 避免混淆冲突,确保各组件混淆独立且兼容。
注意事项
- ARouter、Hilt相关类、注解、接口不能被混淆,否则会导致路由失效、依赖注入失败;
- 自定义实体类(如UserInfo)、接口(如IUserService)不能被混淆,否则会导致序列化失败、接口调用异常;
- 混淆配置后,必须测试release模式,确保所有功能正常;
- 混淆配置不影响Version Catalog的依赖管理,只需确保混淆规则覆盖所有核心依赖类。
全局混淆配置
在壳工程(app模块)的proguard-rules.pro中配置全局混淆规则,覆盖公共依赖(ARouter、Hilt)和基础混淆规则,适用于所有组件。
- 1.基础混淆规则
# 保留注解
-keepattributes *Annotation*
# 保留泛型
-keepattributes Signature
# 保留异常信息
-keepattributes Exceptions,InnerClasses
# 保留R文件相关
-keep class **.R$* {*;}
# 保留Activity、Fragment等组件
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.Fragment
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.view.View
# 保留Parcelable序列化相关类
-keep class * implements android.os.Parcelable {*;}
-keep class * implements android.os.Serializable {*;}
- 2.三方库混淆规则,直接官网拷贝即可,以ARouter为例
// ARouter专属混淆规则(必须保留,否则路由失效)
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 保留Autowired注解相关方法
-keepclassmembers class * {
@com.alibaba.android.arouter.facade.annotation.Autowired *;
}
# 保留Route注解相关类和方法
-keepclassmembers class * {
@com.alibaba.android.arouter.facade.annotation.Route public *;
}
# 保留Interceptor注解相关类
-keepclassmembers class * {
@com.alibaba.android.arouter.facade.annotation.Interceptor public *;
}
- 3.Hilt专属混淆规则(必须保留,否则依赖注入失败)
-keep class dagger.hilt.** { *; }
-keep class javax.inject.** { *; }
-keep class com.google.dagger.** { *; }
# 保留Hilt注解相关类和方法
-keepclassmembers class * {
@dagger.hilt.InstallIn *;
@javax.inject.Inject *;
@dagger.Module *;
@dagger.hilt.AndroidEntryPoint *;
@dagger.hilt.HiltAndroidApp *;
}
# 保留Hilt自动生成的类
-keep class * extends dagger.hilt.GeneratedComponent { *; }
-keep class * extends dagger.hilt.internal.GeneratedComponentManager { *; }
- 4.全局排除混淆的类(自定义公共类)
# 保留base组件中的公共接口、实体类
-keep class com.xxx.base.** {*;}
# 保留FlowBusManager、CoroutineHelp等公共工具类
-keep class com.xxx.base.tools.** {*;}
- 5.配置壳工程build.gradle.kts,开启混淆(沿用Version Catalog配置,不修改依赖引用)
...
android {
...
// 定义构建类型,debug或release
buildTypes {
...
release {
// 开启混淆,代码压缩
isMinifyEnabled = true
// 移除无用资源(可选,减少包体积)
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" // 混淆文件
)
...
}
debug {
// debug不启动混淆,便于调试
isMinifyEnabled = false
...
}
}
}
...
组件混淆配置
在base和user组件中配置专属混淆规则,仅混淆组件内部无关代码,保留核心类和接口,确保组件功能正常。
- 1.base组件混淆配置(base模块的proguard-rules.pro)
# 保留base组件的公共接口、实体类、工具类(已在全局混淆中保留,可重复配置,避免遗漏)
-keep class com.xxx.base.** {*;}
-keep class com.xxx.base.tools.** {*;}
-keep class com.xxx.base.service.** {*;} // 保留IUserService等公共接口
# 混淆base组件内部无关代码(可选,根据实际需求配置)
-keep class com.xxx.base.internal.** {*;} // 若有内部类,可保留或混淆
- 2.user组件混淆配置(user模块的proguard-rules.pro)
# 保留user组件的核心类(Activity、接口实现类)
-keep class com.xxx.user.** {*;}
# 保留UserServiceImpl等接口实现类
-keep class com.xxx.user.service.impl.** {*;}
# 保留user组件的实体类(若有新增)
-keep class com.xxx.user.model.** {*;}
# 混淆user组件内部无关代码(如工具类、内部类)
# -keep class com.xxx.user.internal.** {*;}
- 3.配置组件build.gradle.kts,关联混淆规则
...
android {
...
buildTypes {
release {
// 组件开启混淆
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
// debug不启动混淆,便于调试
isMinifyEnabled = false
}
}
}
...
踩坑点
梳理Version Catalog依赖管理和组件化混淆的7个高频踩坑点
坑点1:Version Catalog配置后,同步工程报错“Could not find libs.xxx”
- 原因:libs.versions.toml中配置有误(如版本号、group/module错误)。
- 修复:确认libs.versions.toml中libraries、versions配置正确,同步工程后清理缓存。
坑点2:依赖版本不统一,导致编译报错
- 原因:部分组件未通过Version Catalog引用依赖,而是硬编码版本。
- 修复:所有组件均通过libs.xxx引用依赖,不硬编码版本,确保Version Catalog中版本统一。
坑点3:Hilt插件与Android Gradle插件版本不兼容
- 原因:未关注版本兼容性,盲目升级插件版本,且未在Version Catalog中同步调整。
- 修复:查看Hilt官方文档,匹配对应的Android Gradle插件版本,在libs.versions.toml中调整gradlePlugin和hilt版本,重新同步工程。
坑点4:依赖隔离不当,导致组件间耦合过高
- 原因:滥用api依赖,将组件内部依赖暴露给其他组件。
- 修复:优先使用implementation,仅base组件的公共依赖用api暴露,避免依赖传递。
坑点5:混淆ARouter相关类,导致路由失效
- 原因:未配置ARouter专属混淆规则,或混淆规则不完整。
- 修复:添加ARouter专属混淆规则,保留路由相关的类、注解和方法,打包release后测试路由功能。
坑点6:混淆Hilt相关类,导致依赖注入失败
- 原因:未配置Hilt专属混淆规则,或遗漏Hilt自动生成的类。
- 修复:添加Hilt专属混淆规则,保留Hilt注解、生成的Component类,确保依赖注入正常。
坑点7:release模式下实体类序列化失败
- 原因:实体类未保留,被混淆导致Parcelable/Serializable接口失效。
- 修复:在混淆规则中保留实体类(如UserInfo),确保序列化相关方法不被混淆。