天天看點

開發效率優化之自動化建構系統Gradle(二)下篇Gradle 插件簡介最後

11/10号文檔資料已全面更新!;《【阿裡P7】移動網際網路架構師進階教程+BAT面試題》,可點選下方連結直接打開: 【阿裡P7】移動網際網路架構師進階進階教程+BAT面試題 本篇文章将繼續從自定義 Gradle 插件開發來介紹自動化建構系統Gradle:

Gradle 插件簡介

Gradle 插件是一個能夠将 Gradle 的建構邏輯(build logic)和建構任務(build task)打包到一起,以便在多個項目的建構腳本(build.gradle)中應用(apply)的工具。

例如,

build.gradle

建構腳本檔案内

apply plugin: 'java'

apply plugin: 'com.android.application'

中的 java、com.android.application 就是官方提供的 Gradle 插件,通過應用這些插件,可以豐富項目的建構任務與建構邏輯。

除官方提供的插件外,Gradle 還允許開發者定義自己的 Gradle 插件。開發者可以根據實際需求定義自己的建構邏輯和建構任務,将其打包為 Gradle 插件,進而在多個項目的建構腳本中複用。此外,還可以将自定義的 Gradle 插件釋出到 plugin portal或其他倉庫中,更為友善的分享給他人使用。

Gradle 插件對程式設計語言沒有太多限制,隻要是能夠被編譯為 JVM 位元組碼的程式設計語言,都能用來編寫 Gradle 插件。Gradle-API 的被設計為對 Groovy、Java、Koltin 友好的,通常情況下,使用 Java 或 Kotlin 這類靜态類型語言實作的 Gradle 插件的性能要比使用 Groovy 實作的相同常見的性能更好。

[]( http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/# 開始之前 "開始之前")開始之前

Gradle 作為一個普通的建構工具,本身并不依賴任何可視化 GUI 工具。為簡化步驟,本文将采用指令行方式來完成自定義 Gradle 插件的示範。在開始之前,需先将 gradle 指令添加到系統環境變量中。

若讀者在 IDEA / Android Studio 使用過 gradle ,則可在目前使用者目錄下找到 gradle 指令,具體路徑如下

  • Mac:

    /Users/目前使用者名/.gradle/wrapper/dists/gradle版本/沙盒路徑/gradle版本/bin

  • Win:

    C:\Users\目前使用者名\.gradle\wrapper\dists\gradle版本\沙盒路徑\gradle版本\bin

若讀者的電腦中尚未安裝 gradle,則可在 Gradle 官方 下載下傳安裝。

以筆者使用的環境為例,gradle 指令所在目錄為

~/.gradle/wrapper/dists/gradle-5.4.1-all/3221gyojl5jsh0helicew7rwx/gradle-5.4.1/bin           

将 gradle 指令所在目錄添加到環境變量中

  • Mac:在

    ~/.bashrc

    中添加
export PATH=~/.gradle/wrapper/dists/gradle-5.4.1-all/3221gyojl5jsh0helicew7rwx/gradle-5.4.1/bin:$PATH           
  • Win:在系統環境變量中添加
C:\Users\使用者名\.gradle\wrapper\dists\gradle-5.4.1-all\805usxkvhgx6e1wbo8o64g0tx\gradle-5.6.1\bin           

牛刀小試 "牛刀小試")牛刀小試

在指令行中輸入

gradle --version           

得到如下輸出則表示 gradle 環境設定成功

------------------------------------------------------------
Gradle 5.4.1
------------------------------------------------------------

Build time:   2019-04-26 08:14:42 UTC
Revision:     261d171646b36a6a28d5a19a69676cd098a4c19d

Kotlin:       1.3.21
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM:          1.8.0_171 (Oracle Corporation 25.171-b11)
OS:           Mac OS X 10.14.6 x86_64           

自定義-Gradle-插件 "自定義 Gradle 插件")自定義 Gradle 插件

