以 LiveApp 直播项目为示例,直接从代码出发介绍 Android 组件化的落地实现。
核心思路一句话:业务模块互不依赖、可独立运行,壳工程负责集成打包。下面全部围绕直播业务场景下的关键代码展开。
一、项目结构
bash
LiveApp/
├── lib_common # 公共库:网络、图片加载、路由、Base 类、直播基础 SDK 封装
├── module_app # 空壳工程:集成所有业务组件,配置签名/混淆/多 Dex,输出 APK
├── module_live # 业务组件:直播间、推流、拉流、房间列表
├── module_gift # 业务组件:礼物面板、礼物特效、礼物商城
├── module_im # 业务组件:弹幕、公屏聊天、私信
├── module_user # 业务组件:登录、个人主页、关注/粉丝
├── build.gradle # 根构建脚本
├── settings.gradle # 子模块声明
├── versions.gradle # 统一依赖版本
└── gradle.properties # isModule 模式开关
依赖方向:module_app → 业务组件 → lib_common,业务组件之间零依赖。
二、模式切换:isModule 开关
组件化的第一个关键点:业务模块在集成模式下是 library,开发调试时切换为 application 独立运行,整个切换由一个 Gradle 开关控制。
2.1 定义开关
ini
# gradle.properties
# false = 集成模式,业务模块作为 library 被壳工程引用
# true = 组件模式,业务模块作为 application 独立运行
isModule=false
2.2 业务模块按开关切换插件
arduino
// module_live/build.gradle
if (isModule.toBoolean()) {
apply plugin: 'com.android.application' // 组件模式:独立 App
} else {
apply plugin: 'com.android.library' // 集成模式:普通依赖库
}
2.3 组件模式下配置独立 applicationId
arduino
// module_live/build.gradle
defaultConfig {
if (isModule.toBoolean()) {
applicationId "com.live.module_live" // 按各模块实际包名配置
}
}
2.4 壳工程只在集成模式下引入业务组件
scss
// module_app/build.gradle
dependencies {
implementation project(':lib_common')
if (!isModule.toBoolean()) {
implementation project(':module_live')
implementation project(':module_gift')
implementation project(':module_im')
implementation project(':module_user')
}
}
三、双份 AndroidManifest 适配
application 插件要求模块声明 LAUNCHER 入口,library 则不允许。解决方案:每个业务模块准备两份清单文件,用 sourceSets 按模式切换。
3.1 组件模式清单:src/main/module/AndroidManifest.xml
自带图标和应用名,声明 LAUNCHER 入口:
ini
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name=".LiveRoomActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
3.2 集成模式清单:src/main/AndroidManifest.xml
只注册页面,不带入口,图标/主题交给壳工程:
xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<!-- 只注册页面,不含 LAUNCHER 入口 -->
<activity android:name=".LiveRoomActivity" />
<activity android:name=".RoomListActivity" />
</application>
</manifest>
3.3 sourceSets 按模式加载,同时排除调试代码
arduino
// module_live/build.gradle
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
exclude 'debug/**' // 集成模式下不编译模块内调试代码
}
}
}
}
四、统一依赖管理:versions.gradle + lib_common
4.1 所有版本集中声明
ini
// versions.gradle
ext.deps = [:]
def versions = [:]
versions.android_gradle_plugin = '3.5.2'
versions.kotlin = "1.1.51"
versions.support = "27.0.2"
versions.arouter_api = "1.3.1"
versions.arouter_compiler = "1.1.4"
versions.live_sdk = "x.y.z" // 直播推拉流 SDK
versions.im_sdk = "x.y.z" // IM / 弹幕 SDK
versions.room = "x.y.z" // Room 数据库
// ...
4.2 lib_common 用 api 下发基础能力
less
// lib_common/build.gradle
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
api deps.support.app_compat
api deps.retrofit.runtime // 网络:Retrofit + RxJava
api deps.glide // 图片:Glide
api deps.arouter_api // 路由:ARouter
api deps.live_sdk // 直播:推流/拉流 SDK
api deps.im_sdk // IM:弹幕/聊天 SDK
// ...
}
api 会向下游传递依赖,业务模块只需依赖 lib_common 一行,即可直接使用网络、图片、路由、直播、IM 等基础能力。
五、跨模块通信:ARouter
业务组件之间不能引用对方的类,页面跳转统一走 ARouter 路由。
5.1 壳工程 Application 初始化
scala
public class LiveApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
ARouter.openDebug();
ARouter.openLog();
}
ARouter.init(this);
}
}
5.2 目标页面用 @Route 声明路径
scala
// module_live
@Route(path = "/live/roomList")
public class RoomListActivity extends AppCompatActivity { }
@Route(path = "/live/room")
public class LiveRoomActivity extends AppCompatActivity { }
// module_gift
@Route(path = "/gift/panel")
public class GiftPanelActivity extends AppCompatActivity { }
@Route(path = "/gift/store")
public class GiftStoreActivity extends AppCompatActivity { }
// module_im
@Route(path = "/im/chat")
public class ChatActivity extends AppCompatActivity { }
// module_user
@Route(path = "/user/profile")
public class UserProfileActivity extends AppCompatActivity { }
5.3 调用方只认 path,不依赖目标模块
scss
// module_live/LiveRoomActivity.java ------ 与 gift / im / user 模块零耦合
ARouter.getInstance().build("/gift/panel").navigation();
ARouter.getInstance().build("/im/chat")
.withString("roomId", roomId)
.navigation();
ARouter.getInstance().build("/user/profile")
.withLong("userId", anchorId)
.navigation();
5.4 各业务模块配置注解处理器
ini
// 各业务模块 build.gradle
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
dependencies {
annotationProcessor deps.arouter_compiler
}
六、日常开发流程
- 独立调试 :
gradle.properties设isModule=true→ Sync → 直接运行module_live/module_gift/module_im/module_user等单个组件; - 集成联调 :改回
isModule=false→ Sync → 运行壳工程module_app,验证完整直播流程。
七、注意事项
- 路由 path 全局唯一 :按模块加前缀约定(
/live/、/gift/、/im/、/user/); - 资源命名 :加模块前缀或配置
resourcePrefix,避免合并时资源冲突(如直播相关 layout 命名live_xxx,礼物gift_xxx); - 版本一致 :SDK 与三方库版本统一走
versions.gradle; - 权限声明:直播推拉流、录音、摄像头权限在壳工程统一声明,也可按模块分清单文件由壳工程合并;
- 生命周期 :直播后台保活、音视频生命周期跨模块时注意统一在壳工程
Application初始化并暴露接口给业务模块调用; - 混淆规则:各模块各自维护,壳工程统一引用。
参考
- 项目源码:
LiveApp - 阿里 ARouter 路由框架