Gradle For Android(7)--創建Task以及Plugin

介紹

到目前爲止,我們已經看到了很多Gradle構建的屬性,並且知道了怎麼去執行Tasks。這一章,會更多的瞭解這些屬性,並且創建我們自己的Task。一旦知道如何自定義Task之後,就可以完成更多的事情,並且自定義自己的插件,而在多工程中使用這些Task和Plugin。

之前我們看到了如何創建自定義Task,並且瞭解了一些Groovy腳本。知道Groovy也幫我們理解Gradle如何工作,並且爲什麼構建配置文件可以這樣配置。

這一章會從下面的角度來介紹:

  • Understanding Groovy
  • Getting started with tasks
  • Hooking into the Android plugin
  • Creating your own plugins

Understanding Groovy

Groovy對於Java開發者而言非常容易閱讀,但是如果沒有一個簡單的介紹的話,Groovy代碼也是一個比較難的任務。

Groovy基於Java並且在JVM中執行。它的宗旨是變得更簡單,更直接的語言,就像腳本語言一樣。而我們將Grovvy和Java對比,可以讓我們更好的瞭解Groovy如何工作的,並且更清楚的瞭解到這兩種語言的區別。

在Java中打印一個字符串如下:

System.out.println("Hello, world!");

而在Groovy中如下:

println 'Hello, world!'

我們可以立即發現一些關鍵的區別:

  • 沒有System.out的命名空間
  • 沒有參數路徑
  • 結尾沒有分號

示例中使用單引號包圍着一個String。你也可以使用單引號或者雙引號,但是他們是有區別的。雙引號的String可以包含一些差值表達式。差值表達式可以值或者函數來代替其中的佔位符。而佔位符表達式會包含多個值,並且通過$前綴來代表值。例如:

   def name = 'Andy'
   def greeting = "Hello, $name!"
   def name_size "Your name is ${name.size()} characters long."

greeting值代表着Hello,Andy字符串。並且name_size的值爲Your name is 4 characters long

字符串差值器允許我們執行動態代碼,比如說下面的代碼是打印正確的日期:

def method = 'toString'
new Date()."$method"()

這在Java中看起來很奇怪,但是在動態語言的裏面確實很平常的。

Classes and members

在Groovy中創建Class如下,包含一個成員和一個函數:

class MyGroovyClass {
       String greeting
       String getGreeting() {
           return 'Hello!'
       } 
}

注意到成員和函數都沒有類似於private ,public的訪問權限。而默認的訪問權限和Java不同,Groovy中的類都是Public的,就和Method一樣,但是成員變量卻是私有的。 如果要創建一個MyGroovyClass變量,如下:

   def instance = new MyGroovyClass()
   instance.setGreeting 'Hello, Groovy!'
   instance.getGreeting()

我們可以使用def關鍵字來創建一個新的變量。一旦創建出了一個變量,就可以操作它的成員了。Groovy自動添加了訪問權限,你也可以重寫他們。就像我們定義了getGreetingMyGroovyClass中。如果沒有指定的話,可以使用setter和getter方法來訪問成員變量。 如果你嘗試直接調用一個成員,那麼需要調用getter方法即可。也就是說,你不需要定義instance.getGreeting()函數,你可以直接調用instance.geeting即可。

println instance.getGreeting()
println instance.greeting

上面兩行代碼完成了相同的事情。

Methods

就像變量一樣,我們不需要指定具體的返回類型給Method。雖然爲了比較清晰的能夠看清楚函數的結構,我們也會定義好返回值。另外一個不同的地方就是,Groovy默認會有返回值,而不需要使用return關鍵字。

例如Java中返回一個值的平方:

public int square(int num) {
       return num * num;
} 
square(2);

你需要指定函數爲public,並且返回的類型,參數,以及返回對應類型的值。同樣的函數定義在Groovy中如下:

def square(def num) {
       num * num
}
square 4

沒有返回類型,沒有參數類型。通過使用def關鍵字來代替一個具體的類型,並且返回具體的值也沒有通過return返回。當調用這個函數的時候,也不需要括號和分號。另外一種Groovy的定義方式如下:

def square = { num ->
       num * num
}
square 8

這不是一個常規的方法,而是一個閉包。閉包的概念和Java中不一樣,但是在Groovy和Gradle中尤爲重要。

Closures

閉包是匿名的代碼塊,能夠接受參數並且返回一個值。它能夠被分配給變量,也能夠作爲參數傳遞給函數。

