痛点
- 多 SDK 分散:每个功能模块单独提供 JAR,用户需要逐一集成和管理
- 调用复杂:不同模块间存在依赖和包名冲突,用户在项目中使用不方便
- 升级维护困难:每次更新都要同步多个 JAR,容易出错
一、核心原理
1.1 最推荐的方案:源码合并 + 下层库作为"源码目录"加入
多 SDK 合并时,最终有效的构建环境只有顶层 SDK,因此最稳定的方式是:
diff
源码合并(sourceSets)
+ 移除模块依赖
+ 将下层 SDK 作为源码目录引入(而不是 module)
Android Studio 会把下层 SDK 当成普通源码,自然不会爆红,也不会再触发 module 依赖的复杂机制。
1.2 为什么不能继续使用 module 依赖?
java
dependencies {
api project(':sdk-core-lib') // ❌ 不推荐
}
问题:
- AAR/JAR 输出不一定包含所有依赖模块代码
- 需要额外处理传递依赖
- fat-aar 插件在 Gradle 8+ 兼容性差
- 模块之间 BuildConfig、Manifest、资源合并容易冲突
- 最重要:module 依赖让下层 SDK 的 build.gradle 继续生效(会导致混淆等配置难以统一管理)
1.3 最关键的优化:用 sourceSets 把下层 SDK 当成"源码目录"
比直接复制代码更干净 ------ 下层 SDK 不再是 module,只是一个源码目录。
css
android {
sourceSets {
main {
java.srcDirs += ['../SDK_Core/src/main/java']
java.srcDirs += ['../SDK_Base/src/main/java']
res.srcDirs += ['../SDK_Core/src/main/res']
res.srcDirs += ['../SDK_Base/src/main/res']
}
}
}
同时从 settings.gradle 中删除:
php
include ':SDK_Core'
include ':SDK_Base'
优点:
- Android Studio 能识别源码,不再爆红(你遇到的问题的核心原因)
- 不再有 Gradle module 带来的依赖逻辑
- 完全由顶层 SDK 的 build.gradle 决定最终产物
- 源码共享更干净,不需要复制
缺点:
- 不再能享受 Gradle dependency graph(因为不是 module)
- 无法单独编译下层 SDK(但通用 SDK 开发通常不需要)
二、适用架构与合并策略
以典型结构为例:
SDK_Standard(对客户的最终输出)
├── SDK_Core
│ └── SDK_Base
所有差异化功能由顶层 SDK(Standard / Custom_A / Custom_B)决定。
三、核心规则(⭐ 极重要)
规则 1:所有下层 SDK 必须作为源码目录存在
❌ 不要是 module
❌ 不要使用依赖
✔ 使用 sourceSets 直接引用源码目录(不会爆红)
规则 2:只有顶层 SDK 的 build.gradle 生效
下层的 build.gradle 完全无效(因为不再是 module)。
失效内容:
- dependencies
- buildConfigField
- proguard-rules.pro
- manifestPlaceholders
全部迁移到顶层。
规则 3:资源文件自动合并,但必须避免冲突
建议命名规范:
| SDK | 前缀 |
|---|---|
| SDK_Base | base_ |
| SDK_Core | core_ |
| SDK_Standard | standard_ |
规则 4:避免包名冲突
下层 SDK 必须独立包目录,例如:
csharp
com.company.base.**
com.company.core.**
com.company.sdk.standard.**
四、完整实现步骤
4.1 顶层 build.gradle(唯一有效)
arduino
android {
namespace 'com.company.sdk.standard'
compileSdk 34
defaultConfig {
minSdk 21
targetSdk 34
}
sourceSets {
main {
// 源码合并
java.srcDir '../SDK_Core/src/main/java'
java.srcDir '../SDK_Base/src/main/java'
// 资源合并(如需要)
res.srcDir '../SDK_Core/src/main/res'
res.srcDir '../SDK_Base/src/main/res'
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
4.2 迁移所有依赖到顶层
arduino
dependencies {
// 来自 Core
implementation 'androidx.core:core-ktx:1.12.0'
// 来自 Base
implementation 'com.google.code.gson:gson:2.10.1'
}
4.3 BuildConfig 失效问题(非常常见)
下层 SDK 不再是 module,所以不会生成 BuildConfig。
解决方式 A(推荐)
修改引用路径:
arduino
// from
import com.company.sdk.core.BuildConfig;
// to
import com.company.sdk.standard.BuildConfig;
解决方式 B(无需改源码)
手动创建对应 BuildConfig:
css
SDK_Standard/src/main/java/com/company/sdk/core/BuildConfig.java
4.4 混淆规则合并(放在顶层)
csharp
# Base
-keep class com.company.base.** { *; }
# Core
-keep class com.company.core.** { *; }
# 顶层对外接口
-keep public class com.company.sdk.MTTagBleManager { *; }
4.5 最终目录结构(重要)
bash
SDK_Standard/
├── build.gradle(唯一有效)
├── proguard-rules.pro
└── src/main/java/
├── com/company/sdk/standard/...
├── com/company/core/... ← via sourceSets
└── com/company/base/... ← via sourceSets
五、为什么之前代码会爆红?
因为:
- 你删掉 settings.gradle 里的 include
- 但没有把 SDK_Core / SDK_Base 作为 sourceSets 手动加入
- Android Studio 不知道这些目录是源码目录
- 所以爆红(找不到类)
只要加上这个:
核心痛点
- 多 SDK 分散:每个功能模块单独提供 JAR,用户需要逐一集成和管理
- 调用复杂:不同模块间存在依赖和包名冲突,用户在项目中使用不方便
- 升级维护困难:每次更新都要同步多个 JAR,容易出错
css
android {
sourceSets {
main {
java.srcDirs += ['../SDK_Core/src/main/java']
}
}
}
即时恢复正常。
这是你目前问题的根源,并且已经彻底解决。
六、总结
| 能力 | 为什么必须使用源码目录方式 |
|---|---|
| 不爆红 | Android Studio 能识别源码 |
| 打包稳定 | 所有代码由顶层统一构建 |
| 混淆统一 | 避免多 module 冲突 |
| 完全控制 | 不再受 module 的 build.gradle 干扰 |
| 干净 | 不需要复制源码 |
最终输出:
- 单 AAR / 单 JAR
- 完整包含 Base + Core + Standard 的全部代码
- 无依赖问题
- 完整兼容 Gradle 8+