Gradle入門系列(五)——Gradle其它模塊與Plugin插件

Gradle其它模塊

1、Settings類

settings.gradle(對應Settings.java)決定哪些工程須要被gradle處理,佔用了整個gradle生命週期的三分之一,即Initialzation初始化階段。html

2、SourceSet類

對默認的文件位置進行修改,從而讓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

1、Gradle插件(Plugin)是什麼

Gradle中的Plugin是對完成指定功能的Task封裝的體現,只要工程依賴了某個Plugin,就能執行該Plugin中全部的功能,如:使用java插件,就能夠打出jar包,使用Android插件,就能夠生成apk、aar。android

2、自定義Plugin

一、建立插件工程

  1. 在工程目錄下建立buildSrc文件夾。
  2. 在buildSrc目錄下,建立src文件夾、build.gradle文件。
  3. 在buildSrc/src目錄下,再建立main文件夾。
  4. 在buildSrc/src/main目錄下,再分別建立groovy、resources文件夾。
  5. 在buildSrc/src/main/resources再建立一個META-INF文件夾,再在META-INF下建立一個gradle-plugins文件夾。
  6. 在build.gradel文件中輸入以下腳本:
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纔是自定義插件的最重要的一部分。

擴展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倉庫便可,這部分可自行百度瞭解。

3、android插件對gradle擴展

譯者序 | Gradle Android插件用戶指南翻譯

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

相關文章
相關標籤/搜索