这个问题得分两层来看:打包阶段(生成 AAR) 和 集成阶段(依赖 AAR 到上层项目)。
1. 打包阶段(生成 AAR)
-
Gradle 处理依赖方式
AAR 本身会把
classes.jar
(工程代码编译产物)、res
、assets
、AndroidManifest.xml
等打进去,但不会直接把你compileOnly
或implementation
的外部 jar 打进最终的classes.jar
,而是放到libs/
目录或通过依赖声明传递出去。 -
两个版本 jar 的冲突
如果你工程里
libs/
下放了两个版本的同一个 jar(包名、类路径相同),编译时 javac 会报 "duplicate class" 错误 ,根本打不出包。如果它们包名不同(比如一个是
com.google.gson.v2
,另一个是com.google.gson
),编译上可以共存,AAR 能正常生成。 -
Gradle 依赖传递
如果是通过
implementation
引入两个版本的同一个库(比如 fastjson 1.2.69 和 1.2.83),Gradle 默认会做 版本冲突解决(dependency resolution) ,只会选一个版本进最终 AAR 的依赖树,除非你手动配置resolutionStrategy
或api/compileOnly
来规避。
所以总结:
- 同包名同类 → 无法编译
- Gradle 冲突 → 会被自动选一个版本
- 不同包名/重定位过 → 可以同时打进去
2. 集成阶段(上层项目依赖这个 AAR)
-
重复依赖问题
如果宿主 app 也依赖了某个 jar 的不同版本,就会触发 依赖冲突:
- Gradle 还是只会选一个版本(默认是高版本),可能导致 AAR 里调用的 API 在宿主里跑不起来(NoSuchMethodError、NoClassDefFoundError)。
- 最典型的就是 Gson、OkHttp、Fastjson 这类库版本差异大时。
-
运行时问题
即便能编译通过,运行时还是可能出现:
- 方法缺失(新版本方法在旧版本中没有);
- 行为差异(同一 API 在不同版本表现不一样);
- ClassCastException(不同版本的类加载器视为不同 class)。
-
AAR 打包方式的隐患
- 如果 jar 被直接打到 AAR 的
libs/
里,那么宿主项目就会和自身依赖的 jar 合并,很容易产生冲突。 - 如果 jar 是通过
implementation
引入,则宿主最终只会保留一个版本,还是存在兼容性问题。
- 如果 jar 被直接打到 AAR 的
3. 常见解决思路
- 保持单一版本 :用 Gradle 的
dependencyResolutionStrategy
强制锁定一个版本。 - 重定位(shade):用 Shadow Plugin 或 JarJar 给某个版本的 jar 改包名,避免和宿主/其他库冲突。
- 提供独立 API:AAR 不直接暴露冲突库,而是用接口隔离,宿主来决定具体依赖哪个版本。
✅ 总结:
- 打包阶段:同包名类冲突直接报错;Gradle 冲突会只保留一个版本。
- 集成阶段 :即使能打成 AAR,也可能在宿主运行时报
NoSuchMethodError
、ClassCastException
等。
👉 最安全的做法是:不要把两个不同版本的 jar 硬塞进同一个 AAR,而是选择统一版本,或者通过重定位来隔离。
另外:需要注意不同包名的两个版本最好不要放在一起,容易引发问题。(依据业务情况)