你可以定義一個簡單的閉包,在花括號中添加代碼塊即可。如果你希望它能夠更直接一些,那麼可以在定義中添加類型,例如:

Closure square = {
       it * it
}
square 16

通過添加Closure定義讓每個人都知道這段代碼是閉包。如果你不想在閉包中指定參數具體的類型,Groovy會自動添加一個。這個參數的名字就叫做it。如果調用者沒有指定任何參數,那麼這個參數就會是null。這可以使代碼更加簡潔,但僅當閉包只用一個參數時纔有用。

在Gradle的上下文中,我們總是使用閉包。例如,android代碼塊以及dependencies代碼塊都是閉包。

Collections

Gradle中有兩個比較重要的概念,List和Map。 在Groovy中創建List很簡單,不需要特殊的初始化:

List list = [1, 2, 3, 4, 5]

列表的迭代器也很簡單。你可以通過each方法來遍歷每個元素:

list.each() { element ->
       println element
}

each函數可以讓你訪問List中的每個元素。而我們也可以通過it變量更方便的調用:

list.each() {
       println it
}

另外一種類型就是Map。Map通常用在Gradle的設置和函數中。Map中保存着K-V的列表。我們可以通過以下方式定義Map:

Map pizzaPrices = [margherita:10, pepperoni:12]

如果要訪問Map中的某一條,則使用get方法或者單引號訪問即可:

 pizzaPrices.get('pepperoni')
 pizzaPrices['pepperoni']

Groovy也爲該功能提供了一個更簡便的方法,你可以通過.的方式來訪問某個值:

pizzaPrices.pepperoni

Groovy in Gradle

打開一個Gradle的build.gradle文件,看整個構建中的Android Plugin應用的地方:

apply plugin: 'com.android.application'

這段代碼是Groovy精簡版,如果原版的Groovy代碼應該是:

project.apply([plugin: 'com.android.application'])

