settings.gradle(對應Settings.java)決定哪些工程須要被gradle處理,佔用了整個gradle生命週期的三分之一,即Initialzation初始化階段。html
對默認的文件位置進行修改,從而讓gradle知道哪一種資源要從哪些文件夾中去查找。java
// sourceSets是能夠調用屢次的
android {
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
sourceSets {
main {
res.srcDirs = ['src/main/res',
'src/main/res-ad',
'src/main/res-player']
}
}
}
// sourceSets通常狀況下是一次性配置
android {
sourceSets {
main {
jniLibs.srcDirs = ['libs']
res.srcDirs = ['src/main/res',
'src/main/res-ad',
'src/main/res-player']
}
}
}
// 使用編程的思想,配置sourceSets
this.android.sourceSets{
main {
jniLibs.srcDirs = ['libs']
res.srcDirs = ['src/main/res',
'src/main/res-ad',
'src/main/res-player']
}
}
複製代碼
Gradle中的Plugin是對完成指定功能的Task封裝的體現,只要工程依賴了某個Plugin,就能執行該Plugin中全部的功能,如:使用java插件,就能夠打出jar包,使用Android插件,就能夠生成apk、aar。android
apply plugin: 'groovy'
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'
}
resources {
srcDir 'src/main/resources'
}
}
}
複製代碼
最後,Async一下工程,buildSrc就會被識別出來了,總體目錄如圖:git
與java同樣,在groovy目錄下,建立一個包,再建立一個插件類(如:com.lqr.gradle.study.GradleStudyPlugin),該插件類必須實現Plugin接口。github
注意:gradle插件類是.groovy文件,不是.java文件編程
import org.gradle.api.Plugin
import org.gradle.api.Project
/** * 自定義Gradle插件 */
class GradleStudyPlugin implements Plugin<Project> {
/** * 插件引入時要執行的方法 * @param project 引入當前插件的project */
@Override
void apply(Project project) {
println 'hello gradle study plugin. current project name is ' + project.name
}
}
複製代碼
在編寫完插件類的邏輯以後,須要在META-INF.gradle-plugins目錄下建立一個properties文件(建議以插件類包名來命名,如:com.lqr.gradle.study.properties),在該properties中聲明插件類,以此來指定插件入口。api
該properties文件的名字將做爲當前gradle插件被app工程引用的依據。閉包
implementation-class=com.lqr.gradle.study.GradleStudyPlugin // 若是報錯 Could not find implementation class 'xxx' 的話,通常是類全路徑有問題,默認包不須要寫包路徑,修改以下便可: // implementation-class=GradleStudyPlugin 複製代碼
打開app工程的build.gradle,應用上面的自定義gradle插件,並Async。app
apply plugin: 'com.android.application'
apply plugin: 'com.lqr.gradle.study'
android {
...
}
複製代碼
能夠看到,在gradle的配置階段,就輸出了前面自定義插件的apply方法中的日誌。 maven
插件每每會在gradle腳本中進行參數配置,如在android{}中,能夠配置compileSdkVersion等參數,其實本質上,就是在gradle腳本中使用閉包方式建立了一個javaBean,並將其傳遞到插件中被插件識別讀取而已。步驟以下:
1)建立一個實體類,聲明成員變量,用於接收gradle中配置的參數。(能夠理解爲就是javaBean,不過要注意,該文件後綴是.groovy,不是.java)
class ReleaseInfoExtension {
String versionCode
String versionName
String versionInfo
String fileName
ReleaseInfoExtension() {}
@Override
String toString() {
return "versionCode = ${versionCode} , versionName = ${versionName} ," +
" versionInfo = ${versionInfo} , fileName = ${fileName}"
}
}
複製代碼
2)在自定義插件中,對當前project進行擴展。
class GradleStudyPlugin implements Plugin<Project> {
/** * 插件引入時要執行的方法 * @param project 引入當前插件的project */
@Override
void apply(Project project) {
// 這樣就能夠在gradle腳本中,經過releaseInfo閉包來完成ReleaseInfoExtension的初始化。
project.extensions.create("releaseInfo", ReleaseInfoExtension)
}
}
複製代碼
3)打開在app工程的build.gradle,經過擴展key值命名閉包的方式,就能夠配置指定參數了。
apply plugin: 'com.lqr.gradle.study'
releaseInfo {
versionCode = '1.0.0'
versionName = '100'
versionInfo = '第一個app信息'
fileName = 'release.xml'
}
複製代碼
4)接收參數,如:
def versionCodeMsg = project.extensions.releaseInfo.versionCode
複製代碼
自定義插件無非就是封裝一些經常使用Task,因此,擴展Task纔是自定義插件的最重要的一部分。
擴展Task也很簡單,繼承DefaultTask,編寫TaskAction註解方法,下面以 「把app版本信息寫入到xml文件中」的task 爲例,註釋很詳細,很少贅述:
import groovy.xml.MarkupBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class ReleaseInfoTask extends DefaultTask {
ReleaseInfoTask() {
group 'lqr' // 指定分組
description 'update the release info' // 添加說明信息
}
/** * 使用TaskAction註解,可讓方法在gradle的執行階段去執行。 * doFirst其實就是在外部爲@TaskAction的最前面添加執行邏輯。 * 而doLast則是在外部爲@TaskAction的最後面添加執行邏輯。 */
@TaskAction
void doAction() {
updateInfo()
}
private void updateInfo() {
// 獲取gradle腳本中配置的參數
def versionCodeMsg = project.extensions.releaseInfo.versionCode
def versionNameMsg = project.extensions.releaseInfo.versionName
def versionInfoMsg = project.extensions.releaseInfo.versionInfo
def fileName = project.extensions.releaseInfo.fileName
// 建立xml文件
def file = project.file(fileName)
if (file != null && !file.exists()) {
file.createNewFile()
}
// 建立寫入xml數據所須要的類。
def sw = new StringWriter();
def xmlBuilder = new MarkupBuilder(sw)
// 若xml文件中沒有內容,就多建立一個realease節點,並寫入xml數據
if (file.text != null && file.text.size() <= 0) {
xmlBuilder.releases {
release {
versionCode(versionCodeMsg)
versionName(versionNameMsg)
versionInfo(versionInfoMsg)
}
}
file.withWriter { writer ->
writer.append(sw.toString())
}
} else { // 若xml文件中已經有內容,則在原來的內容上追加。
xmlBuilder.release {
versionCode(versionCodeMsg)
versionName(versionNameMsg)
versionInfo(versionInfoMsg)
}
def lines = file.readLines()
def lengths = lines.size() - 1
file.withWriter { writer ->
lines.eachWithIndex { String line, int index ->
if (index != lengths) {
writer.append(line + '\r\n')
} else if (index == lengths) {
writer.append(sw.toString() + '\r\n')
writer.append(line + '\r\n')
}
}
}
}
}
}
複製代碼
與建立擴展屬性同樣,擴展Task也須要在project中建立注入。
/** * 自定義Gradle插件 */
class GradleStudyPlugin implements Plugin<Project> {
/** * 插件引入時要執行的方法 * @param project 引入當前插件的project */
@Override
void apply(Project project) {
// 建立擴展屬性
// 這樣就能夠在gradle腳本中,經過releaseInfo閉包來完成ReleaseInfoExtension的初始化。
project.extensions.create("releaseInfo", ReleaseInfoExtension)
// 建立Task
project.tasks.create("updateReleaseInfo", ReleaseInfoTask)
}
}
複製代碼
再次Async工程以後,就能夠在Idea的gradle標籤裏看到自定義好的Task了。
以上就是自定義gradle插件的核心內容了,可是,這種在工程下直接建立buildSrc目錄編寫的插件,只能對當前工程可見,因此,若是須要將咱們自定義好的grdle插件被其餘工程所使用,則須要單首創建一個庫工程,並建立如buildSrc目錄下全部的文件,最後上傳maven倉庫便可,這部分可自行百度瞭解。
Manipulation tasks(操做task) | Gradle Android插件用戶指南翻譯
自定義Apk輸出位置:
this.afterEvaluate {
this.android.applicationVariants.all { variant ->
def output = variant.outpus.first() // 獲取變體輸出文件(outputs返回是一個集合,但只有一個元素,即輸出apk的file)
def apkName = "app-${variant.baseName}-${variant.versionName}.apk"
output.outputFile = new File(output.outputFile.parent, apkName)
}
}
複製代碼
variant.baseName : baidu-release variant.name : baiduRelease