自定義 gradle 插件可以在以下三個地方建立,分别是:

  1. 建構腳本内
  2. buildSrc 子產品内
  3. 單獨項目

建構腳本内建方式 "建構腳本内建方式")建構腳本内建方式

build.gradle

内直接建立 Gradle 插件

優點:

  • build.gradle

    中建立的插件将被自動編譯并包含在 classpath 中,使用時無需在建構腳本内指定 classpath

缺點:

  • 此插件僅在目前建構腳本中有效,對外部檔案不可見,無法在目前建構腳本以外的其他地方複用此插件

示例

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#1- 建立-BuildInDemo-目錄 "1.建立 BuildInDemo 目錄")1. 建立

BuildInDemo

目錄

mkdir BuildInDemo           

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#2- 在BuildInDemo目錄内中建立-build-gradle-檔案 "2.在BuildInDemo目錄内中建立 build.gradle 檔案")2. 在

BuildInDemo

目錄内中建立

build.gradle

檔案

cd BuildInDemo
touch build.gradle           

使用

tree

指令檢視建立後的目錄結構,如下所示

BuildInDemo
.
└── build.gradle

0 directories, 1 file           

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#3- 在-BuildInDemo-build-gradle-内建立并應用-Gradle-插件,代碼如下 "3.在 BuildInDemo/build.gradle 内建立并應用 Gradle 插件,代碼如下")3. 在

BuildInDemo/build.gradle

内建立并應用 Gradle 插件,代碼如下

// 1. 建立插件 BuildInPlugin
class BuildInPlugin implements Plugin<Project> {
    // 2. 應用插件時執行此函數
    @Override void apply(Project target) {
        println("hello form build-in plugin")
    }
}
//3. 應用插件
apply plugin: BuildInPlugin
 // 2\. 應用插件時執行此函數
 @Override void apply(Project target) {
 println("hello form build-in plugin")
 }
}
//3\. 應用插件
apply plugin: BuildInPlugin           

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#4- 建構此-build-gradle-檔案 "4.建構此 build.gradle 檔案")4. 建構此

build.gradle

gradle build           

Gradle 建構時将執行

build.gradle

中的代碼,當執行到

apply plugin: BuildInPlugin

時,将會調用 BuildInPlugin 的執行個體方法

apply(Project p)

。是以在建構過程中,可以看到如下輸出,其中第 2 行即為上一步自定義插件中列印的内容,表明插件應用成功

> Configure project :
hello form build-in plugin

> Task :buildEnvironment

------------------------------------------------------------
Root project
------------------------------------------------------------

classpath
No dependencies

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed           

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#buildSrc- 子產品方式 "buildSrc 子產品方式")buildSrc 子產品方式

rootProject/buildSrc 檔案夾是 Gradle 的預留目錄,用來存放目前項目私有 Gradle 插件的源代碼與建構腳本

  • 項目建構時,Gradle 會自動編譯項目目錄下的 buildSrc 檔案夾下的建構腳本和源碼,并将其添加到項目建構腳本的 classpath 中,是以在使用 buildSrc 中建立的插件時,無需再手動指定 classpath
  • buildSrc 檔案夾中建構腳本和 Gradle 插件同一項目均可見,是以同一項目中的其他子產品也可以使用 buildSrc 中建立的插件
  • 此處建立的插件對外部項目不可見,無法在其他項目中複用

建立-PluginBuildSrcDemo-項目子產品 "1. 建立 PluginBuildSrcDemo 項目子產品")1. 建立

PluginBuildSrcDemo

項目子產品

建立

PluginBuildSrcDemo

目錄,并在該目錄下建立

build.gradle

mkdir PluginBuildSrcDemo && cd PluginBuildSrcDemo && touch build.gradle           

建立-buildSrc-子子產品 "2. 建立 buildSrc 子子產品")2. 建立

buildSrc

子子產品

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#2-1- 在-PluginBuildSrcDemo-目錄下建立buildSrc目錄 "2.1 在 PluginBuildSrcDemo 目錄下建立buildSrc目錄")2.1 在

