一、概念
组件化是基于可重用目的,对单个功能进行开发,提升复用性降低耦合度。多个功能组件起来就是一个业务组件,多个业务组件组合起来就是一个应用,因此去除了模块间的耦合,使得按业务划分的模块成了可单独运行的业务组件。(组件化只是一定程度上的独立,还是依附于整个项目中,想完全独立详见插件化)
- 功能复用:每个组件都是一个单独的功能,可被不同的模块甚至不同的应用所使用。
- 提高效率:每个组件都是一个可单独编译运行的APP,由于拆分使得代码量少,调试起来快。
- 协同开发:组件之间相互独立,使得不同的开发人员能专注于各自的功能开发互不影响。
1.1 组件划分
依赖关系是上层依赖下层,修改频率是上层高于下层。
|------------------|------------------------------------------------------------------------------------------------------------|
| app壳 | 应用的入口:只依赖各业务组件,不包含具体业务代码。将业务组件打包成一个APP,做一些配置工作(打包环境、签名、混淆等)。 |
| 业务组件 module_XXX | 某个页面:根据业务拆分的独立模块,如主页模块、登录模块、商城模块。业务组件之间无直接关系,通过路由进行通信。既可以作为 Application 单独编译运行调试,又可作为 Library 集成到项目中。 |
| 功能组件 feature_XXX | 公共功能:是对公用的功能进行封装与实现,如网络请求、日志打印、地图、支付、广告。非必须层,业务组件可以直接依赖基础组件去实现功能。 |
| 基础组件 lib_XXX | 最底层:修改频率极低,统一依赖配置和资源文件:如引入第三方框架(Retrofit、Glide)、存放公用资源文件(strings、drawable、自定义View、工具类Utils)、实现路由(ARouter)。 |
1.2 组件模式
在 Module 的 build.gradle 中指定插件类型,指定为集成模式(Library)可以被其它组件调用,指定为独立模式(Application)可以单独运行调试。
|-------------------------|---------------------------------|
| com.android.application | 项目构建后输出 apk 包,在调试时是一个应用能单独编译运行。 |
| com.android.library | 项目构建后输出 aar 包,在打包时是一个库文件集成到项目中。 |
Kotlin
plugins {
alias(libs.plugins.android.library)
}
1.3 创建组件
File(或在Project上右键)→New→New Module。独立模式(业务组件)选择【Phone & Tablet】,集成模式(功能组件、基础组件)需要用到资源文件选【Android Library】纯代码选【Java or kotlin Library】。
使用目录来聚合同类型组件,使层次结构更清晰。语法是模块取名的时候使用":library:lib_base",这样 lib_base 就在根目录的 library 下了。
二、统一配置
2.1 动态模式切换
在 TOML 的节点 [versions] 中定义属性 isDebug = "false" ,用于后续在业务组件中读取来动态切换组件模式。
Kotlin
[versions]
isDebug ="false"
2.2 抽取 build.gradle 中相同的配置
组件中有很多相同的配置,分别抽成【commonMoudle.gradle】【commonLib.gradle】 文件并在对应组件中引入,就可以删除重复的配置了。
- commonMoudle:提供组件模式的切换,剔除各个 module 组件专有的 namespace、applicationId 属性。
- commonLib:剔除各个 lib 组件专有的 namespace 属性。
Kotlin
1
三、基础组件
所有组件都依赖 lib_base,提供全局的功能。
3.1 创建 lib_base 组件

