gradle设置build执⾏命令_⼗分钟搞定Gradle 项⽬经验,如需转载,请注明作者:Yuloran (t/EGU6c76)
项⽬经验,如需转载,请注明作者:Yuloran (t/EGU6c76)
原⽂
⼗分钟搞定 Gradle - 掘⾦j uejin.im
前⾔
学习过程中,什么阶段最痛苦?⼤概是某个知识点的碎⽚信息学习了很多却仍然⽆法窥其门径,也就是似懂⾮懂的时候。对于 Gradle,笔者之前就是这种状态。在亲⼿完成了⼀个需求后,发现 Gradle 也不过如此。
由于笔者做需求时采⽤的是倒扒⽪的⽅式,即先 google 搜索如何解决问题,再阅读官⽅ Ur Guide,最后总结反思,所以⽤了半天的时间,还踩了⼀些坑。如果按照本⽂介绍,按部就班地学习,⼤概⼗分钟就够了。所谓⼀通则百通,窥其门径后,若有其它需求,直接查阅API 即可。
案例
笔者是做安卓整机开发的,⽬前接⼿了⼀个新项⽬,其 APP 分为两个版本,⼀个是系统预置(private),⼀个供其它品牌⼿机安装使⽤(public)。其中 public apk 需要打包到 private apk 的 asts ⽬录下,以在 private apk 上实现扫码安装 public apk 的功能。两个版本的代码⽬前是⼿动维护,很不⽅便。笔者便想通过创建⾃定义的 Task,让 Gradle 来⾃动构建。
问题
如何创建 private、public 两个 build variants(构建变体)?
如何配置 public 版本在 private 版本之前构建(因为 private 版本依赖 public 版本⽣成的 apk)?
public 版本构建完成后,如何⾃动复制其⽣成的 apk 到 private 版本的 asts ⽬录下?
解决⽅案
关于构建变体,其实就是⼀次编译,输出多个版本的 apk,具体内容请参考官⽅⽂档中⽂版《配置构建变体》
两个构建变体,说明对应两个 asmble task,那么只要获获取到这两个 task 对象,然后设置其依赖关系即可
Gradle ⽂件⽀持 groovy 编写,groovy ⼜是基于 java 的,所以即使不熟悉 groovy 的语法,也可以⽤ java 写出来。不过对于复制这种操作,Gradle 有现成的 API
如何编写
⽅案很清晰:asmblePublicApp -> deleteOldPublicApp -> signNewPublicApp -> copyNewPublicApp -> asmblePrivateApp
但是代码怎么写呢?笔者⼀时间感到⽆从下⼿。⽐如如何获取两个构建变体对应的 asmble task?如何创建⼀个 copy task?⼜如何在执⾏ copy task 之前先执⾏ delete task(删除 asts ⽬录下的旧 apk) 以及 sign task(签名 public apk)?
笔者⼀顿 google 搜索之后解决了这些问题,不过也踩了⼀个坑,就是⾃定义 task 内的代码执⾏时机不对。⽐如 deleteOldPublicApk task 中的⽇志,总是在执⾏ gradle asmble 命令之后⽴即输出,⽽不是在 asmblePublicApp task 之后输出:
File -> Demo/adle
android {
...
}
task deleteOldPublicApk(type: Delete) {
println("-----------> delete the old pubic apk begin") // 注意:这么写代码会在配置阶段⽴即执⾏
delete 'src/privateApp/asts/Public.apk' // delete ⽅法继承⾃ Delete task,所以是⼀个 Action,在执⾏阶段才会被执⾏
println("-----------> delete the old pubic apk end") // 注意:这么写代码会在配置阶段⽴即执⾏
}
task signNewPublicApp() {
doFirst {
println 'sign the new public app' // 写在 doFirst 或者 doLast 中,才会在执⾏阶段被执⾏,具体见下⽂
}
}
task copyNewPublicApp() {
doLast {
println 'copy the new public app'
}
}
afterEvaluate {
def asmblePublic = ByName('asmblePublicAppRelea')
deleteOldPublicApk.dependsOn(asmblePublic)
copyNewPublicApp.dependsOn(deleteOldPublicApk, signNewPublicApp)
def asmblePrivate = ByName('asmblePrivateApp')
asmblePrivate.dependsOn(copyNewPublicApp)
}
dependencies {
...
}
如上所⽰的 deleteOldPublicApk task,只要在 terminal 中 输⼊ gradlew asmble 必然会⾸先打印:
-----------> delete the old pubic apk begin
-----------> delete the old pubic apk end
相信很多不熟悉 Gradle 的⼈都会犯这样的错误,stackoverflow 上有⼈也发出了同样的疑问 Why is my Gradle task always running?后来笔者阅读了 Gradle 的官⽅⽂档 《Build Lifecycle》,恍然⼤悟,应该这么写:
task deleteOldPublicApk(type: Delete) {
doFirst {
println("-----------> delete the old pubic apk begin")
}
delete 'src/privateApp/asts/Public.apk'
doLast {
println("-----------> delete the old pubic apk old")
}
}
痛定思痛,笔者决定将 Gradle 的⼊门在此做⼀个总结。
⼊门
Gradle 的⼊门其实很简单,不需要深⼊学习 Groovy(随⽤随查),也不⽤记 Gradle 的 API(随⽤随查)。只需要了解⼏个核⼼概念(构建模型、构建的⽣命周期、Project、Task、TaskContainer),就能做到⼀通百通了。
构建模型的核⼼
左边是构建模型的抽象,右边是⼀个 java ⼯程的具体实现。Gradle 的核⼼就是左边的抽象模型(有向⽆环图),也就是说⼀个完整的构建过程,其实就是⼀系列 Task 的有序执⾏。
构建⽣命周期
注意,这⼀⼩节尤为重要,特别是配置阶段与执⾏阶段的区别,⼀定要分清楚。
三个构建阶段
1. Initialization:配置构建环境以及有哪些 Project 会参与构建(解析 ttings.build)
2. Configuration:⽣成参与构建的 Task 的有向⽆环图以及执⾏属于配置阶段的代码(解析 adle)
3. Execution:按序执⾏所有 Task
⽰例
File-> adle
println 'This is executed during the initialization pha.' // adle 中的代码在初始化阶段执⾏
File->Demo/adle
println 'This is executed during the configuration pha.' // 在配置阶段执⾏
// 普通的⾃定义 Task
task testBoth {
doFirst {
println 'This is executed first during the execution pha.' // doFirst 中的代码在执⾏阶段执⾏
}
doLast {
println 'This is executed last during the execution pha.' // doLast 中的代码在执⾏阶段执⾏
}
println 'This is executed during the configuration pha as well.' // ⾮ doFirst 或者 doLast 中的代码,在配置阶段执⾏
}
// 继承⾃ Copy 的 TasK
task copyPublicApk(type: Copy) {
doFirst {
println("-----------> copy the new pubic apk begin")
}
// from, into, rename 都继承⾃ Copy,所以即使直接写也是在执⾏阶段执⾏
from 'build/outputs/apk/app-publicApp-relea.apk'
into file('src/privateApp/asts')
rename { String fileName ->
fileName = "Public.apk"
}
doLast {
println("-----------> copy the new pubic apk end")
}
}
Project
⼀个 adle 对应⼀个 Project 对象,在 gradle ⽂件中可通过 project 属性访问该对象。⽽ rootProject 属性代表的是根 Project 对象,即项⽬根⽬录下的 adle ⽂件。
Project 由⼀系列的 task 组成,你可以⾃定义 task,也可以继承已有的 task:
Project 还有⾃⼰的属性和⽅法:
Task types 以及 Project 的属性和⽅法都可以在 Groovy DSL Reference 中查到。
Task
在 gradle ⽂件中,我们⼀般使⽤ task 关键字来定义⼀个 task,通过 task 的名字就可以直接访问该 task 对象:
File -> Demo/adle
task customTask() {
doLast {
println 'hello, this is a custom task'
}
}
如何查找⼀个 task 呢?通过 TaskContainer 对象,在 gradle ⽂件中通过 tasks 属性来访问该对象:
File -> Demo/adle
afterEvaluate {
def aTask = ByName('asmbleDebug')
println "aTask name is ${aTask.name}"
aTask.dependsOn(customTask)
}
如上所⽰,我们获取到了 asmbleDebug 这个 Task 的实例,并设置它依赖之前定义的 customTask,所以执⾏ asmbleDebug 时就会先执⾏ customTask。
TaskContainer 还有很多查找 task 的⽅法,具体可以查询 Task Container。
Gradle API 查阅指导
了解了构建模型及三⼤阶段,接下来就是如何查阅 API ⼿册了。因为 Android Studio 对 Gradle ⽂件的编写⽀持很不友好,笔者经常会出现代码没有智能提⽰、⽆法⾃动补全、⽆法代码跳转等问题,⽽且语法⾼亮也是弱的可怜。所以,必须掌握⼿动查阅 Gradle API 的⽅法。
不过现在 Gradle ⽂件也可以使⽤ kotlin 编写,语法清晰,可读性好,⽽且⽀持语法⾼亮、代码补全、代码跳转等。感兴趣的可以参考官⽅迁移教程《Migrating build logic from Groovy to Kotlin》 。
离线查看
Gradle ⽹站现在也可以正常访问了,不过 Android Studio 在下载 Gradle 插件时,已经⾃动将⽤户指南、DSL参考、API参考下载到本地了:
dsl:⾥⾯的内容跟 javadoc 差不多,不过是经过分类的,交互体检⽐ API ⽂档要好,主要关注核⼼类型⾥的 Project、Task 和TaskType,具体关注⾥⾯的属性和⽅法,以及继承的属性和⽅法,⽤到什么就去查什么
javadoc:java api ⽂档,可以查看类的继承以及实现情况,快速索引
urguide:⽤户指南,⽐如 build lifecycle 的介绍,不过 html 内部的链接点击⽆法跳转,还好⽬录下有个带书签的 pdf 版
在线⽂档
离线⽂档不⼀定是最新的,有需要时可以查看在线⽂档
dsl