第三章 依赖管理
我们只需要在构建文件 build.gradle 中添加一行代码,Gradle 将会从远程仓库下载依赖,确保我们的项目能够使用依赖中的类。
- 如果我们的项目中的某一个依赖A,A自己还有一个依赖B,Gradle 会帮助我们处理这种情况,这些依赖中的依赖叫做
依赖传递
。
一、依赖仓库
一般情况下我们讨论的依赖指的是外部依赖,比如其他开发者提供的 依赖库
。
一个 依赖仓库
可以被看做是文件的集合。Gradle 默认情况下不会给我们的项目添加任何依赖,我们需要在 repositories
代码块中添加它们。
repositories{
jcenter()
}
Gradle 支持三种不同的依赖仓库:Maven
Ivy
静态文件或文件夹
。在构建的执行阶段,依赖从依赖仓库中被获取出来。Gradle 也有本地缓存,所以一个特定版本的依赖只会下载一次。
一个依赖通常由三种元素定义:group
name
version
。
- group:指定了创建该依赖的组织,通常是反向域名(可选,为了表述清楚一般会添加group)
- name:依赖库的唯一标识 (必选)
- version:指定了需要使用依赖库的版本(可选,不写的话依赖会自动更新,可能会影响到项目构建)
1. 预定义依赖仓库
为了方便,Gradle 预定义了三个 Maven 仓库:JCenter
Maven Central
本地Maven仓库
。
在 repositories
中添加他们:
repositories {
jcenter()
mavenCentral()
mavenLocal()
}
默认情况下,使用 AndroidStudio 创建 Android 项目时,默认使用的依赖仓库就是 JCenter
。JCenter
是 Maven Central
的超集,并且 JCenter
支持 HTTPS。
2. 远程仓库
一些组织会创建有趣的插件或依赖库,并且更喜欢将它们放在自有的 Maven 或 Ivy 服务器上,而不是将它们发布到 Maven Central
或 JCenter
。如果要想在构建中使用这些依赖,需要在 maven
代码块中添加 URL:
如果你的团队正在使用自己的仓库,那么需要进行资格验证后才能访问它们,下面是为一个仓库添加凭证的方法:
maven {
url "http://repo.example.com/maven2"
//验证
credentials{
//用户名
username 'user'
//密码
password 'secretpassword'
}
}
- 不建议在构建配置文件中存储你的凭证。更高的方法是使用一个单独的 Gradle 属性文件
- 因为配置文件会被迁入源码控制系统。
3. 本地仓库
我们可以在自己的硬盘驱动器或网络驱动器上运行 Maven 和 Ivy 仓库。要想在构建中添加本地仓库,只需要配置一个相对或绝对路径的 URL 即可:
repositories{
maven{
url "../repo"
}
}
新的 Android 项目默认情况下有一个 Android Support Library
的依赖。当使用 SDK Manager 来安装 Google 仓库时,在硬件驱动器上,会创建两个 Maven
仓库,分别是 ANDROID_SDK/extras/google/m2repository
和 ANDROID_SDK/extras/android/m2repository
。Gradle 通过它们获取谷歌提供的依赖包(eg:Android Support Library
和 Google Play Services
。
二、本地依赖
有时我们可能需要创建自己的依赖库,以便可以在没有将其发布到公有或私有仓库时在多个项目中复用。这时,我们不能使用任何在线资源,必须通过其他方式来添加依赖。
1. 文件依赖
可以使用 Gradle 提供的 files
方法来添加 JAR 文件作为一个依赖:
dependencies{
implementation files('libs/xxx.jar')
}
也可以直接添加一个完整的文件夹:
dependencies{
//会直接把 libs 下的 文件 包全部引用
implementation fileTree('libs')
}
默认情况下,新建的 Android 项目会有一个 libs
文件夹,其会被声明为依赖使用的文件夹,默认情况下会依赖 libs
文件夹下的所有文件。可以使用过滤器来选定只依赖 JAR
文件:
dependencies{
//会直接把 libs 下的 Jar 包全部引用
implementation fileTree(dir: 'libs', include:['*.jar'])
}
2. 原生依赖库
用 C
或 C++
编写的依赖库可以被编译成特定平台的原生代码。这些依赖库通常包含几个 .so
文件,可以用于所有平台。 Android 插件默认支持原生依赖库(用 C
或 C++
编写的),我们只需要在模块层创建一个 jniLibs
文件夹,然后为每个平台创建子文件夹,将 .so
文件放在适当的文件夹中:
3. 依赖项目
如果想自己写一个 Android API
或 Android 资源
的依赖库分享给别人使用,那么需要创建一个依赖项目。依赖项目通常和应用项目类似,不同之处在于输出不同。应用项目将生成一个可被安装和运行在 Android 设备上的 APK ,依赖项目则生成一个 .aar
文件。该文件可被 Android 应用项目用作依赖库。
1) 创建和使用依赖项目模块
不同于 Android 应用插件,构建脚本需要应用 Android 依赖库插件:
apply plugin: 'com.android.library'
在应用中包含依赖项目的方式有两种:
在项目中当做一个模块
创建一个可在多个应用中复用的 .aar 文件
如果在项目中创建了一个模块作为依赖项目,那么我们需要在 setting.gradle
中添加该模块,在应用模块中将它作为依赖:
Include ':app', ':library'
在这种情况下,依赖模块被称为依赖库,并且文件夹的名称与此相同,要在 Android 模块中使用依赖库,需要在 Android 模块的 build.gradle
文件中添加一个依赖库:
dependencies{
compile project(':library')
}
2)使用 .arr
文件
如果创建了一个依赖库,想在不同的 Android 应用中复用,那么可以创建一个 .aar
文件,然后将其作为一个依赖添加到项目中。在构建依赖库时,模块目录下的 build/out/aar/
文件夹将会生成 .aar
文件。在应用模块中创建一个文件夹,赋值 .aar
文件到该文件夹,并且将该文件夹作为依赖仓库:
repositories{
flatDir{
dirs 'aars'
}
}
通过如下方法(告知 Gradle 查找具有特定名称且扩展名为 .aar
的依赖库),我们可以添加任何文件到该目录下,并将其作为依赖:
dependencies{
implementation name:'文件夹名', ext:'aar'
}
三、依赖概念
1. 配置
有时可能你不得不和一个只在特定设备上工作的 SDK 打交道,比如特定厂商的蓝牙 SDK。为了能够编译该代码,你需要将 SDK 添加至编译类路径。你并不需要添加 SDK 到你的 APK 中,因为其早已存在于设备中,这就是所谓的依赖配置。
Gradle 将多个依赖添加至配置,并将其命名为 集文件
。(是被命名为xx,所以没什么其他的含义)。
下面是 Gradle 2.x.x版本 Android 应用或依赖库的标准配置:
- compile
- 默认的配置,在编译主应用时包含所有的依赖
- 该配置不仅会将依赖添加至类路径,还会生成对应的
APK
- apk
- 只会将该依赖打包到
APK
,而不会添加到编译类路径 - 只适用于
JAR
依赖
- 只会将该依赖打包到
- provided
- 不会将该依赖打包到
APK
,会添加到编译类路径 - 只适用于
JAR
依赖
- 不会将该依赖打包到
- testCompile
- 添加用于测试的额外依赖库,不会添加到
release
版本中
- 添加用于测试的额外依赖库,不会添加到
- androidTestCompile
- 添加用于测试的额外依赖库,不会添加到
release
版本中
- 添加用于测试的额外依赖库,不会添加到
下面是 Gradle 3.x.x版本 Android 应用或依赖库的标准配置:
- implementation
- 只对当前的
Module
提供提供接口。 - 依赖A通过
implementation
引用了依赖B,我们的项目引用了依赖A,那么我们的项目是无法访问依赖B的接口的
- 只对当前的
- api
- 2.x.x 版本中的
compile
- 2.x.x 版本中的
- compileOnly
- 2.x.x 版本中的
provided
- 2.x.x 版本中的
- runtimeOnly
- 2.x.x 版本中的
apk
- 2.x.x 版本中的
- unitTestImplementation
- testImplementation
- debugImplementation
- releaseImplementation
2. 语义化版本
版本化是依赖管理的重要部分。将依赖添加到 JCenter
等依赖仓库时,约定遵循
了一套版本化规则,我们称之为 语义化版本
。
版本数字的格式一般为:major.minor.patch
数字按照下列规则依次增加:
- 当做不兼容 API 变化时,
major
版本增加 - 当以向后兼容的方式添加功能时,
minor
版本增加 - 当修复一些 bug 时,
patch
版本增加
3. 动态化版本
在某些情况下,你可能希望在每次构建你的应用或依赖时,都能够获取到最后的依赖,要想做到这一点,最好的实现方式是使用动态化版本。动态化版本的使用方式有很多种:
dependencies{
//获取最新的版本
implementation 'com.android.support:support-v4:22.2.+'
//获取最新的 minor 版本,并且 minor 版本至少是 2
implementation 'com.android.support:appcompat-v7:22.2+'
//获取依赖库的最新版本
implementation 'com.android.support:recyclerview-v7:+'
}
注: 动态化版本可能会因为 Gradle 自动获取的依赖版本不稳定而导致构建失败
四、总结
添加依赖到 Android 项目的多种方式,各种各样的依赖仓库,未使用依赖仓库时如何添加文件。
配置名称,语义化版本,动态化版本都是什么。
下一章:variants 。