PluginBuildSrcDemo

目錄下建立

buildSrc

mkdir buildSrc           
http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#2-2- 在-PluginBuildSrcDemo-buildSrc-目錄下建立-buildSrc-子子產品的建構腳本檔案-build-gradle "2.2 在 PluginBuildSrcDemo/buildSrc 目錄下建立 buildSrc 子子產品的建構腳本檔案 build.gradle")2.2 在

PluginBuildSrcDemo/buildSrc

目錄下建立 buildSrc 子子產品的建構腳本檔案

build.gradle

cd buildSrc
touch build.gradle           

PluginBuildSrcDemo/buildSrc/build.gradle

的内容如下

// 使用 plugins 塊文法應用插件
plugins {
  // 應用 kotlin 插件
  id 'org.jetbrains.kotlin.jvm' version '1.3.50'
}
dependencies {
  // 僅在編譯時使用 Grdale-API 依賴
  compileOnly gradleApi()
  // 在插件源碼中添加 kotlin 标準庫依賴
  implementation 'org.jetbrains.kotlin:kotlin-stdlib'
}           
http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#2-3- 建立-buildSrc-子產品的源碼目錄 "2.3 建立 buildSrc 子產品的源碼目錄")2.3 建立 buildSrc 子產品的源碼目錄
cd PluginBuildSrcDemo/buildSrc
mkdir -p /src/main/kotlin/com/example/plugin           
http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#2-4- 建立插件檔案PluginBuildSrc-kt "2.4 建立插件檔案PluginBuildSrc.kt")2.4 建立插件檔案

PluginBuildSrc.kt

cd PluginBuildSrcDemo/buildSrc/src/main/kotlin/com/example/plugin
touch PluginBuildSrc.kt           

PluginBuildSrc.kt

的代碼如下

package com.example.plugin

import org.gradle.api.Plugin
import org.gradle.api.Project

class PluginBuildSrc : Plugin<Project> {
  override fun apply(target: Project) {
    println("hello from buildSrc plugin")
  }
}           
http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#2-5- 聲明-Gradle-插件的-ID-與實作類 "2.5 聲明 Gradle 插件的 ID 與實作類")2.5 聲明 Gradle 插件的 ID 與實作類
此步驟是可選的:若使用插件 ID 形式應用自定義插件,則必須進行此步驟;若使用插件實作類的形式應用自定義插件,則可跳過此步驟。

完成此步驟的方式有兩種,任選其一即可

方式1-META-INF-方式 "方式1. META-INF 方式")方式 1. META-INF 方式

PluginBuildSrcDemo/buildSrc/src/main/resources/META-INF/gradle-plugins

cd PluginBuildSrcDemo/buildSrc
mkdir -p src/main/resources/META-INF/gradle-plugins           

gradle-plugins

目錄下建立 com.example.plugin.properties 屬性檔案,紅色部分表示插件的 ID

cd src/main/resources/META-INF/gradle-plugins
touch com.example.plugin.properties           

屬性檔案的内容如下,表示插件 ID 為 com.example.plugin 的插件所對應的實作類為

com.example.plugin.PluginBuildSrc

implementations-class=com.example.plugin.PluginBuildSrc           

方式2-java-gradle-plugin-插件方式 "方式2. java-gradle-plugin 插件方式")方式 2. java-gradle-plugin 插件方式

java-gradle-plugin 是一個用于開發 Gradle 插件的輔助插件,它内置了很多輔助功能:

  1. 為宿主子產品添加

    gradlePlugin

    配置塊,可在此處配置插件的 ID 和實作類
  2. complile gradleApi()

    依賴
  3. etc…

此處我們主要使用

gradlePlugin

配置塊代替

META-INF

目錄下的屬性檔案。

java-gradle-plugin

的使用方式非常簡單,隻需在

PluginBuildSrcDemo/buildSrc/build.gradle

建構腳本檔案中簡單配置即可,如下所示。