重寫Groovy的精簡的方法,我們調用了Project類的``apply方法。而apply方法只有一個參數,而該參數是一個Map,裏面包含了Key爲plugin,Value爲com.android.application```。

另外一個例子,就是dependencies代碼塊,之前我們定義dependencies如下:

dependencies {
       compile 'com.google.code.gson:gson:2.3'
}

我們現在知道這個代碼塊是一個閉包,調用了Project對象的dependencies函數。這個閉包傳入的是一個DependencyHandler對象,而這個對象中存在add函數。 這個函數接受了三個參數,一個String定義了配置,一個對象定義了依賴庫,以及一個閉包可以指定依賴的屬性。全部展開如下:

project.dependencies({
       add('compile', 'com.google.code.gson:gson:2.3', {
           // Configuration statements
       })
})

如果希望瞭解更多的Groovy在Gradle中的內幕,最開始可以看看Project的官方文檔。地址爲:http://gradle.org/docs/current/javadoc/org/gradle/api/Project.html

Getting started with tasks

自定義Gradle任務可以提升我們的開發效率。Tasks可以操作已存在的構建流程,添加新的構建步驟,並且影響構建的輸出。我們可以執行一些簡單的任務,比如說可以通過Hook Gradle的Android Plugin重命名一個已經生成的APK。Tasks也允許你執行更多複雜的代碼,以至於我們可以在APK打包前生成多Density的圖片。例如,一旦你知道如何創建自定義Tasks了,你就會發現你可以改變構件流程了。

Defining tasks

Tasks屬於Project對象,並且每個Task實現了Task接口。定義一個Task最簡單的方法就是使用Tasks的名字作爲參數執行Task方法即可。例如:

task hello

這將創建出Task。但是不會做任何事情,如果我們希望添加一些事件,則可以通過以下方式:

task hello {
     println 'Hello, world!'
}

當執行這個任務的時候,就會發現:

$ gradlew hello
Hello, world!
:hello

從這個輸出,可以看出:Hello,world!在任務執行前被打印出來了。回顧一下之前說的Gradle構建流程,有三個階段:初始化階段,配置階段,執行階段。當按照上述例子添加Task時候,實際上是配置了這個Task。甚至如果你執行其他的任務,Hello,World!這條消息仍然會出現。

如果你希望在執行階段添加一些事件的話,則可以使用:

task hello << {
     println 'Hello, world!'
}

唯一不同的是在閉包前加入了<<。這告訴了Gradle代碼是在執行階段,而不是在配置階段。

爲了證明這個區別,我們可以在build.gradle中加入:

task hello << {
  println 'Execution'
}
hello {
  println 'Configuration'
}

我們定義了一個當它執行的時候會打印的Task。我們也定義了一個在Configuration階段打印的的Task。即使它在真正的Task之後定義的,也會首先執行。輸出的結果如下:

$ gradlew hello
Configuration
:hello
Execution

由於Groovy有很多簡潔定義的方式,以下爲一些示例:

task(hello) << {
     println 'Hello, world!'
}
task('hello') << {
     println 'Hello, world!'
}
tasks.create(name: 'hello') << {
     println 'Hello, world!'
}

第一個和第二個代碼塊通過兩種不同的方式實現同一個效果。你可以使用單引號,也可以使用括號。在這兩個代碼塊中,我們調用的是task()函數,它會有兩個參數,一個是Task的名字,另外一個是一個閉包。task()函數就是Gradle中Project類中的一部分。

最後一個代碼塊則不是使用task()函數。它用的是一個名爲tasks的對象,而這個對象則是TaskContainer的實例。並且,這個實例代表着每一個Project。它提供了create函數,而這個函數會通過一個Map對象和一個閉包作爲參數,並且返回一個Task對象。

Anatomy of a task

Task接口是所有Task,以及定義一系列Properties和Methods的基礎。所有的這些都被一個默認的Class實現了,它的名字叫做DefaultTask。這是標準的Task類型的實現,當創建一個新的Task的時候,它會基於DefaultTask

每個Task都包含了一系列Action對象。當Task被執行的時候,這些Action都會按照順序執行。我們可以使用doFirstdoLast函數來添加Action。這些方法都添加一個閉包作爲參數,並且把他們包裝到一個Action對象中。

你只需要通過doFirst()doLast()來在Execution階段來執行代碼。而<<符號則其實代表着在doFirst中定義了Action。舉例如下:

task hello {
     println 'Configuration'
     doLast {
       println 'Goodbye'
      }
     doFirst {
       println 'Hello'
     } 
}

當我們執行hello這個任務時,則會打印出:

$ gradlew hello
Configuration
:hello
Hello
Goodbye

即使打印Goodbye那行代碼定義在Hello之前,它也會在Task執行的時候,按照正確的位置打印出來。你也可以多次使用doFirst()doLast(),例如:

task mindTheOrder {
     doFirst {
       println 'Not really first.'
     }
     doFirst {
       println 'First!'
     }
     doLast {
       println 'Not really last.'
    }
     doLast {
       println 'Last!'
    } 
}

執行完這個任務,就會打印出:

$ gradlew mindTheOrder
:mindTheOrder
First!
Not really first.
Not really last.
Last!

注意,doFirst()函數會加在Task的Action集合最開始的地方,而doLast()添加的Action則在最後的位置。這也就意味着,我們使用這些函數的時候需要很小心,尤其注意它的順序。

如果它依賴於某個順序執行的任務的話,那麼可以使用mustRunAfter()函數。這個函數允許你影響Gradle構建的Dependency的DAG。當你使用mustRunAfter時,需要指定兩個任務,其中一個必須在另外一個之前執行:

task task1 << {
    println 'task1'
}
task task2 << {
    println 'task2'
}
task2.mustRunAfter task1

執行task1和task2將會得到task1在task2之前執行,而忽略你所指定順序。

$ gradlew task2 task1
:task1
task1
:task2
task2

mustRunAfter()函數不會在兩個Task之間添加依賴關係。它可以在Task1不執行的情況下,仍然可以執行Task2。如果你希望添加兩個Task之間的依賴關係的話,那麼需要使用dependsOn()。例如:

task task1 << {
     println 'task1'
}
task task2 << {
     println 'task2'
}
task2.dependsOn task1

而當你只執行task2,而不執行task1的時候:

$ gradlew task2
:task1
task1
:task2
task2

使用mustRunAfter()的時候,同時執行task2和task1,並且在task2優先執行的時候,他們還是會有執行的依賴關係。而dependsOn()的話,task2必須和task1掛鉤,即使沒有明確的說明。這是一個很重要的點。

Using a task to simplify the release process

在發佈App之前,你需要對APK進行簽名。而簽名前,需要創建自己的keystore,其中包含了很多private keys。當你創建完keystore後,你可以在Gradle中定義簽名的配置了。例如:

android {
    signingConfigs {
        release {
            storeFile file("release.keystore")
            storePassword "password"
            keyAlias "ReleaseKey"
            keyPassword "password"
        } 
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    } 
}

這種方式的缺點就是密碼會被銘文保存在倉庫中。如果你正在爲開源做奮鬥的話,那不要用這種方式。任何一個擁有keystore文件和password的人都可以使用你的ID發佈App。

爲了避免這種情況,你可以創建一個Task,在每次打Release包的時候詢問Release的Password。這會有一點麻煩,而且在自動持續集成構建Release包的情況下也是不可能的。一種比較好的解決方案就是,創建一個配置文件保存keystore的密碼,而這個配置文件不在倉庫中。

我們可以在根目錄下提供一個名爲private.properties的文件,並且添加:

release.password = thepassword

我們假設Keystore和key的密碼相同。如果你有兩個不同的密碼,那麼則可以創建第二個屬性。一旦設置完成,你可以定義一個新的Task,名爲getReleasePassword

task getReleasePassword << {
       def password = ''
       if (rootProject.file('private.properties').exists()) {
           Properties properties = new Properties();
           properties.load(rootProject.file('private.properties').newDataInputStream())
           password = properties.getProperty('release.password')
        } 
}

這個任務會在根目錄尋找一個名爲private.properties的文件。如果文件存在,那麼Task會加載所有的properties。並且properties.load()函數會查找Key-Value對,就像我們在properties文件中定義的release.password一樣。

爲了保證沒有private properties文件的人也可以運行這個腳本,或者處理如果文件存在,但是password屬性不存在的情況,我們可以添加一個fallback。如果password仍然爲空,那麼可以在console中詢問Password:

if (!password?.trim()) {
    password = new String(System.console().readPassword ("\nWhat's the secret password? "))
}

在Groovy中檢查字符串是否爲空是一個很簡單的操作。用?標誌的password?.trim()檢查了password是否爲null,並且使用trim()避免password爲空。

使用new String是必須的,因爲System.readPassword()會返回一個字符數組,然後通過String來轉換成字符串。一旦我們擁有了keystore的密碼,我們就可以在release構建中配置簽名:

android.signingConfigs.release.storePassword = password
android.signingConfigs.release.keyPassword = password

現在我們已經完成我們的任務,我們需要確認當執行一次Release構建的時候是否成功,接下來在build.gradle中添加這幾行:

tasks.whenTaskAdded { theTask ->
       if (theTask.name.equals("packageRelease")) {
           theTask.dependsOn "getReleasePassword"
       }
}

這段代碼Hook進了Gradle,並且在運行的時候Android Plugin會把閉包加入到Dependency Graph中。直到packageRelease執行之前,password都不是必須的,所以我們需要確保packageRelease任務依賴於我們的getReleasePassword任務。我們不能直接使用packageRelease.dependsOn()的原因是Android Plugin會基於Build Variant動態的生成打包的Tasks。這也就意味着,packageRelease任務直到Android Plugin掃描完所有的Build Variants之前,都不會存在。而發現的過程在Build之前就已經開始了。

在添加了Task的構建Hook之後,執行gradlew assembleRelease任務的結果如下:

Hook Android Plugin

就像上面截圖所示,private.properties文件不可用,所以task在console中詢問password。這種情況下,我們需要添加一些提醒,如何創建properties文件,並且添加password屬性讓未來的構建更賤簡單。一旦我們的Task選擇了keystore的密碼,Gradle就可以開始打包我們的APP並且完成構建了。

爲了讓這個Task可以正常運轉,它本質就是Hook到Gradle和Android Plugin中。

Hooking into the Android plugin

當開發Android App的時候,我們希望修改的任務大多都是與Android Plugin相關的。之前的例子,我們可以看到如何在一個自定義的Task中添加依賴。在這一屆,我們來看看如何進行Android特殊的構建Hook。

一種Hook到Android Plugin的方法是操作Build Varian。我們只需要在遍歷Variant的時候,完成我們的任務即可。

android.applicationVariants.all { variant ->
     // Do something
}

爲了得到所有的Build Variants,我們可以使用applicationVariants對象。一旦我們引用到了一個具體的Build Variant,我們就可以訪問它的屬性,並且操作它的屬性,比如說名字,描述等等。如果你希望在Android Library中加入相同的邏輯,那麼使用libraryVariants來替代applicationVariants即可。

這種Hook可以用來修改APK的名字,並且在文件名後添加版本號。這樣可以更簡單的生成一個帶版本的APK名,而不需要手動修改文件名。接下來則看看如何實現

Automatically renaming APKs

在打包完後,我們來重命名APK。我們可以遍歷App的Build Variants,並且修改outputFile屬性。如下代碼所示:

android.applicationVariants.all { variant ->
     variant.outputs.each { output ->
        def file = output.outputFile
        output.outputFile = new File(file.parent,file.name.replace(".apk", "-${variant.versionName}.apk"))
      } 
}

每個Build Variant的輸出都是一個APK文件。variant.outputs對象都會有一個屬性名爲outputFile,而它則是File類型的。一旦我們知道了output的路徑後,我們就可以操縱它了。

如上所示,我們在文件名中添加了版本號,而APK的名字也會從app-debug.apk修改爲app-debug-1.0.apk。接下來,我們來看看如何爲每一個Build Variant創建一個Task。

Dynamically creating new tasks

由於Gradle工作方式以及Tasks的構建,我們可以在Configuration階段基於Build Variant創建我們自己的Task。

爲了解釋這個強大的概念,我們會創建一個Task,但不是安裝,而是運行Android App的某一個Build Variant。Install Task只是Android Plugin中的一部分,但是如果你通過命令行的installDebug任務安裝了Apk的話,當安裝完成後,需要手動啓動App才行。而我們創建的這個Task則會把最後一步去掉。

通過Hook Application Variant中的屬性:

android.applicationVariants.all { variant ->
     if (variant.install) {
       tasks.create(name: "run${variant.name.capitalize()}",
         dependsOn: variant.install) {
           description "Installs the ${variant.description} and runs the main launcher activity."
          } 
       }
}

對於每個Variant,我們檢查它是否有install這個任務。因爲我們需要依賴install任務,所以必須要檢查這個任務是否存在。一旦我們確定了install任務存在,我們就可以創建一個新的Task,並且基於Variant的名字賦予這個Task名字。我們需要將我們新建的任務依賴variant.install。這會在我們的任務執行前打開install任務。而在tasks.create()的閉包中,我們添加了一個description,可以幫助我們在執行gradlew tasks的時候展示日誌。

在添加完description之後,我們也會添加真正的Task Action。在這個例子中,我們希望啓動APP。你可以通過Android Debug Tool(ADB)在已經連接的設備或者模擬器中啓動APP。

$ adb shell am start -n com.package.name/com.package.name.Activity

Gradle有一個函數叫做exec(),這個函數可以讓我們在命令行執行命令。爲了確保exec()可以正常工作,我們需要提供一個可執行的環境變量。我們也需要傳遞一些參數,例如:

doFirst {
       exec {
           executable = 'adb'
           args = ['shell', 'am', 'start', '-n',"${variant.applicationId}/.MainActivity"]
       }
}

爲了得到包名,我們使用Build Variant中帶有後綴的Application ID。而如果我們加了後綴,Activity的classpath仍然相同。例如:

android {
       defaultConfig {
           applicationId 'com.gradleforandroid'
       }
       buildTypes {
           debug {
               applicationIdSuffix '.debug'
           }
       }
}

包名爲com.gradleforandroid.debug,但是Activity的路徑還是com.gradleforandroid.Activity。爲了保證我們得到正確的Activity類,我們從ApplicationId中帶入後綴:

doFirst {
       def classpath = variant.applicationId
       if(variant.buildType.applicationIdSuffix) {
           classpath -= "${variant.buildType.applicationIdSuffix}"
       }
       def launchClass = "${variant.applicationId}/${classpath}.MainActivity"
       exec {
          executable = 'adb'
          args = ['shell', 'am', 'start', '-n', launchClass]
        } 
}

首先,我們創建了一個變量爲classpath,該值爲applicationId。然後我們通過buildType找到後綴。在Groovy中,我們可以通過-=運算符來從String中減去一個String。這些修改可以保證在安裝過後,使用後綴的APP也不會打開失敗。

Creating your own plugins

如果你有一系列的Gradle的Tasks希望在多個Project中重用,那我們可以考慮把這些Task添加到一個自定義的插件中去。這樣可以讓我們自己的構建邏輯與別人共享。

Plugin也可以使用Groovy編寫,Java或者Scala也都可以,只要是基於JVM的語言都可以。實際上,大部分的Android Plugin都是Java與Groovy混編的。

Creating a simple plugin

爲了從已經保存到build.gradle中的構建邏輯提取出來,我們可以在build.gradle中創建一個Plugin。這是最簡單的方法。

爲了創建一個Plugin,我們需要創建一個新的Class,實現Plugin接口。我們也將使用我們之前動態創建Tasks的代碼。我們的Plugin類如下:

class RunPlugin implements Plugin<Project> {
     void apply(Project project) {
        project.android.applicationVariants.all { variant -> if (variant.install) {
            project.tasks.create(name: "run${variant.name.capitalize()}", dependsOn: variant.install) {
               // Task definition
           }
        } 
     }}
} 

Plugin接口定義了apply()函數。Gradle會在插件使用的時候,調用這個函數。Project對象會作爲參數傳遞,並且可以在Plugin中配置該project對象,並且使用它的函數以及屬性。

在之前的例子中,我們需要首先需要訪問project對象,需要注意我們需要在build.gradle中Apply這個Plugin才行,否則會導致異常。

爲了保證這個Plugin在我們的構建配置中被Apply,需要在build.gradle中添加以下這一行:

apply plugin: RunPlugin

Distributing plugins

爲了發佈一個Plugin,我們需要把它移動到一個單獨的Module或者Project中。一個單獨的Plugin擁有它自己的build.gradle文件來配置dependencies。這個Module會產生一個Jar文件,包括包含了Plugin的classes和屬性。我們可以使用這個JAR文件將插件應用到多個模塊和項目中,並與其他模塊共享。而Gradle工程,則需要創建一個build.gradle文件進行配置:

apply plugin: 'groovy'

dependencies {
       compile gradleApi()
       compile localGroovy()
}

一旦使用Groovy寫Plugin後,我們就需要應用groovy這個插件。Groovy Plugin集成自Java Plugin,並且能讓我們構建以及打包Groovy的類。Groovy和Java都可以支持,所以我們可以混編。你甚至可以使用Groovy來繼承一個Java類。甚至你都感覺不到在使用Groovy。

爲了開始我們單獨模塊的代碼,我們首先需要保證正確的目錄結構:

plugin
   └── src
       └── main
           ├── groovy
           │    └─com
           │       └─package
           │            └── RunPlugin.groovy
           └── resources
               └── META-INF
                   └── gradle-plugins

對於任意的Gradle模塊,我們需要提供一個src/main目錄。因爲這是Groovy工程,main的子目錄使用groovy來替代java。而另外一個子目錄叫做resources,用來指定我們Plugin的屬性。我們創建了一個文件名爲:RunPlugin.groovy在``package```目錄下,而這個目錄下我們會定義我們Plugin的類:

package com.gradleforandroid

import org.gradle.api.Project
import org.gradle.api.Plugin
class RunPlugin implements Plugin<Project> {
       void apply(Project project) {
           project.android.applicationVariants.all { variant ->
               // Task code
           } 
        }
}

爲了Gradle能夠查找到這個Plugin,我們需要提供一個properties的文件。並且將該文件放到src/main/resources/META-INF/gradle-plugins/這個目錄下。這個文件的名字需要匹配Plugin的ID。例如:RunPlugin,這個文件名稱就叫做com.gradleforandroid.run.properties,該文件的內容爲:

implementation-class=com.gradleforandroid.RunPlugin

這個properties文件中唯一的東西就是包名以及Plugin具體實現的類名。當Plugin和Properties文件準備完成,我們就可以通過gradlew assemble命令來構建Plugin了。這會在構建的output目錄下創建一個Jar文件。如果你希望把這個插件發佈到Maven倉庫上的話,你需要應用Maven Plugin

apply plugin: 'maven'

然後配置uploadArchives任務:

uploadArchives {
       repositories {
           mavenDeployer {
             repository(url: uri('repository_url'))
            }
        }
}

uploadArchives是一個已經定義過的Task。一旦你配置了任務中的倉庫,你就可以執行它發佈你的Plugin。

Using a custom plugin

爲了使用一個Plugin,我們需要在buildscript中添加它作爲dependency。首先,我們需要配置一個新的repository。這個配置決定了Plugin如何被共享。然後,我們需要在dependencies中配置Plugin的classpath。如果你想包含一個Jar文件的話,我們可以定義flatDir倉庫:

buildscript {
       repositories {
           flatDir { dirs 'build_libs' }
       }
       dependencies {
           classpath 'com.gradleforandroid:plugin'
       } 
}

如果我們已經在Maven或者Ivy倉庫中上傳了該插件的話,那麼它就會有一點不一樣。在我們設置了dependency之後,我們就可以應用該Plugin了:

apply plugin: com.gradleforandroid.RunPlugin

當使用了apply()方法,Gradle會創建一個Plugin的實例,然後執行Plugin的apply()方法。

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