Android多SDK合并为单个JAR包的完整指南

作者:安卓蓝牙Vincent日期:2025/11/19

痛点

  • 多 SDK 分散:每个功能模块单独提供 JAR,用户需要逐一集成和管理
  • 调用复杂:不同模块间存在依赖和包名冲突,用户在项目中使用不方便
  • 升级维护困难:每次更新都要同步多个 JAR,容易出错

一、核心原理

1.1 最推荐的方案:源码合并 + 下层库作为“源码目录”加入

多 SDK 合并时,最终有效的构建环境只有顶层 SDK,因此最稳定的方式是:

1源码合并(sourceSets)  
2+ 移除模块依赖  
3+ 将下层 SDK 作为源码目录引入(而不是 module)
4

Android Studio 会把下层 SDK 当成普通源码,自然不会爆红,也不会再触发 module 依赖的复杂机制。


1.2 为什么不能继续使用 module 依赖?

1dependencies {
2    api project(':sdk-core-lib')  // ❌ 不推荐
3}
4

问题:

  • AAR/JAR 输出不一定包含所有依赖模块代码
  • 需要额外处理传递依赖
  • fat-aar 插件在 Gradle 8+ 兼容性差
  • 模块之间 BuildConfig、Manifest、资源合并容易冲突
  • 最重要:module 依赖让下层 SDK 的 build.gradle 继续生效(会导致混淆等配置难以统一管理)

1.3 最关键的优化:用 sourceSets 把下层 SDK 当成“源码目录”

比直接复制代码更干净 —— 下层 SDK 不再是 module,只是一个源码目录。

1android {
2    sourceSets {
3        main {
4            java.srcDirs += ['../SDK_Core/src/main/java']
5            java.srcDirs += ['../SDK_Base/src/main/java']
6            res.srcDirs  += ['../SDK_Core/src/main/res']
7            res.srcDirs  += ['../SDK_Base/src/main/res']
8        }
9    }
10}
11

同时从 settings.gradle 中删除:

1include ':SDK_Core'
2include ':SDK_Base'
3

优点:

  • Android Studio 能识别源码,不再爆红(你遇到的问题的核心原因)
  • 不再有 Gradle module 带来的依赖逻辑
  • 完全由顶层 SDK 的 build.gradle 决定最终产物
  • 源码共享更干净,不需要复制

缺点:

  • 不再能享受 Gradle dependency graph(因为不是 module)
  • 无法单独编译下层 SDK(但通用 SDK 开发通常不需要)

二、适用架构与合并策略

以典型结构为例:

1SDK_Standard(对客户的最终输出)
2 ├── SDK_Core
3 │     └── SDK_Base
4

所有差异化功能由顶层 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_Basebase_
SDK_Corecore_
SDK_Standardstandard_

规则 4:避免包名冲突

下层 SDK 必须独立包目录,例如:

1com.company.base.**
2com.company.core.**
3com.company.sdk.standard.**
4

四、完整实现步骤


4.1 顶层 build.gradle(唯一有效)

1android {
2    namespace 'com.company.sdk.standard'
3    compileSdk 34
4
5    defaultConfig {
6        minSdk 21
7        targetSdk 34
8    }
9
10    sourceSets {
11        main {
12            // 源码合并
13            java.srcDir '../SDK_Core/src/main/java'
14            java.srcDir '../SDK_Base/src/main/java'
15
16            // 资源合并(如需要)
17            res.srcDir '../SDK_Core/src/main/res'
18            res.srcDir '../SDK_Base/src/main/res'
19        }
20    }
21
22    buildTypes {
23        release {
24            minifyEnabled true
25            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
26                         'proguard-rules.pro'
27        }
28    }
29}
30

4.2 迁移所有依赖到顶层

1dependencies {
2    // 来自 Core
3    implementation 'androidx.core:core-ktx:1.12.0'
4
5    // 来自 Base
6    implementation 'com.google.code.gson:gson:2.10.1'
7}
8

4.3 BuildConfig 失效问题(非常常见)

下层 SDK 不再是 module,所以不会生成 BuildConfig。

解决方式 A(推荐)
修改引用路径:

1// from
2import com.company.sdk.core.BuildConfig;
3
4// to
5import com.company.sdk.standard.BuildConfig;
6

解决方式 B(无需改源码)
手动创建对应 BuildConfig:

1SDK_Standard/src/main/java/com/company/sdk/core/BuildConfig.java
2

4.4 混淆规则合并(放在顶层)

1# Base
2-keep class com.company.base.** { *; }
3
4# Core
5-keep class com.company.core.** { *; }
6
7# 顶层对外接口
8-keep public class com.company.sdk.MTTagBleManager { *; }
9

4.5 最终目录结构(重要)

1SDK_Standard/
2 ├── build.gradle(唯一有效)
3 ├── proguard-rules.pro
4 └── src/main/java/
5       ├── com/company/sdk/standard/...
6       ├── com/company/core/...     ← via sourceSets
7       └── com/company/base/...     ← via sourceSets
8

五、为什么之前代码会爆红?

因为:

  • 你删掉 settings.gradle 里的 include
  • 但没有把 SDK_Core / SDK_Base 作为 sourceSets 手动加入
  • Android Studio 不知道这些目录是源码目录
  • 所以爆红(找不到类)

只要加上这个:

核心痛点

  • 多 SDK 分散:每个功能模块单独提供 JAR,用户需要逐一集成和管理
  • 调用复杂:不同模块间存在依赖和包名冲突,用户在项目中使用不方便
  • 升级维护困难:每次更新都要同步多个 JAR,容易出错
1android {
2    sourceSets {
3        main {
4            java.srcDirs += ['../SDK_Core/src/main/java']
5        }
6    }
7}
8

即时恢复正常。

这是你目前问题的根源,并且已经彻底解决。


六、总结

能力为什么必须使用源码目录方式
不爆红Android Studio 能识别源码
打包稳定所有代码由顶层统一构建
混淆统一避免多 module 冲突
完全控制不再受 module 的 build.gradle 干扰
干净不需要复制源码

最终输出:

  • 单 AAR / 单 JAR
  • 完整包含 Base + Core + Standard 的全部代码
  • 无依赖问题
  • 完整兼容 Gradle 8+

Android多SDK合并为单个JAR包的完整指南》 是转载文章,点击查看原文


相关推荐


Python 的内置函数 super
IMPYLH2025/11/17