plugins {
      id 'org.jetbrains.kotlin.jvm' version '1.3.50'
+ //1. 應用 java-gradle-plugin 插件
+     id 'java-gradle-plugin' 
  }
     
  dependencies {
-     compileOnly gradleApi() // java-gradle-plugin 插件已為宿主添加 gradleApi 依賴,此行可移除 
      implementation 'org.jetbrains.kotlin:kotlin-stdlib'
  }
+ //2. 添加 gradlePlugin 配置塊資訊
+ gradlePlugin {
+     plugins{
+         // 此處的 tag 可以為任意名稱
+         tag1{
+             id = 'com.example.plugin.buildsrc' //自定義插件的 ID
+             implementationClass  = 'com.example.plugin.PluginBuildSrc' //自定義插件的實作類
+         }
+     }
+ }           

此時在 PluginBuildSrcDemo 目錄下使用

tree

指令,可以看到目前的目錄結構如下

PluginBuildSrcDemo
.
├── build.gradle
├── buildSrc
│   ├── build.gradle
│   └── src
│       └── main
│           └── kotlin
│               └── com
│                   └── example
│                       └── plugin
│                           └── PluginBuildSrc.kt
7 directories, 3 files           

在-PruginBuildSrcDemo-項目子產品中應用-buildSrc-中聲明的-Gradle-插件 "3. 在 PruginBuildSrcDemo 項目子產品中應用 buildSrc 中聲明的 Gradle 插件")3. 在

PruginBuildSrcDemo

項目子產品中應用

buildSrc

中聲明的 Gradle 插件

PluginBuildSrcDemo/build.gradle

建構腳本檔案中添加如下代碼

//apply plugin: '插件 ID' 
apply plugin: 'com.example.plugin'
//apply plugin: 實作類
//apply plugin: com.example.plugin.PluginBuildSrc           
應用插件時,指定插件 ID 或指定插件的實作類都可以,但指定插件 ID 的形式更為簡短及靈活,在實際開發中也更為常見。

PluginBuildSrcDemo

目錄下執行

gradle build

指令進行建構,可看到如下輸出

> Configure project :
hello from buildSrc plugin

> Task :buildEnvironment
------------------------------------------------------------
Root project
------------------------------------------------------------
classpath
No dependencies

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed           

其中第 2 行是我們在 buildSrc 子產品中定義的 Gradle 插件所列印日志,表明 buildSrc 子產品 中的自定義插件在根項目中已生效。

建立-SubModule-子子產品 "4. 建立 SubModule 子子產品")4. 建立

SubModule

buildSrc 子產品中定義的插件可以在同一項目的任意子產品的建構腳本中使用,接下來便示範在 SubModule 子子產品中的應用。
http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#4-1- 建立-SubModule-目錄與建構腳本 "4.1 建立 SubModule 目錄與建構腳本")4.1 建立 SubModule 目錄與建構腳本
// 1. 在 PluginBuildSrcDemo 目錄下建立 SubModule 目錄
cd PluginBuildSrcDemo && mkdir SubModule
// 2. 在 SubModule 目錄下建立 gradle 建構腳本 
cd SubModule
touch build.gralde           

PluginBuildSrcDemo/SubModule/build.gradle

apply plugin: 'com.example.plugin'           
http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#4-2- 将-SubModule-子產品關聯到-PluginBuildSrcDemo-項目中 "4.2 将 SubModule 子產品關聯到 PluginBuildSrcDemo 項目中")4.2 将 SubModule 子產品關聯到 PluginBuildSrcDemo 項目中

PluginBuildSrcDemo

目錄下建立

settings.gradle

檔案,内容如下

// 将SubModule 子子產品添加到 PluginBuildSrcDemo 項目子產品中
include ':SubModule'           

此時在

PluginBuildSrcDemo

目錄下使用

tree

指令,可以看到項目目前的目錄結構如下

