介紹
到目前爲止,我們已經看到了很多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自動添加了訪問權限,你也可以重寫他們。就像我們定義了getGreeting
在MyGroovyClass
中。如果沒有指定的話,可以使用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都會按照順序執行。我們可以使用doFirst
和doLast
函數來添加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()
方法。