Python 内建函数列表 > Python 的内置函数 super Python 的内置函数 super() 是一个非常重要的内置函数,主要用于在子类中调用父类(超类)的方法。这个函数在面向对象编程中扮演着关键角色,特别是在处理继承关系时。 基本用法 super() 最常见的用法是在子类的初始化方法中调用父类的初始化方法: class Parent: def __init__(self, name): self.name = name class Child(


Python 的内置函数 pow
IMPYLH2025/11/16

Python 内建函数列表 > Python 的内置函数 pow Python 的内置函数 pow() 是一个用于计算幂运算的强大工具。它有两种基本用法,可以计算数值的幂次方,也支持进行模运算。 基本语法 pow(base, exp) 参数说明 base:底数,可以是整数或浮点数exp:指数,可以是整数或浮点数 使用示例 基本幂运算: pow(2, 3) # 返回8 (2的3次方) pow(2.5, 2) # 返回6.25 (2.5的平方) 带模运算: pow(2,


🔥 “Solo Coding”的近期热度解析(截至 2025 年末)
LeonGao2025/11/15

🧠 一、概念回顾 Solo Coding 并不是新词,但在过去一年随着 AIGC 编程辅助工具(如 Copilot、Cursor、TabNine、ChatGPT Code Interpreter) 的普及,它被重新定义为: 一个人独立开发完整系统,但具备团队级效率。 这与传统意义的“独立开发者(Indie Developer)”不同,核心在于借助 AI 的合作力量,实现准团队式的个人生产力爆发。 📈 二、热度增长趋势 时间区间关键词趋势


Python 的内置函数 iter
IMPYLH2025/11/14

Python 内建函数列表 > Python 的内置函数 iter Python 的内置函数 iter() 用于创建一个迭代器对象,它可以将可迭代对象(如列表、元组、字典、集合等)转换为迭代器,从而支持逐个访问元素的操作。 基本语法 iter(iterable, sentinel) iterable:必需参数,表示要转换为迭代器的可迭代对象(如列表、字符串等)。sentinel:可选参数,用于指定迭代停止的条件值(主要用于自定义迭代行为)。 示例说明 基本用法(无 sentinel


python+uniapp基于微信小程序的垃圾分类信息系统
Q_Q5110082852025/11/13

目录 项目介绍本项目具体实现截图开发技术大数据类设计开发的基本流程是:论文大纲结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 项目介绍 本文介绍了一款基于微信小程序的垃圾分类信息系统。该系统旨在帮助用户更便捷地了解垃圾分类知识,提高垃圾分类的准确性和效率。通过微信小程序平台,用户可以随时随地查询各类垃圾的归属类别,并获取详细的分类指导。 本研究首先进行了用户需求分析,明确了平台应具备的功能和特点。然后,利用微信小程序开发技术,设计并实现了该平台。课题主要分为


HTML 的 <svg> 标签
hubenchang05152025/11/11

#HTML 的 <svg> 标签 请查看 HTML 元素帮助手册 了解更多 HTML 元素。 如果 svg 不是根元素,svg 元素可以用于在当前文档(比如说,一个 HTML 文档)内嵌套一个独立的 svg 片段。这个独立片段拥有独立的视口和坐标系统。 #属性 请查看 HTML 元素的全局属性 了解 HTML 元素的全局属性。 #示例 <svg width="300" height="300" viewBox="0 0 300 300" xmlns="http://www.w3.org/


LRU 缓存的设计与实现
前似锦2025/11/9

目录 一、LRU 缓存的核心诉求 二、数据结构选型与设计思路 1. 双向链表:维护访问顺序的 “时间轴” 2. 哈希表:实现 key 的 O (1) 寻址 3. 组合设计:“哈希表 + 双向链表” 的协同工作 三、代码实现 1. 类结构定义 2. get 方法实现:查询并更新访问顺序 3. put 方法实现:插入、更新与容量控制 四、复杂度与边界场景分析 1. 时间复杂度 2. 边界场景处理 五、测试验证与工程价值 六、总结 在高并发与大数据场景中,缓存是提


Less-8 GET-Blind-Boolean Based-Single Quotes
泷羽Sec-静安2025/11/7

GET-盲注-基于布尔值-单引号 Less-8 代码分析 关键特征对比 特征Less-5Less-8SQL结构id='$id'id='$id'成功时“You are in”“You are in”失败时显示错误 mysql_error()什么都不显示注入类型报错注入/布尔盲注纯布尔盲注核心区别(关键!) // Less-5 else { echo 'You have an error in your SQL syntax'; print_r(mysql_error()); /


Python 的内置函数 format
IMPYLH2025/11/2

Python 内建函数列表 > Python 的内置函数 format Python 的内置函数 format() 是一个功能强大的字符串格式化工具,它提供了灵活且可读性强的格式化方式。该函数主要通过两种形式使用: 作为字符串对象的方法: "格式化字符串".format(参数) 这是最常见的用法,在字符串内部使用 {} 作为占位符,然后通过 format() 方法传入参数进行替换。 作为独立的内置函数: format(value, format_spec) 这种形式主要用于对单个值进


2025年组件化开发这样做,效率提升300%
良山有风来2025/10/31

你是不是还在重复写着相似的代码?每次产品经理说要改个按钮样式,你都得在几十个文件里翻来翻去?明明是个小改动,却要花大半天时间? 别担心,这篇文章就是来拯救你的。我会带你彻底搞懂现代前端框架的组件化开发,从基础概念到实战技巧,再到2025年的最新趋势。读完本文,你将拥有一套完整的组件化思维,开发效率至少提升3倍! 什么是组件化开发? 简单来说,组件化就是把页面拆分成一个个独立的小模块。就像搭乐高积木一样,每个组件都是独立的积木块,你可以随意组合、重复使用。 想想你每天写的代码,是不是经常遇到这样的

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0