PluginBuildSrcDemo
.
├── SubModule
│   └── build.gradle
├── build.gradle
├── buildSrc
│   ├── build.gradle
│   └── src
│       └── main
│           └── kotlin
│               └── com
│                   └── example
│                       └── plugin
│                           └── PluginBuildSrc.kt
└── settings.gradle           

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#5- 在-SubModule-子產品執行建構指令 "5. 在 SubModule 子產品執行建構指令")5. 在

SubModule

子產品執行建構指令

cd PluginBuildSrcDemo/SubModule
gradle build           

得到如下輸出

> Configure project :SubModule
hello from buildSrc plugin

> Task :SubModule:buildEnvironment

------------------------------------------------------------
Project :SubModule
------------------------------------------------------------

classpath
No dependencies

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed           

獨立項目方式 "獨立項目方式")獨立項目方式

采用 buildSrc 子產品方式時,Gradle 會妥善處理 buildSrc 子產品的建構腳本與源碼,并将其添加到目前項目的 classpath 中。但 buildSrc 方式的插件隻能在項目内共享與複用,若要在其他項目中使用該插件,還需要再進行下列操作

  • 将插件釋出到 maven 倉庫(任意倉庫)
  • 在需要應用該插件的建構腳本中的 repository 部分添加該插件所在的 maven 倉庫
  • 在需要應用該插件的建構腳本中的 classpath 部分添加該插件對應的 maven 坐标 (group : id : version)

因為是在其他項目中使用該項目 buildSrc 子產品 中的自定義 Gradle 插件,是以 Gradle 的 buildSrc 保留目錄優勢不再。如果将子產品名由

buildSrc

修改為其他名稱,則可将其稱為獨立的 Gradle 插件子產品。

在本小節中,我們主要學習 gradle 插件的釋出與使用。

建立-gradle-插件項目 "1. 建立 gradle 插件項目")1. 建立 gradle 插件項目

與 buildSrc 方式相同,先建立建構腳本與自定義插件類

mkdir StandaloneDemo 
cd StandaloneDemo
touch build.gradle
mkdir src/main/kotlin/com/example/plugin
touch src/main/kotlin/com/example/plugin/StandalonePlugin.kt           

StandaloneDemo/build.gradle

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.50'
    id 'java-gradle-plugin'
}

gradlePlugin{
    plugins{
        sometag{
            id = 'com.example.plugin'
            implementationClass = 'com.example.plugin.StandalonePlugin'
        }
    }
}           

StandaloneDemo/src/main/kotlin/com/example/plugin/StandalonePlugin.kt

package com.example.plugin

import org.gradle.api.Plugin
import org.gradle.api.Project

class StandalonePlugin : Plugin<Project> {
    override fun apply(target: Project) {
        println("hello from standalone plugin")
    }
}           

将-gradle-插件釋出到-maven-倉庫 "2. 将 gradle 插件釋出到 maven 倉庫")2. 将 gradle 插件釋出到 maven 倉庫

在StandaloneDemo-build-gradle-檔案中配置釋出資訊 "2.1 在StandaloneDemo/build.gradle 檔案中配置釋出資訊")2.1 在

StandaloneDemo/build.gradle

檔案中配置釋出資訊

maven-publish

插件将自定義插件釋出到本地 maven 倉庫中,如下所示

plugins {
     id 'org.jetbrains.kotlin.jvm' version '1.3.50'
     id 'java-gradle-plugin'
+    //1. 應用 maven-publish 插件
+    id 'maven-publish'
 }
 
 gradlePlugin{
     plugins{
         sometag{
             id = 'com.example.plugin'
             implementationClass = 'com.example.plugin.StandalonePlugin'
         }
     }
 }
+//2. 設定釋出相關配置
+publishing {
+    publications {
+        //3. 将插件釋出到 maven 倉庫
+        maven(MavenPublication) {
+                        //4. 設定插件的 maven 坐标
+            groupId 'com.example'//組織 ID
+            artifactId 'plugin'  //制品 ID
+            version 'snapshot'   //制品版本
+            from components.kotlin
+        }
+    }
+     //5. 設定釋出倉庫
+   repositories {
+       // 6. 釋出到本地 maven 倉庫 
+       mavenLocal()
+   }
+}           
使用-publishMavenPublicationToMavenLocal-任務将插件釋出到本地倉庫 "2.2 使用 publishMavenPublicationToMavenLocal 任務将插件釋出到本地倉庫")2.2 使用

