日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Android?Gradle?插件自定義Plugin實現注意事項_Android

作者:??自動化BUG制造器???? ? 更新時間: 2022-08-07 編程語言

Android Gradle Plugin

在 Android 項目中的 build.gradle 文件中,經常可以看見一些 plugin 聲明:

plugins {
    id 'com.android.application'
	  id 'com.android.library'
}
// or
apply plugin: 'com.android.application'
apply plugin: 'com.android.library'

上面是兩種引用 gradle 插件的常用代碼,com.android.application?是用來構建 apk 的 gradle 插件;com.android.library?是用來構建 Android Library 的 gradle 插件。

Gradle 是什么?

Gradle 是自動化構建工具,多項目構建而設計的。通過 groovy 或 kotlin 來編寫構建腳本。主要用來處理:

  • 自動處理包依賴關系
  • 自動處理部署問題

過去 Java 開發者常用 Maven 和 Ant 等工具進行封裝布署的自動化,或是兩者兼用,不過這兩個包彼此有優缺點:

  • 如果頻繁改變相依包版本,使用 Ant 相當麻煩,
  • 如果瑣碎工作很多,Maven 功能不足
  • 而且兩者都使用 XML 描述,相當不利于設計 if、switch 等判斷式,即使寫了可讀性也不佳

而 Gradle 改良了過去 Maven、Ant 帶給開發者的問題,至今也成為 Android Studio 內置的封裝布署工具。

官方文檔:What is Gradle?

Gradle 插件

Gradle 的核心是提供自動化處理流程。所有有用的特性,比如編譯 Java 代碼的能力,都是由插件添加的。

插件實際的作用有:

  • 拓展 Gradle Model (例如:添加可配置的新 DSL 元素)
  • 根據約定配置項目(例如:添加新的 Gradle Task 或配置一些合理的默認值)
  • 應用指定的配置(例如:添加一些倉庫或執行標準)

好處:

通過應用插件,而不是向項目構建腳本添加邏輯,可以獲得的好處有:

  • 提高復用能力,減少跨多個項目維護類似邏輯的開銷:同一個插件可以應用到不同的項目。
  • 更好的模塊化:通過插件的形式,可以使項目架構更加明確更容易理解。
  • 封裝重要的邏輯,允許構建腳本盡可能具有聲明性。

分類

Gradle 插件有兩種類型,分為二進制插件和腳本插件。

二進制插件:

  • 二進制插件可以通過實現?org.gradle.api.Plugin?接口以編程方式編寫,也可以使用 Gradle 的一種 DSL 語言以聲明方式編寫。
  • 二進制插件可以駐留在構建腳本中、項目層次結構中或外部插件 jar 包中。

腳本插件:

  • 腳本插件是額外的構建腳本,可以進一步配置構建并且通常實現一種聲明性的方法來操作構建。它們通常在構建中使用,盡管它們也可以外部化并從遠程位置訪問。
  • 插件通常以腳本插件開始(因為它們易于編寫),然后隨著代碼變得更有價值,它被遷移到可以在多個項目或組織之間輕松測試和共享的二進制插件。

使用插件

