日常Android开发中,很大部分不需要自定义Gradle插件,但是需要定制一些task来满足需求,比如自定义打jar包,本文就借自定义打包来讲讲gradle的task使用方法和如何利用现在的task修改依赖关系。
自定义打包在N年前我也曾写过一篇博文,[使用gradle打包指定包名和类的jar](http://www.alloyteam.com/2015/03/shi-yong-gradle-da-bao-zhi-ding-bao-ming-he-lei-di-jar/),这是刚开始学习gradle时的做法,实现方法也就是在原有的gradle文件上建立一个Jar类型的task然后依赖编译过程的某个task然后调用相关apip实现自定义的功能
task makeJar(type:org.gradle.api.tasks.bundling.Jar) {
//指定生成的jar名
baseName 'sdk'
//从哪里打包class文件
from('build/intermediates/classes/debug/org/cmdmac/cloud/pluginsdk/')
//打包到jar后的目录结构
into('org/cmdmac/cloud/pluginsdk/')
//去掉不需要打包的目录和文件
exclude('test/', 'BuildConfig.class', 'R.class')
//去掉R$开头的文件
exclude{ it.name.startsWith('R$');}
}
makeJar.dependsOn(clearJar, build)
这种方式可以达到目的,但是有个问题是,这个task需要在命令行./gradlew makeJar执行或者在Androd Studio的gradle task界面上手动触发,一般我们运行生成apk并运行都是直接点run的,这个过程是不会触发我们定义的task的,原因是原有的task依赖链中没有makeJar,那如何做到我们点run就能执行的自定义的task呢?
由前面的原因分析可以知道是因为我们的task没有在原来的依赖链中,解决方法就是把它加到原有的依赖链中!方法如下:
//配置检查完后
afterEvaluate {
logger.log(LogLevel.ERROR, assemble.getTaskDependencies().toString())
logger.log(LogLevel.ERROR, assemble.getTaskDependencies().getDependencies().toString())
//让打包任务先依赖assemble任务
def t = tasks.jarAopLib
t.dependsOn assemble.getTaskDependencies().getDependencies()
//让assemble任务再依赖jarAopLib,这样相当于在原有任务中插入任务jarAopLib
assemble.dependsOn t
}
//打包任务
task jarAopLib(type: Jar) {
archiveName = 'aop.jar'
from('build/intermediates/classes/release')
destinationDir = file('build/libs')
// into('build/libs')
exclude('org/cmdmac/aop/BuildConfig.class')
exclude('org/cmdmac/aop/BuildConfig\$*.class')
exclude('**/R.class')
exclude('**/R\$*.class')
include('org/cmdmac/aop/')
}
重写afterEvalute闭包(这是gradle配置完成后会调用的方法,gradle分配置task和运行task两个状态),修改原来的依赖关系,把自定义的task加入到依赖链中,此时点run会自动执行jarAopLib生成一个aop.jar文件在工程的build/libs下。
上面我们是把打包任务定义在外层,这种方式不能根据debug和release分开打包,其实也可以把任务定义在闭包里面根据variant的根据来实现分类型打包,如:
afterEvaluate {
//遍历编译类型,一般是debug和release两种,用android.libraryVariants是因为我写在Library工程
android.libraryVariants.each { variant ->
//tasks对象包含了project下的所有task。这里根据编译类型实现命名不同动态创建task
def t = tasks.create(name: "JarLibTask-${variant.name}", type: Jar) {
archiveName "aop-${variant.name}.jar"
from('build/intermediates/classes/release')
destinationDir = file('build/libs')
exclude('org/cmdmac/aop/BuildConfig.class')
exclude('org/cmdmac/aop/BuildConfig\$*.class')
exclude('**/R.class')
exclude('**/R\$*.class')
include('org/cmdmac/aop/')
}
t.doLast {
//打包完成时会执行
System.out.println('打包完啦');
}
//修改依赖关系
t.dependsOn assemble.getTaskDependencies().getDependencies()
assemble.dependsOn t
}
}
点run就会出现aop-debug.jar和aop-release.jar,怎么样,是不是挺好用的?
上面的task是动态创建的,创建task方式有挺多种,我自己总结了这么几种使用方式:
//用task带括号创建要注意,第一个参数不能name:'xxx',否则参数无效,变成一个匿名task
//匿名task,archiveName属性不生效
def t = task("ttt${variant.name}", type: Jar) {
archiveName "aop-${variant.name}.jar"
logger.log(LogLevel.ERROR, 'ttt')
}
//有效,第一个参数为task名称
def t = task("ttt${variant.name}", type: Jar) {
logger.log(LogLevel.ERROR, 'ttt')
}
//也有效,第一个参数为task名称
def t = task(name: "ttt${variant.name}", type: Jar) {
logger.log(LogLevel.ERROR, 'ttt')
}
//也可以用tasks内置对象来创建
def t = tasks.create(name: 'xxx', type: Jar) {
…
}
//也可以这样
def t = task name(type: Jar) {
…
}
上面的例子中有看到可以在字符串中动态填入参数的用法,有点像java的String.format功能,这里需要注意的是groovy中要使用这个功能字符串需要使用双引号,单引号只是单纯的字符串,如:
//要用双引号才能字符串内带计算,单引号是纯字符串,下面这句输出结果为:'${variant.name
logger.log(LogLevel.ERROR, '${variant.name}')