Android开发[6]:组件化之版本管理+混淆

2 阅读11分钟

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(插件),统一管理所有依赖
[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$* {*;}
# 保留ActivityFragment等组件
-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),确保序列化相关方法不被混淆。