publishMavenPublicationToMavenLocal

任務将插件釋出到本地倉庫
cd StandaloneDemo
gradle publishMavenPublicationToMavenLocal           

執行以上指令後,gradle 會把

StandaloneDemo

中的代碼編譯打包後釋出到本地 maven 倉庫中,本地 maven 倉庫通常存放于目前使用者目錄下,具體路徑為

  • ~/.m2/repository

  • C:\Users\目前使用者名\.m2\repository

我們可以在此目錄下看到剛剛釋出的插件,如下圖所示

http://geek5nan.github.io/uploads/gradle-plugin-dev-1.png

在其他項目中使用本地-maven-倉庫中的-gradle-插件 "3. 在其他項目中使用本地 maven 倉庫中的 gradle 插件")3. 在其他項目中使用本地 maven 倉庫中的 gradle 插件

http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#3-1- 建立-OtherProject項目 "3.1 建立 OtherProject項目")3.1 建立

OtherProject

項目
mkdir OtherProject
cd OtherProject
touch build.gradle           

build.gradle

的檔案内容如下,相比 buildSrc 方式,應用時多了 11 行的 buildscript 相關的配置資訊。

+buildscript {
+  repositories {
+    //1. 為目前建構腳本添加插件所在的 maven 倉庫,本例中為 maven 本地倉庫
+    mavenLocal()
+  }
+  dependencies {
+    //2. 為目前建構腳本添加如下依賴
+    //`com.exaple`、`plugin`、`snapshot` 是在上一步中設定的 maven 三維坐标
+    classpath 'com.example:plugin:snapshot'
+  }
+}
 //3. 應用獨立插件項目中的自定義插件
 // apply plugin: '插件 ID'
 apply plugin: 'com.example.plugin'           
http://geek5nan.github.io/2019/09/07/Developing-Gradle-Plugin-1/#3-2- 建構-OtherProject-項目 "3.2 建構 OtherProject 項目")3.2 建構

OtherProject

cd OtherProject
gradle build           

輸入以上指令,得到如下輸出

> Configure project :
hello from standalone plugin

> Task :buildEnvironment

------------------------------------------------------------
Root project
------------------------------------------------------------

classpath
\--- com.example:plugin:snapshot

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed           

小結 "小結")小結

本文示範了 gradle 插件的三種建立方式,相關代碼已上傳至 github 中,點此即可檢視。行文匆忙難免疏忽,如有遺漏還請斧正。

最後

我們今年整理了一份阿裡P7級别的Android架構師全套學習資料,特别适合有3-5年以上經驗的小夥伴深入學習提升。

主要包括騰訊,以及位元組跳動,華為,小米,等一線網際網路公司主流架構技術。如果你有需要,盡管拿走好了。

以下為我整理的資料免費分享;【阿裡P7】Android進階教程+BAT面試題

1.Android進階技術腦圖

2.P7級Android進階架構視訊教程

3.Android核心進階技術PDF文檔+BAT大廠面試真題解析

4.Android思維腦圖(技能樹)

1.Android進階技術腦圖;

查漏補缺,體系化深入學習提升

2.【Android進階架構視訊教程】;

全套部分展示;

java與Android核心進階專題視訊與源碼

阿裡P7級全套進階學習視訊;

3.Android核心進階技術PDF文檔,BAT大廠面試真題解析

免費分享

為什麼免費分享?

我的目的是讓更多需要的Android開發朋友能夠提升自己的技術水準

無論是Android,還是qq,微信,360等,想在網際網路上最大程度推廣,就必須免費!

如果我的學習資料對你有幫助,點個贊,謝謝!

繼續閱讀