要使用插件中封裝的構建邏輯,Gradle 需要執行兩個步驟。 首先,解析插件,然后需要將插件應用到一個目標上,通常是一個?org.gradle.api.Project?對象。

  • 解析插件:解析插件的工作是找到包含給定插件的正確版本的 jar 并將其添加到腳本類路徑中。一旦一個插件被解析,它的 API 就可以在構建腳本中使用。
  • 應用插件:應用插件意味著在要使用插件的項目上實際執行插件的Plugin.apply(T?。應用插件是冪等的。也就是說,您可以安全地多次應用任何插件而不會產生副作用。

本篇文章主要介紹如何實現一個二進制插件。

實現一個插件

最簡單的構建 Gradle 插件的方式是 通過命令來構建:

gradle init // or ./gradlew init

執行命令:

  • 第一步,選擇項目類型,4 是 Gradle 插件項目。
  • 第二步,選擇實現芋圓,這里主要是 插件的代碼語言,支持 Groovy、Java 和 Kotlin。
  • 第三步,選擇 DSL 語言(構建腳本語言),支持 Groovy 和 Kotlin。
  • 第四步,輸入項目名稱和插件包名。

最后會顯示構建結果。 構建完的項目結構是這樣的:

這里有很多不需要的文件目錄,包括用來測試和 Gradle 的一些相關內容,都可以刪除(當然你也可以不處理),因為當我們把這個項目引入到一個 Android 項目中時,Android 項目提供了 Gradle 相關文件。

如圖所示,ExamplePlugin 目錄下 gradle 相關的文件,在 Android 的根目錄中都存在。 其中構建插件相關的內容都在 build.gradle 文件中,首先是,插件項目引用的插件:

plugins {
    id 'java-gradle-plugin' 
    id 'maven' // maven 倉庫
    id 'groovy'	// groovy 支持
}

需要重點注意的是,使用一些第三方依賴如果下載不到,要檢查引用的遠程倉庫是否在包含想要引用的依賴:

repositories {
    // Use JCenter for resolving dependencies.
    jcenter()
}

當我想引用?com.android.tools.build:gradle?依賴時,一直報錯,原因是 jcenter 中不存在這個項目,需要添加?google()

然后是一些依賴:

dependencies {
    // ...
    testImplementation 'org.spockframework:spock-core:1.3-groovy-2.5'
}

接下來是比較重要的插件定義:

gradlePlugin {
    // Define the plugin
    plugins {
        customName {
            id = 'com.example.plugin.customname'
            implementationClass = 'com.example.plugin.ComExamplePluginPlugin'
        }
    }
}

這里需要注意的是 customName 是你可以隨意定義的字符串,這個字符串會在 Plugin.apply 方法中使用到。 Id 就是插件唯一標識,后續在其他項目中引用的時候,也是引用這個 id 。 implementationClass 的值指向一個實際的代碼類,這個類實現了?org.gradle.api.Plugin?。 自動生成的 Plugin 實現類是這樣的:

class ComExamplePluginPlugin implements Plugin<Project> {
    void apply(Project project) {
        // Register a task
        project.tasks.register("customName") {
            doLast {
                println("Hello from plugin 'com.example.plugin.customname'")
            }
        }
    }
}

在這個 apply 方法中,使用之前我們定義的 customName 注冊了一個 Task 。 實際上 Gradle 后續就是執行這個 Task ,來執行代碼塊中的代碼的。

在很多之前的 Gradle 插件實現方案中,需要創建?resources/META-INF/gradle-plugin/xxx.properties?,而通過上面的方式,不需要在去創建這個文件了。 這樣一個插件的定義基本上就完成了。

發布插件

我們已經定義好了一個 Gradle 插件,那么應該如何校驗這個插件是否真的能夠使用呢?為了解決這個問題,我們要把 Gradle 插件發布到遠程倉庫或者本地目錄,然后供其他項目引用,以此來測試插件。 以本地發布為例,在插件項目的根目錄下的?build.gradle?文件中添加:

plugins {
	  // ...
    id 'maven-publish' // 用來發布插件
}
publishing {
    repositories {
        maven {
            // $rootDir 表示你項目的根目錄
			  // 這里配置發布到的本地目錄
            url = "$rootDir/repo" 
        }
    }
    publications {
        publish(MavenPublication) {
            // 插件的組ID,建議設置為插件的包名
            groupId = 'com.example.plugin.customname'
            // 插件的名字,后續在引用時會用到
            artifactId = 'customName'
            version = '0.0.1'
            // 組件類型
            from components.java
        }
    }
}

如果發布到本地,運行 Gradle 命令:

./gradlew publishPublishPublicationToMavenLocal

則會發布到本地目錄?/Users/XXX/.m2/repository/?中。

./gradlew publishPublishPublicationToMavenRepository

會發布到你在?build.gradle?中,指定的目錄?"$rootDir/repo"?中。

引用插件

在 Android 項目中引用的第一步是在根目錄的?build.gradle中添加 maven 倉庫,這樣 Gradle 才能從特定的本地目錄中找到我們的 jar 包:

repositories {
    jcenter()
    google()
    maven {
        url = "$rootDir/repo"
    }
}

第二步,在根目錄的?build.gradle?中添加依賴:

dependencies {
    classpath "com.example.plugin.customname:customName:0.0.1"
}

這個就是我們在發布插件時,指定的 groupId 、artifactId 和 version,規則是:

classpath "$groupId:$artifactId:$version"

然后,在需要引用的 module 下的?build.gradle?文件中應用插件:

plugins {
    id 'com.example.plugin.customname'
}

這里的 id 是我們在定義插件時在 gradlePlugin 代碼塊中指定的。 這樣我們就成功的通過 jar 包的形式引用到了插件。 這里以我另一個項目為例,我在 gradlePlugin 中指定的代碼塊自定義名稱為 transfrom :

gradlePlugin {
    plugins {
        transform {
			 // ...
        }
    }
}

引用成功后會在 Gradle Task 中多一個同名的任務:

對應的 Groovy 中實現 apply 方法:

@Override
void apply(Project project) {
    project.tasks.register("transform") {
        doLast {
            println("Hello from plugin 'com.chunyu.transform.plugin'")
        }
    }
}

執行該任務,會看到 log 面板中有對應的輸出:

> Task :app:transform
Hello from plugin 'com.chunyu.transform.plugin'

成功的驗證了,在 apply 中 print 代碼正確的執行了。

原文鏈接:https://juejin.cn/post/7084952244051214373

欄目分類
最近更新