3.2 提供 BaseApplication
其它组件都依赖于 lib_base,因此在其中提供一个全局的 BaseApplication 供其它组件在代码中使用。所有资源的初始化也在这里。
|-------------------|------------------------------------------------------------------------------------------------------------|
| 其它组件所处的模式 | 引入后如何使用 |
| 集成模式(Library) | 直接使用 BaseApplication,不是应用不需要注册。 |
| 独立模式(Application) | 在 debug 文件夹中创建一个子类继承自 BaseApplication 然后注册到 debug 文件夹中的 AndroidManifest 中(不需要使用自己定义的就注册为 BaseApplication)。 |
| app壳 | 创建一个子类继承自 BaseApplication 然后在 AndroidManifest 中注册(不需要使用自己定义的就注册为 BaseApplication) 。 |
Kotlin
open class App : Application() {
companion object {
@SuppressLint("StaticFieldLeak") //注解忽略警告
lateinit var context: Context
private set
}
override fun onCreate() {
super.onCreate()
context = applicationContext //在APP创建的时候就赋值
}
}
3.3 提供权限声明 AndroidManifest
声明了项目中用到的所有权限,这样其它组件就无需在自己的 AndroidManifest.xm 声明自己要用到的权限了。
XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
3.4 提供依赖 build.gradle
使用 imlemntation 添加的依赖只对当前组件有效,使用 api 添加的依赖对其上层组件同样有效,这样依赖于基础组件的组件就不用再添加相同的依赖了。
项目中某个组件会被其它组件重复依赖,在集成构建应用时 Gradle 会自动剔除重复的 arr 包,这样就不会存在好几份重复的代码了。而第三方库和我们的项目可能都依赖了相同的库(例如 Glide 中也依赖了 OkHttp)就会导致重复加载,解决办法是找出相同的库根据组件名或包名排除。
|---------------------------|-----------------------------|
| 仅用于当前组件 | 可向上传递(引入这个组件的上层组件不用重复添加依赖项) |
| implementation | api |
| testImplementation | testApi |
| androidTestImplementation | androidTestApi |
| debugImplementation | debugApi |
Kotlin
[versions]
agp = "8.13.1"
kotlin = "2.3.0"
coreKtx = "1.16.0"
junit = "4.13.2"
junitVersion = "1.1.5"
espressoCore = "3.5.1"
lifecycleRuntimeKtx = "2.10.0"
composeActivity = "1.12.0"
composeBom = "2025.12.00"
[libraries]
#Compose
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
compose-material3 = { module = "androidx.compose.material3:material3" }
#预览
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
#测试
compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4" }
compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" }
#可选
compose-activity = { module = "androidx.activity:activity-compose", version.ref = "composeActivity" }
#其它
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-junit = { module = "androidx.test.ext:junit", version.ref = "junitVersion" }
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" }
junit = { module = "junit:junit", version.ref = "junit" }
[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-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
java
dependencies {
//Compose
//物料清单
api(platform(libs.compose.bom))
androidTestApi(platform(libs.compose.bom))
//主题
api(libs.compose.material3)
//预览
api(libs.compose.ui.tooling.preview)
debugImplementation(libs.compose.ui.tooling)
//UI测试
androidTestImplementation(libs.compose.ui.test.junit4)
debugImplementation(libs.compose.ui.test.manifest)
//可选
api(libs.compose.activity)
//默认
api(libs.androidx.core.ktx)
api(libs.androidx.lifecycle.runtime.ktx)
testApi(libs.junit)
androidTestApi(libs.androidx.junit)
androidTestApi(libs.androidx.espresso.core)
}
3.4.1 处理 jar 包 aar 包依赖
一般依赖的都是 Maven 仓库,如果提供的是 aar、jar 文件,第一行添加如下代码引入。
Kotlin
dependencies {
api(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
}
3.5 提供公共资源
自定义的类(Utils、Base、Constants、Ext、Widgets)、res资源目录(drawable、strings)、通用业务(Retrofit)、通用配置等都应该放在这里。
四、功能组件
3.1 创建 feature_common 组件

3.2 引入基础组件 lib_base
Kotlin
dependencies {
api(project(":library:lib_base"))
}
五、业务组件
5.1 创建 module_main 组件
现在都是单 Activity 的应用开发,创建的时候选 NoActivity。

5.2 创建 debug 包
在业务组件根目录中创建 debug 包,用于存放只在独立模式下使用的文件,在集成模式下会被剔除不参与打包。
在业务组件的 src/main/java 目录上右键→New→Package。(不推荐在组件的其它层级上创建目录存放,切换到Android视图不会显示)

5.2.1 自定义 Application
有的业务组件需要被传入数据,或是用到的资源需要初始化,自定义一个 TestApplication 继承 lib_base 中提供的 BaseApplication。如果用不到,就直接把 BaseApplication 注册。
Kotlin
class MyApp : App() {}
5.2.2 自定义入口 LauncherActivity
现在都是单 Activity 的应用开发,业务模块在独立模式下需要有 Activity 承载显示,因此 debug 包下创建一个 LauncherActivity。
Kotlin
class LauncherActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MsgScreen()
}
}
}
5.2.3 两份 AndroidManifest
处于独立模式时,需要为了<application>标签配置、自定义Application 、启动入口 Activity 而在 AndroidManifest 中进行注册,但在集成模式下打包到一起时存在重复和冲突(如桌面上好几个启动图标、只能注册一个自定义的Application、同一个权限无须多次申请)。
- 将自动创建的 AndroidManifest 复制一份到 debug 包下,对 <manifest> 标签添加 package 属性指定为组件的包名,将 .MainActivity 改成自定义的启动Activity。然后像单工程那样用就行。
- 再修改自动创建的 AndroidManifest,也对 <manifest> 标签添加 package 属性指定为组件的包名。若该业务组件不是程序入口,将 <application> 的属性和子标签都删除,只存放四大组件的注册。
5.3 修改 build.gradle
根据在 TOML 中定义的 isDebug 来动态切换插件模式、设置applicationId、加载AndroidManifest。引入需要功能组件。
5.3.1 动态切换组件模式
Kotlin
plugins {
if (libs.versions.isDebug.get().toBoolean()) {
alias(libs.plugins.android.application)
} else {
alias(libs.plugins.android.library)
}
}
5.3.2 动态设置 applicationId
这里会提示找不到 applicationId、versionCode、versionName,注释掉能正常执行。20260112
Kotlin
android {
defaultConfig {
if (libs.versions.isDebug.get().toBoolean()) {
applicationId = "com.example.module_main"
}
}
}
5.3.3 动态加载 AndroidManifest
这里剔除 debug 包下文件有问题,用了AI也找不到相应语法,报错方法不正确。20260112
Kotlin
sourceSets {
named("main") {
if (isDebug) {
manifest.srcFile("src/main/java/debug/AndroidManifest.xml")
} else {
manifest.srcFile("src/main/AndroidManifest.xml")
}
}
}
5.3.4 引入需要的功能模块
Kotlin
dependencies {
implementation(project(":library:lib_base"))
}
六、搬空 app 壳
6.1 搬运程序入口 MainActivity
- 将 app 中的 MainActivity.class 和 activity_main.xml(Compose没有这个) 剪切至 module_main 中。
- 将 AndroidManifest 中的 MainActivity 注册(包含程序入口)也剪切至 module_core 中只保留 <application> 标签。
6.2 搬运资源目录 res
将 app 中的整个 res 目录剪切至 lib_base 中。
6.3 自定义 Application
需要用到就自定义一个 MyApp 继承 lib_base 中提供的 BaseApplication,用不到就直接把 BaseApplication 注册。
6.4 修改 AndroidManifest
<application>标签的属性都是在app壳配置的,而其它组件也会有自己的清单,在集成模式下最终会打包合并成一个文件,需要解决属性重复(在上面5.4中用于集成模式的AndroidManifest的<application>标签并不会进行配置,但还是会配置theme),分别对 app 的 <manifest> 和 <application> 添加如下代码。
|-----------------|-------------------------------------------------------------------------------------------|
| <manifest> | xmlns:tools="http://schemas.android.com/tools" |
| <application> | tools:replace="android:name,android:label,android:icon,android:theme,android:allowBackup" |
XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<application
android:name="com.example.lib_base.App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.WAModularization"
tools:replace="android:name,android:label,android:icon,android:theme,android:allowBackup"
>
</application>
</manifest>
6.5 修改 build.gradle
应用的打包签名、buildTypes、defaultConfig 都需要在这里配置,而它的 dependencies 则需要根据 isDebug 的值分别依赖不同的组件,在独立模式下app壳只需要依赖 lib_common 组件,在集成模式下必须依赖所有声明的业务组件。
当需要同时引入好几个组件时,可以像"分组"一样一次性引入,避免每次新建组件引入多个其他组件的时候出错。像多渠道打包、测试某几个固定组件协同时使用。
Kotlin
dependencies {
implementation(project(":library:lib_base"))
if (!libs.versions.isDebug.get().toBoolean()) {
implementation(project(":module:module_main"))
}
}