1. Android音频系统全景
1.1 依赖坐标
Gradle 使用 Maven 坐标(GAV)来唯一标识一个外部依赖。一个完整的依赖坐标由三个部分组成:group(组织/集团标识)、name(模块名称)、version(版本号)。在 build.gradle 中声明依赖时,通常写作:
implementation 'com.google.guava:guava:31.1-jre'
上面字符串格式等价于:group = 'com.google.guava', name = 'guava', version = '31.1-jre'。坐标是 Gradle 从仓库中查找依赖的唯一凭据。
| 坐标部分 | 含义 | 示例值 |
|---|---|---|
| group | 组织或项目组标识,通常为反向域名 | com.google.guava |
| name | 模块或构件名称 | guava |
| version | 版本号,可包含 range 或动态版本 | 31.1-jre |
Tip: 在 Gradle 中,也可以使用 Map 形式声明依赖,如
implementation group: 'com.google.guava', name: 'guava', version: '31.1-jre',更便于动态构建坐标。
1.2 仓库配置
依赖坐标指向的构件需要从仓库中下载。Gradle 支持 Maven、Ivy 和本地文件仓库。默认情况下,Gradle 不会配置任何仓库,必须手动声明。常用仓库配置在 build.gradle 的 repositories {} 块中:
repositories {
mavenCentral()
google()
maven { url 'https://jitpack.io' }
mavenLocal() // 本地 ~/.m2/repository
flatDir { dirs 'libs' } // 本地目录仓库
}
- mavenCentral() – Maven Central 远程仓库,最常用且稳定。
- google() – Google 的 Maven 仓库,主要用于 Android 依赖。
- maven { url '...' } – 自定义 Maven 仓库地址。
- mavenLocal() – 本地 Maven 缓存仓库,用于引用本地构建的构件。
- flatDir { dirs 'libs' } – 从项目本地目录加载 JAR/AAR 文件,不依赖坐标。
Warning: 仓库配置的顺序影响依赖查找效率。通常将 mavenCentral() 放在最前,但 Google 仓库或 private 仓库若包含同名构件先被找到,可能导致版本冲突。建议明确可重复的仓库列表。
1.3 implementation vs api
Gradle 的 Java / Android 插件引入了两种主要的依赖配置:implementation 和 api。它们控制依赖是否对外泄露(即是否传递到消费者的编译 classpath)。
| 配置 | 行为 | 适用场景 |
|---|---|---|
| implementation | 依赖仅对当前模块可见,不对消费者暴露其编译接口 | 内部实现依赖,不希望在库的 API 中暴露的类型 |
| api | 依赖同时暴露给当前模块和所有消费者(传递到编译 classpath) | 库的公开 API 中直接引用的第三方类 |
典型示例:
dependencies {
// 内部使用 Gson,不暴露给使用方
implementation 'com.google.code.gson:gson:2.9.0'
// 注解工具 @NonNull 暴露在公共方法签名中,必须用 api
api 'com.google.code.findbugs:jsr305:3.0.2'
}
性能建议: 优先使用
implementation,可减少重新编译时的传播范围,提升构建速度。只有那些作为公开 API 类型暴露的依赖才使用 api。
1.4 compileOnly 和 runtimeOnly
- compileOnly – 仅在编译期可见,不会被打包或传递。常用于编译时需要的注解处理器或 Lombok。
- runtimeOnly – 仅在运行期可见,编译时不需要。典型场景:数据库驱动(编译时只需接口,运行时需要具体实现)。
声明示例:
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.26'
annotationProcessor 'org.projectlombok:lombok:1.18.26'
runtimeOnly 'mysql:mysql-connector-java:8.0.33'
}
对比总结:
| 配置 | 编译 classpath | 运行时 classpath | 是否传递 |
|---|---|---|---|
| compileOnly | 是 | 否 | 否 |
| runtimeOnly | 否 | 是 | 否 |
| implementation | 是 | 是 | 否(不对外暴露) |
| api | 是 | 是 | 是(暴露给消费者) |
1.5 依赖声明结构图
下图展示了 Gradle 依赖声明的完整链路:从坐标形成、仓库解析,到不同配置的作用域。
1.6 常见错误与调试
- 依赖无法解析:忘记配置仓库或仓库中不存在指定坐标。检查
repositories块是否包含所需仓库。 - 传递依赖版本冲突:多个依赖引入相同库的不同版本。使用
./gradlew dependencies查看依赖树,通过force或constraints统一版本。 - 误用 api 导致编译过慢:无意中将内部依赖声明为
api,导致下游模块频繁重新编译。使用implementation替代。 - compileOnly 依赖在运行时 ClassNotFoundException:确认运行时 classpath 存在相应 jar,或改用
implementation。
调试命令:
# 查看项目依赖树
./gradlew :app:dependencies
# 查看指定配置的依赖
./gradlew :app:dependencies --configuration compileClasspath
1.7 性能与稳定性优化建议
- 优先使用
implementation而非api,减少模块重新编译范围。 - 仓库配置中尽量指定 HTTPS 并启用缓存:
maven { url '...'; metadataSources { mavenPom() } }。 - 使用版本目录(Version Catalog)集中管理依赖版本,避免散落版本号。
- 对于仅在本地开发使用的依赖(如 Lombok、QueryDSL),使用
compileOnly避免打包体积膨胀。
实战提示: 在 Android 项目中,
implementation 和 api 的区别尤为重要。如果一个库使用了 api 暴露了 AndroidX 依赖,可能导致应用模块无法独立升级版本。建议始终先尝试 implementation,遇到编译错误再升级为 api。