Android Gradle 插件基礎

本章跟大家一起探討下 Gradle 基礎知識:Project、Task和插件,由於是作爲插樁的鋪墊,所以我們重點放在 Gradle 插件 上,其他基礎知識自行查閱。

Project(項目)

以咱們熟悉的 Android 項目舉例說明:

通過 Android Studio 創建項目會自動生成兩個模塊,一個就是以項目名來命名的根模塊(ASMInjectDemo),另外一個就是 app 模塊。這兩個模塊都有 build.gradle 文件,我們知道每個 build.gradle 文件都代表一個 Project,所以按照這個說法就是兩個 Project。其中, ASMInjectDemo 稱之爲 rootProject,項目 app 稱爲 subProject。

每一個 Project 會包含了一個或多個 Task。而 Task 一般被定義在 build.gradle 中,它表示一個操作,比如:複製文件、打個 jar 包、上傳文件等等。

Task(任務)

什麼是 Task?

Task(任務)表示 Gradle 構建過程中的單個原子操作,例如 rootProject 的 clean Task。每個任務都屬於某個 Project,在 Project 中我們可以通過任務名或者 TaskContainer 來訪問任務。

Gradle 構建生命週期

執行一個 Gradle 構建最簡單的形式是執行一個 Task,而這些 Task 可能會依賴其他的Task。 Gradle 爲了管理這些 Task 會在任何一個 Task 執行前構建一個 DAG 圖(Directed Acyclic Graph,有向無環圖)。這也就意味着所有的 Task 都會是一個接一個的執行且只執行一次。那些沒有依賴的 Task 通常會優先執行。

Gradle 構建的生命週期分爲三個階段:

Gradle 插件

Gradle 本身提供基本的核心框架,其他的場景邏輯都可以通過插件擴展的方式來實現。對於 Android 開發來說,常用的插件就是 Android Gradle 插件和 Java 插件了。

插件的作用: Gradle 插件通常用來封裝一些可重用的編譯邏輯,可以用來擴展項目的功能,幫助項目構建中處理一些特殊的邏輯。

接下來,咱們主要討論 Gradle 插件的基本知識和如何編寫自定義的插件。

腳本插件

所謂腳本插件就是我們自定義的以 .gradle 爲後綴的腳本文件,嚴格意義上說它只是一個可執行的腳本。應用它就是把整個腳本加載到 build.gradle 腳本中。這種場景非常簡單不再贅述。

自定義插件

自定義插件的關鍵點在於要實現 org.gradle.api.Plugin 接口,重寫其 apply 方法來實現自己的業務邏輯。

接下來看一個示例:

在 app 的 build.gradle 中添加下面代碼:

/**
 * 定義一個Extension類用來接收腳本傳的參數
 */
class CustomExtensionA {
    String extensionArgs = ""
}
/**
 * 自定義插件示例
 */
class CustomPluginA implements Plugin<Project> {

    @Override
    void apply(Project target) {
        //將Extension註冊給Plugin
        def extension = target.extensions.create('customA', CustomExtensionA)
        //定義一個任務
        target.task('CustomPluginTaskA') {
            doLast {
                println "接收外部參數:${extension.extensionArgs}"
            }
        }

    }
}

其中爲了從外部傳給插件某些參數,我們可以定義一個類,並使用 Project.extensions.create 進行註冊,這樣外部就可以通過 customA 傳入參數。
爲了驗證插件生效,我們創建一個自定義的 Task(CustomPluginTaskA)。

在 app 的 build.gradle 中應用插件:

//應用插件
apply plugin: CustomPluginA
//傳入參數
customA.extensionArgs = "我是外部傳入的參數"

同步代碼之後會在 Gradle 的工具欄中出現 CustomPluginTaskA 任務,我們執行它試試:

終端輸出如我們所料:

buildSrc 模塊

我們可以在工程新建一個名爲 buildSrc 的模塊來開發自定義插件,編寫過程與寫 Android Library 類似。buildSrc 模塊中的代碼會自動被 Gradle 加載。

該模塊的結構非常簡單,只需要 src/main/groovy 目錄來存放源碼:

注意:只能使用 buildSrc 命名該模塊

另外需要在 build.gradle 文件中添加 gradleApi 和 groovy 插件依賴。

apply plugin: 'groovy'

dependencies {
    //gradle sdk
    implementation gradleApi()
    //groovy sdk
    implementation localGroovy()
}

創建兩個Groovy 文件 CustomPluginB.groovy 和CustomExtensionB.groovy。

跟上面自定義插件寫法一樣,只不過將代碼寫在了 groovy 文件中。

/**
 * 自定義插件
 */
class CustomPluginB implements Plugin<Project> {

    @Override
    void apply(Project project) {
        println "CustomPluginB Hello"
        //將Extension註冊給Plugin
        def extension = project.extensions.create("customB", CustomExtensionB)
        //定義一個任務
        project.task('CustomPluginTaskB') {
            doLast {
                println "接收外部參數:${extension.extensionArgs}"
            }
        }
    }
}

在 app 的 build.gradle 中依賴插件

import com.lulu.customplugin.CustomPluginB
apply plugin: CustomPluginB
customB.extensionArgs = "customB 外部傳入參數"

同樣在 Gradle 工具欄中執行 CustomPluginTaskB
結果正常輸出:

獨立項目的自定義插件

上面的自定義插件雖然獨立了模塊,但是在不同項目中是不可複用的。

對於可重用的插件,一般會獨立項目併發布成一個 jar,在不同的項目中引用。

跟 buildSrc 模塊類似,我們創建任意名稱的模塊,特殊的是多了一個 resources 目錄。

CustomExtensionC 和 CustomPluginC 的內容與上面提到的代碼類似,不再貼出。

着重看下這個 properties 文件中的內容,其實只有一句話,它指向了咱們編寫的插件類。

implementation-class = com.lulu.customplugin.CustomPluginC

而文件名錶示的就是 插件 ID(Plugin ID)。

爲了可以將其發佈爲 jar 包,需要在其 build.grdle 文件中做以下修改,添加 uploadArchives Task 發佈到根目錄下的 repo 文件夾:

apply plugin: 'groovy'
apply plugin: 'maven'
apply plugin: 'java'
apply plugin : 'maven-publish'

repositories {
    mavenCentral()
}
dependencies {
    //gradle sdk
    implementation gradleApi()
    //groovy sdk
    implementation localGroovy()
    //添加 gradle
    implementation 'com.android.tools.build:gradle:3.6.1'
}

group = 'com.lulu.customplugin'
version = "1.0.0"

//打包上傳到本地
uploadArchives {
    repositories {
        flatDir {
            dirs '../repo/'
        }
    }
}

代碼同步後,在 Gradle 工具欄中執行 uploadArchives,發佈 jar 包,此時在根目錄下將會生成 repo 文件夾:


一切準備好後,就可以在根目錄下的 build.gradle 中添加倉庫依賴地址:

allprojects {
    repositories {
        google()
        jcenter()
        flatDir {
            dirs './repo/'
        }
    }
}

之後添加插件依賴:

dependencies {
    //引入自定義插件
    classpath "com.lulu.customplugin:asmplugin:1.0.0"
}

在 app 模塊中的 build.gradle 應用插件並傳入額外參數,其中 plugin id 即爲上面 properties 的文件名:

apply plugin: 'custom-plugin-demo'
customC.extensionArgs = "customC 外部傳入參數"

同步代碼,執行 Task,結果輸出正常:

Demo 工程

Android 工程:https://github.com/changer0/ASMInjectDemo

以上就是本節內容,歡迎大家關注👇👇👇

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章