前言
通过前两篇文章我们了解了 Groovy语言、 Gradle基本命令、生命周期、Task 的相关知识,那么这篇文章主要记录一些关于插件以及依赖配置的知识。
一、Project
build.gradle 在配置阶段会生成 project 实例,在 build.gradle 中直接调用方法或属性,实则是调用当前工程 project 对象的方法或属性。
1.project的相关api
project(':app'){ }
指定project(app)的配置,源代码如下:
/**
* <p>Locates a project by path and configures it using the given closure. If the path is relative, it is
* interpreted relative to this project. The target project is passed to the closure as the closure's delegate.</p>
*
* @param path The path.
* @param configureClosure The closure to use to configure the project.
* @return The project with the given path. Never returns null.
* @throws UnknownProjectException If no project with the given path exists.
*/
Project project(String path, Closure configureClosure);
allprojects{ }
表示配置所有的project及其子project
allprojects {//fro project include repositories
repositories {
google()
mavenCentral()
}
}
subprojects{ }
表示配置所有的子project
//根目录下的build.gradle
subprojects {
println("subprojects->$it")
}
输出:
> Configure project :
subprojects->project ':app'
4. buildscript{ }
表示项目配置构建脚本类路径
buildscript {//for ☆gradle include dependencies and repositories
repositories {
google()
mavenCentral()
}
dependencies {//构建工具的依赖
classpath(group: 'com.android.tools.build', name: 'gradle', version: '4.2.1')
}
}
2.ext扩展
使用 ext 可以对任意对象属性进行扩展。
- 在根项目中配置对其它 project 均可见
- 一般在 root project 中进行 ext 属性扩展,为子工程提供复用属性,通过 rootProject 直接访问。
- 任意对象都可以使用 ext 来添加属性:使用闭包,在闭包中定义扩展属性。直接使用 = 赋值,添加扩展属性。
//根build.gradle
this.ext.pop = "pop"
//ext{
// pop = '1111'
//}
4.使用 gradle.properties 以键值对形式定义属性,所有 project 可直接使用。
例如:我们在管理全局依赖配置文件一般会有 config.gradle 文件,一般写法如下:
ext {
android = [
compileSdkVersion: 29,
minSdkVersion : 21,
targetSdkVersion : 29,
]
androidxVersion = "1.0.0"
supportDependencies = [
supportV4: "androidx.legacy:legacy-support-v4:${androidxVersion}",
]
}
然后在 module 中的 build.gradle 引入此文件使用其属性达到依赖版本统一。
二、插件
插件就是把独立或可公用的代码进行打包,已达到其它模块的复用。插件的应用都是通过 Project.apply() 方法完成的,并且插件分为两种,一种是脚本插件,另一种是二进制插件。
1.脚本插件
脚本插件就是直接编辑在 gradle 脚本文件中,然后通过 apply plugin: PluginName
引用对应的插件,只能在此脚本中使用。
class MyPlugin implements Plugin<Project> {
@Override
void apply(Project target) {
//此project对象就是 apply插件的Project对象
println "MyPlugin apply"
}
}
apply plugin: MyPlugin
2.二进制插件
二进制插件就是实现了 Plugin 接口的插件,他们有 plugin id,通过 apply id 引用。一般可以在单独的项目中实现,也可以在 buildSrc 目录下编写,由于 buildSrc 可应用于其他项目,那么在它项目初始化前就需要构建好 buildSrc,所以他的构建时间会早于 settings.gradle,接下来我们以 buildSrc 方式来实现, buildSrc 目录下的插件,在运行时,会自动打包成 jar 并进行依赖,实现方式:
- 创建 moudle,并且命名为 buildSrc。
- 删除目录仅留下 main 文件夹,然后创建 java 文件夹( groovy 也可以,只是实现的语言不同),和 resources 文件夹。
- 新建 resources -> META-INF.gradle-plugins -> com.empty.test.properties 文件,并且写入
implementation-class=com.empty.test.MyTestPlugin
- 在 buildSrc 中配置 groovy 依赖:
apply plugin:'groovy'
- 在 app 中
apply plugin: MyTestPlugin
即可使用
三、Transform
Transform 允许我们在 class 文件转为 dex 文件前操作编译好的 class 文件,每个 Transform 都是一个 gradle task。具体实现如下:
class MyTestTransform extends Transform {
@Override
String getName() {
return MyTestTransform
}
@Override
Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS
}
@Override
Set<? super QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT
}
@Override
boolean isIncremental() {
return true
}
@Override
void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
super.transform(transformInvocation)
transformInvocation.inputs.each { TransformInput input ->
input.jarInputs.each { JarInput jarInput ->
//处理Jar
}
input.directoryInputs.each { DirectoryInput directoryInput ->
//处理源码文件
}
}
}
- getName():对应的Task名称
- getInputTypes():确定对那些类型的结果进行转换,常用的是 CONTENT_CLASS 表示要处理 java 的 class 文件。
- getScopes():指定插件的适用范围,常用的是 TransformManager.SCOPE_FULL_PROJECT 表示处理全部的class 字节码。
- isIncremental():是否支持增量更新
- transform():具体的转换过程
之后在 Plugin 中注册这个 Transform 即可。
def appExtension = project.getExtensions().getByType(AppExtension.class)
appExtension.registerTransform(new MyTestTransform())
四、依赖管理
关于依赖项的配置,我们常用的有 implementation、api、compileOnly 等,具体的解释官网中有, 链接在此。
需要注意的是:
- A implemetation B,B implemetation C,则 A 不能使用 C。
- A implemetation B,B api C,则 A 可以使用C。
- A implemetation B,B implemetation C,C api D,则 B 可以使用 D,但 A 不能使用 D。
- A implemetation B,B api C,C api D,这样 A 可以使用 D 不管ABCD在何处被添加到类路径都一样,在运行时这些模块中的 class 都是要被加载的。
1.查看项目依赖
要查看项目依赖项 可使用命令:
gradlew :app:dependencies
或者 gradlew :app:dependencies --configuration compile
也可以使用 gradlew build --scan
在网址上看。
同时 Gradle 也会有一部分优化,例如:
如果项目存在同一个依赖库的多个版本,默认选择最高版本、Gradle 会自动排除重复的依赖、Gradle 默认支持依赖传递等等。
其中
- x.x.x (*) 该依赖已经有了,将不再重复依赖。
- x.x.x -> x.x.x 该依赖的版本被箭头所指的版本代替。
- x.x.x -> x.x.x(*) 该依赖的版本被箭头所指的版本代替,并且该依赖已经有了,不再重复依赖。
2.排除依赖
随着应用的范围不断扩大,它可能会包含许多依赖项,包括直接依赖项和传递依赖项(应用中导入的库所依赖的库)。如需排除不再需要的传递依赖项,可以使 exclude 关键字:
dependencies {
implementation('androidx.appcompat:appcompat:1.2.0') {
exclude(group: 'androidx.core')
exclude(group: 'androidx.arch.core', module: 'core-common')
}
}
使用全部排除:
// 在configurations{ } 中添加下面节点
configuration {
all*.exclude module: 'name'
}
3.指定依赖库版本
使用 force 来强行指定某个三方库的版本。
configurations.all {
resolutionStrategy {
force 'group:module:version'
}
}
五、发布插件到本地
先引入 maven 插件,再在 uploadArchives 加入上传的仓库地址与相关配置,配置中:groupId 为组织或公司名称, artifactId 为模块名称,version 为当前版本号,这样 Gradle 在执行 uploadArchives 时将生成和上传 pom.xml 文件。
apply plugin: 'maven'
uploadArchives {
repositories.mavenDeployer {
repository(url: uri('../repostory'))
pom.groupId = "com.empty.test"
pom.artifactId = "mylibrary"
pom.version = "1.0.0"
}
}
implementation(group: 'com.empty.test', name: 'mylibrary', version: '1.0.0')
发布远程一般为 MavenCentral 或者 Jitpack ,具体实现可自查。
六、总结
到这里,我们了解到什么是project、自定义插件、Transform、发布插件及依赖配置。