背景
前段时间在搞Android自动化打包的事情。
我们的library
是需要提供给其他团队使用的,所以在使用Jenkins
自动化打包过程中,需要将library
打包成aar
并发布到maven仓库上。
所以对于打包,我们需要先将myLibrary
打包成aar
并发布到maven仓库上,再清空app
的缓存,并将app
打包成apk
对应gradle
命令如下
gradlew myLibrary:clean myLibrary:uploadArchives app:clean app:assembleRelease
按原先的理解来说,gradle
在执行命令的时候,会顺序执行,会先执行myLibrary:clean
,再执行myLibrary:uploadArchives
,然后执行app:clean
,最后执行app:assembleRelease
在项目的依赖没有问题的时候,确实是没有问题的。
但是,由于我们是先上传myLibrary
到maven
仓库,然后app
再去获取最新的myLibrary
的 maven
依赖,这个过程中,当myLibrary
上传maven 仓库成功后,会自动将myLibrary
的maven依赖的版本号+1
。
这个具体看我的另一篇博客 Android Maven仓库搭建 - 实现自动化打包自动拉取最新maven依赖
这个时候就出问题了,会发现直接就报找不到依赖的错误了
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':app:lintVitalRelease'.
> Could not resolve all artifacts for configuration ':app:debugCompileClasspath'.
> Could not find com.heiko.test:myLibrary:2.0.99.
Required by:
project :app
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
这是为什么呢 ?
按gradle执行命令的顺序,按之前的理解是会先执行myLibrary:uploadArchives
将aar
上传到maven仓库,这时候再去执行app:assembleRelease
应该已经可以取到最新的依赖了才对呀 ?
测试
百思不得其解之际,写了一个gradle
的demo
,对task
的相关方法进行了打印
task myTask1 {
configure {
println("myTask1:configure")
}
doFirst {
println("myTask1:doFirst")
}
doLast {
println("myTask1:doLast")
}
}
task myTask2 {
configure {
println("myTask2:configure")
}
doFirst {
println("myTask2:doFirst")
}
doLast {
println("myTask2:doLast")
}
}
task myTask3 {
configure {
println("myTask3:configure")
}
doFirst {
println("myTask3:doFirst")
}
doLast {
println("myTask3:doLast")
}
}
然后我们使用命令行来执行myTask1
、 myTask2
、myTask3
gradlew myTask1 myTask2 myTask3
可以看到执行结果
Starting a Gradle Daemon, 1 busy Daemon could not be reused, use --status for details
> Configure project :
myTask1:configure
myTask2:configure
myTask3:configure
> Task :myTask1
myTask1:doFirst
myTask1:doLast
> Task :myTask2
myTask2:doFirst
myTask2:doLast
> Task :myTask3
myTask3:doFirst
myTask3:doLast
BUILD SUCCESSFUL in 5s
3 actionable tasks: 3 executed
这时,可以发现gradle会先去执行所有task
的configure
方法,再去真正依次执行各个task
gradle的生命周期
这就引申出gradle的生命周期了
- initialization:初始化阶段
- 执行工程的setting.gradle文件
- 解析整个工程下的所有Project,构建所有的Project对应的project对象
- Configuration:配置阶段
- 解析所有的Projects对象中的task,构建好所有task的依赖图 (执行的先后顺序)
- Excution:执行阶段
- 执行具体的task及依赖task (先执行目标Task依赖的Task,再执行目标Task)
这里说明一下
Project : 每个build.gradle 就对应一个project,Project里可以有多个Task
Task : 主要的工作执行者,每个Task由多个Action组成
我们在settings.gradle
中打印一句日志
再执行一下gradlew myTask1 myTask2 myTask3
,可以看到执行顺序
解决方案
知道了这个概念我们就可以知道,所有gradle task在执行之前,都会先执行所有task的configure
,进行配置。
所以,我们必须要把上面的这个gradle命令进行拆分。
步骤一 : 清空myLibrary
的缓存,并将myLibrary
打包成aar
并发布到maven仓库上
gradlew myLibrary:clean myLibrary:uploadArchives
步骤二 : 清空app
的缓存,并将app
打包成apk
gradlew app:clean app:assembleRelease
这样子执行,就不存在最初说的那个问题了。
Jenkins是支持创建多个gradle
执行命令的,所以是不需要把gradlew命令杂糅在一起,是可以拆分开来分步骤执行的,这个也是我们前期踩坑的地方。
重新配置好Jenkins,就可以继续搞我们的自动化打包了,详见 Android Maven仓库搭建 - 实现自动化打包自动拉取最新maven依赖