Gradle其它模組
一、Settings類
settings.gradle(對應Settings.java)決定哪些工程需要被gradle處理,佔用了整個gradle生命週期的三分之一,即Initialzation初始化階段。
二、SourceSet類
對預設的檔案位置進行修改,從而讓gradle知道哪種資源要從哪些資料夾中去查詢。
// 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
一、Gradle外掛(Plugin)是什麼
Gradle中的Plugin是對完成指定功能的Task封裝的體現,只要工程依賴了某個Plugin,就能執行該Plugin中所有的功能,如:使用java外掛,就可以打出jar包,使用Android外掛,就可以生成apk、aar。
二、自定義Plugin
1、建立外掛工程
- 在工程目錄下建立buildSrc資料夾。
- 在buildSrc目錄下,建立src資料夾、build.gradle檔案。
- 在buildSrc/src目錄下,再建立main資料夾。
- 在buildSrc/src/main目錄下,再分別建立groovy、resources資料夾。
- 在buildSrc/src/main/resources再建立一個META-INF資料夾,再在META-INF下建立一個gradle-plugins資料夾。
- 在build.gradel檔案中輸入如下指令碼:
apply plugin: 'groovy'
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'
}
resources {
srcDir 'src/main/resources'
}
}
}
複製程式碼
最後,Async一下工程,buildSrc就會被識別出來了,整體目錄如圖:
2、建立外掛類
與java一樣,在groovy目錄下,建立一個包,再建立一個外掛類(如:com.lqr.gradle.study.GradleStudyPlugin),該外掛類必須實現Plugin介面。
注意: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
}
}
複製程式碼
3、指定外掛入口
在編寫完外掛類的邏輯之後,需要在META-INF.gradle-plugins目錄下建立一個properties檔案(建議以外掛類包名來命名,如:com.lqr.gradle.study.properties),在該properties中宣告外掛類,以此來指定外掛入口。
該properties檔案的名字將作為當前gradle外掛被app工程引用的依據。
implementation-class=com.lqr.gradle.study.GradleStudyPlugin
// 如果報錯 Could not find implementation class 'xxx' 的話,一般是類全路徑有問題,預設包不需要寫包路徑,修改如下即可:
// implementation-class=GradleStudyPlugin
複製程式碼
4、使用自定義外掛
開啟app工程的build.gradle,應用上面的自定義gradle外掛,並Async。
apply plugin: 'com.android.application'
apply plugin: 'com.lqr.gradle.study'
android {
...
}
複製程式碼
可以看到,在gradle的配置階段,就輸出了前面自定義外掛的apply方法中的日誌。
5、建立擴充套件屬性
外掛往往會在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
複製程式碼
6、建立擴充套件Task
自定義外掛無非就是封裝一些常用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倉庫即可,這部分可自行百度瞭解。
三、android外掛對gradle擴充套件
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