Gradle是干嘛的颅崩?
簡(jiǎn)單的講,Gradle是基于Groovy的項(xiàng)目自動(dòng)化構(gòu)建工具,用來(lái)聲明項(xiàng)目配置
具體一點(diǎn)戈钢,在開(kāi)發(fā)過(guò)程中主要實(shí)現(xiàn)工程的管理,例如依賴(lài),打包,部署,發(fā)布,各種渠道的差異管理是尔,Gradle負(fù)責(zé)將這些行為以代碼的方式描述出來(lái)以實(shí)現(xiàn)行為的復(fù)用
基本概念
projects , tasks and action:工程殉了,任務(wù),還有行為
一個(gè)項(xiàng)目至少要有一個(gè)工程拟枚,一個(gè)工程至少要有一個(gè)任務(wù)薪铜,一個(gè)任務(wù)由一些行為組成
結(jié)合實(shí)例來(lái)理解:
對(duì)于一個(gè)標(biāo)準(zhǔn)的AS項(xiàng)目而言,一個(gè)build.gradle對(duì)應(yīng)一個(gè)project恩溅,action則相當(dāng)于build.gradle中的一段段代碼塊
在工程構(gòu)建的過(guò)程中隔箍,gradle會(huì)根據(jù)build.gradle中的配置信息生成相應(yīng)的project和task
Project實(shí)質(zhì)上是一系列task的集合,每一個(gè)task執(zhí)行一些工作脚乡,比如編譯類(lèi)文件蜒滩,解壓縮文件,刪除文件等等
怎么用?
構(gòu)建
- 初始化階段:首先會(huì)創(chuàng)建一個(gè)Project對(duì)象帮掉,然后執(zhí)行build.gradle配置這個(gè)對(duì)象弦悉。如果一個(gè)工程中有多個(gè)module,那么意味著會(huì)有多個(gè)Project,也就需要多個(gè)build.gradle
- 配置階段:配置腳本會(huì)被執(zhí)行,執(zhí)行的過(guò)程中蟆炊,新的task會(huì)被創(chuàng)建并且配置給Project對(duì)象
- 執(zhí)行階段:配置階段創(chuàng)建的task會(huì)被執(zhí)行稽莉,執(zhí)行的順序取決于啟動(dòng)腳本時(shí)傳入的參數(shù)和當(dāng)前目錄
task
task標(biāo)示一個(gè)邏輯上的執(zhí)行單元
舉幾個(gè)栗子:
- 重新編譯工程,用到一個(gè)叫做build 的task
- 清理工程涩搓,用到一個(gè)叫clean 的task
...
具體有哪些task可已通過(guò)gradle tasks查看
自定義task
在build.gradle中定義
- 方式1:
task haha {
println "HAHA"
}
執(zhí)行g(shù)radle haha污秆,則會(huì)打印出haha
- 方式2:
task hello << {
println "hello,world"
}
<<
意思是給hello這個(gè)task添加一些action,其實(shí)就是調(diào)用了task的doLast方法昧甘,相當(dāng)于以下:
task hello {
doLast{
println "hello良拼,world"
}
}
目前build.gradle中存在haha和hello兩個(gè)task,我們執(zhí)行一下gradle看看結(jié)果:
ckc@ckc-PC:~/AopDemo$ ./gradlew
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=gasp
> Configure project :
HAHA
The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
at build_1wojgokbha0tm9swmixbdcemv.run(/home/ckc/AopDemo/build.gradle:33)
結(jié)果可知充边,只執(zhí)行了haha的task
這里就有兩個(gè)疑問(wèn):
1.并沒(méi)有執(zhí)行haha的task庸推,他為什么執(zhí)行了?
2.既然haha執(zhí)行了hello為神馬沒(méi)有執(zhí)行浇冰?
解釋是贬媒,方式1的定義方式生成的task是在初始化階段就會(huì)默認(rèn)執(zhí)行,而方式2是在執(zhí)行階段才會(huì)執(zhí)行
簡(jiǎn)單的講就是doLast起到的作用
- 方式3:
// 需要繼承自DefaultTask
class HelloTask extends DefaultTask {
// @Optional 表示在配置該Task時(shí)肘习,message是可選的际乘。
@Optional
String message = 'I am 34sir'
// @TaskAction 表示該Task要執(zhí)行的動(dòng)作,即在調(diào)用該Task時(shí),hello()方法將被執(zhí)行
@TaskAction
def hello() {
println "$message"
}
@Override
void onlyIf(Spec<? super Task> onlyIfSpec) {
}
@Override
void setOnlyIf(Spec<? super Task> onlyIfSpec) {
}
@Override
Task doFirst(Action<? super Task> action) {
return null
}
@Override
Task doLast(Action<? super Task> action) {
return null
}
@Override
int compareTo(Task task) {
return 0
}
@Override
void setActions(List<Action<? super Task>> actions) {
}
}
// hello使用了默認(rèn)的message值
task helloOne(type: HelloTask)
// 重新設(shè)置了message的值
task helloTwo(type: HelloTask) {
message = "你站在這別動(dòng)漂佩,我去給你買(mǎi)橘子"
}
當(dāng)前工程中定義
我們可以把task定義在buildSrc
module中:
在項(xiàng)目的根目錄下新建一個(gè)名為buildSrc
文件夾(一定要這樣命名),然后依次新建子目錄src/main/groovy
,然后可以建自己的包名脖含,這里以com.oil為例,依次新建子目錄demo/gradle/task,然后在buildSrc根目錄下新建build.gradle文件投蝉,此build.gradle中:
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
在demo/gradle/task目錄下創(chuàng)建HelloTask.groovy文件养葵,此文件中:
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
class HelloThreeTask extends DefaultTask {
@Optional
String message = 'I am 34sir'
@TaskAction
def hello() {
println "hello world $message"
}
}
查看buildSrc
下的目錄:
使用此task:
build.gradle中:
task helloThree(type: HelloThreeTask) {
message = "hello three"
}
執(zhí)行命令:gradle helloThree
查看運(yùn)行結(jié)果:
> Task :app:helloThree
hello world hello three
自定義plugin
build.gradle中:
apply plugin: DateAndTimePlugin
dateAndTime {
timeFormat = 'HH:mm:ss.SSS'
dateFormat = 'MM/dd/yyyy'
}
// 每一個(gè)自定義的Plugin都需要實(shí)現(xiàn)Plugin<T>接口
class DateAndTimePlugin implements Plugin<Project> {
//該接口定義了一個(gè)apply()方法,在該方法中墓拜,我們可以操作Project港柜,
//比如向其中加入Task,定義額外的Property等咳榜。
void apply(Project project) {
println "Current time"
project.extensions.create("dateAndTime", DateAndTimePluginExtension)
//每個(gè)Gradle的Project都維護(hù)了一個(gè)ExtenionContainer,
//我們可以通過(guò)project.extentions進(jìn)行訪問(wèn)
//比如讀取額外的Property和定義額外的Property等爽锥。
project.task('showTime') << {
println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
}
project.tasks.create('showDate') << {
println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
}
}
}
//向Project中定義了一個(gè)名為dateAndTime的extension
//并向其中加入了2個(gè)Property涌韩,分別為timeFormat和dateFormat
class DateAndTimePluginExtension {
String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
String dateFormat = "yyyy-MM-dd"
}
執(zhí)行gradle showTime
以及gradle showDate
查看結(jié)果:
> Task :app:showTime
Current time is 14:52:11.539
> Task :app:showDate
Current date is 02/08/2018
執(zhí)行task
執(zhí)行多個(gè)task
gradle task1 task2 [...]
簡(jiǎn)化執(zhí)行
對(duì)于名字太長(zhǎng)的task可以簡(jiǎn)化執(zhí)行
例如上面的hello就可以這樣執(zhí)行:
gradle hell //能唯一標(biāo)識(shí)出task的字符串即可
自動(dòng)執(zhí)行任務(wù)
不想在每次打包前執(zhí)行各種自定義的任務(wù),我們可以在build時(shí)自動(dòng)執(zhí)行任務(wù):
afterEvaluate {
tasks.matching {
// 以process開(kāi)頭以ReleaseJavaRes或DebugJavaRes結(jié)尾的task
it.name.startsWith('process') && (it.name.endsWith('ReleaseJavaRes') || it.name.endsWith
('DebugJavaRes'))
}.each { task ->
task.dependsOn(chVer, chSo) // 任務(wù)依賴(lài):執(zhí)行task之前需要執(zhí)行dependsOn指定的任務(wù)
}
}
type
task clean(type: Delete) {
delete rootProject.buildDir
}
以上這段task想必大家都見(jiàn)過(guò)氯夷,這里出現(xiàn)了一個(gè)新的概念:type
task的有很多中類(lèi)型臣樱,此處的類(lèi)型就是delete,任務(wù)是刪除文件
常見(jiàn)的type
- Copy
將文件復(fù)制到目標(biāo)目錄,同時(shí)雇毫,也可以執(zhí)行重命名和過(guò)濾文件操作
替換AndroidManifest文件:
task chVer(type: Copy) { // 指定Type為Copy任務(wù)
from "src/main/manifest/AndroidManifestCopy.xml" // 復(fù)制src/main/manifest/目錄下的AndroidManifest.xml
into 'src/main' // 復(fù)制到指定目標(biāo)目錄
rename { String fileName -> //在復(fù)制時(shí)重命名文件
fileName = "AndroidManifest.xml" // 重命名
}
}
替換so文件:
task chSo(type: Copy) {
from "src/main/jniLibs/test" // 復(fù)制test文件夾下的所有so文件
into "src/main/jniLibs/armeabi-v7a" //復(fù)制到armeabi-v7a文件夾下
}
- Sync
與Copy任務(wù)類(lèi)似玄捕,唯一的區(qū)別是當(dāng)執(zhí)行時(shí)會(huì)復(fù)制源文件到目標(biāo)目錄,目標(biāo)目錄中所有非復(fù)制文件將會(huì)被刪除棚放,除非指定Sync.preserve(org.gradle.api.Action)
task syncDependencies(type: Sync) {
from 'my/shared/dependencyDir'
into 'build/deps/compile'
}
// 你可以保護(hù)目標(biāo)目錄已經(jīng)存在的文件枚粘。匹配的文件將不會(huì)被刪除。
task sync(type: Sync) {
from 'source'
into 'dest'
preserve {
include 'extraDir/**'
include 'dir1/**'
exclude 'dir1/extra.txt'
}
}
- Zip
創(chuàng)建ZIP歸檔文件飘蚯,默認(rèn)壓縮文件類(lèi)型為zip
task zip(type: Zip) {
from 'src/dist'
into('libs')
}