Gradle系列之從init.gradle提及

從maven提及

用過maven的開發都知道,在maven裏一些信息能夠定義在全局的配置文件中,好比把一些倉庫信息定義在用戶目錄/.m2/setting.xml文件中,這樣就不用每一個項目都配置這些相同的配置了。對於Andorid開發者來講,使用gradle比使用maven更常見,在開發中說不定你會在每個項目中配置一遍公司的倉庫地址,定義一些相同的配置,那麼在gradle中有沒有相似maven的這麼一個配置文件能夠定義一些全局信息呢?java

答案固然是有,那就是init.gradle。android

init.gradle的做用

先來簡單介紹一下init.gradle這個文件的做用。數據庫

  • 它能夠用來創建公司內部的配置,如定義公司內部的倉庫地址。
  • 它能夠用來配置一些全局屬性,好比配置持續集成服務器的地址等配置。
  • 它能夠用來提供構建所須要的用戶的我的信息,如倉庫或數據庫的用戶名和密碼。
  • 它能夠用來定義開發者機器的環境,好比定義jdk安裝在什麼位置,android sdk安裝在什麼位置等等。
  • 最重要的功能之一,它能夠用來註冊一些監聽器。好比監聽Gradle事件的發生,作一些額外的操做,例如須要對某個項目構建前和構建後作一些操做,又例如對項目的依賴作檢測,檢測是否含有snapshot包,在release構建中通常來講是禁止依賴snapshot包的,因此這時候就能夠扔出一個異常。
  • 重定向日誌。咱們能夠將gradle默認的日誌進行重定向,甚至咱們能夠不輸出默認日誌,自定義如何輸出gradle產生的日誌信息。

init.gradle的加載順序

再來講說init.gradle文件的加載順序(不必定命名爲init.gradle)。Gradle會依次對一些目錄進行檢測,按照優先級加載這些目錄下的文件,若是一個目錄下有多個文件被找到,則按照英文字母的順序依次加載。加載優先級以下:apache

  • 經過 -I 或者 –init-script 參數在構建開始時指定路徑,如
  • gradle --init-script init.gradle clean

gradle --I init.gradle assembleDebug api

  • 加載USER_HOME/.gradle/init.gradle文件
  • 加載USER_HOME/.gradle/init.d/目錄下的以.gradle結尾的文件
  • 加載GRADLE_HOME/init.d/目錄下的以.gradle結尾的文件

那麼USER_HOME和GRADLE_HOME能夠怎麼獲得呢,其實USER_HOME通常來講就是當前用戶目錄下的.gradle目錄,而GRADLE_HOME目錄通常來講是gradle的可執行目錄,若是你配置了環境變量,且你使用的是環境變量中的可執行文件,則這個目錄會執向你配置了環境變量的目錄,好比,我配置了gradle的環境變量指向/Library/gradle,這兩個目錄在我電腦上的值爲:緩存

gradleHomeDir:/Library/gradle gradleUserHomeDir:/Users/lizhangqu/.gradle

 

可是若是我使用項目中的gradlew去執行任務,則這兩個值爲ruby

gradleHomeDir:/Users/lizhangqu/.gradle/wrapper/dists/gradle-2.10-all/a4w5fzrkeut1ox71xslb49gst/gradle-2.10 gradleUserHomeDir:/Users/lizhangqu/.gradle

 

咱們能夠在init.gradle中使用gradle實例來得到這兩個目錄,甚至能夠得到gradle的版本,以及gradle啓動時所攜帶的參數。具體腳本以下:服務器

//gradle的可執行目錄 gradle.println "gradleHomeDir:${gradle.gradleHomeDir}" //gradle的用戶目錄,用於緩存一些下載好的資源,編譯好的構建腳本等 gradle.println "gradleUserHomeDir:${gradle.gradleUserHomeDir}" //gradle的版本號 gradle.println "gradleVersion:${gradle.gradleVersion}" //gralde當前構建的啓動參數 gradle.println "startParameter:${gradle.startParameter}"

 

在init.gradle使用三方庫

若是咱們須要在init.gradle中使用第三方庫的功能,好比我須要使用apache的commons-math庫中的某個函數,則可使用initscript定義倉庫地址,而後將依賴加入,以下腳本:閉包

initscript {
    //定義init.gradle所須要的倉庫地址 repositories { jcenter() mavenCentral() mavenLocal() }  //加入依賴 dependencies { classpath 'org.apache.commons:commons-math:2.0' } } //使用函數 println org.apache.commons.math.fraction.Fraction.ONE_FIFTH.multiply(2)

 

以上代碼會輸出2/5app

在init.gradle中定義全局的倉庫

在公司中,我所見到的倉庫的定義都是定義在每個項目中,沒有一個全局的倉庫配置,這樣顯得有點冗餘,而在init.gradle中就能夠定義一個公司的倉庫地址,以後全部的gradle項目均可以使用這個倉庫。而且對於一些實時在改變的庫,咱們能夠定義其全局的更新策略(雖然這個策略在個人電腦上一直沒有生效,但這是gradle官方標準的作法,即便用cacheChangingModulesFor屬性,將其時間設爲0,沒有生效顯然是一個bug)。

//init.gralde能夠配置一些全局的配置,好比倉庫的地址等 import java.util.concurrent.TimeUnit allprojects { Project project -> buildscript { repositories { maven { url "htttp://url/to/maven" } jcenter() mavenCentral() mavenLocal() } } repositories { maven { url "htttp://url/to/maven" } jcenter() mavenCentral() mavenLocal() } configurations.all { resolutionStrategy { // cache dynamic versions for 10 minutes cacheDynamicVersionsFor 10 * 60, TimeUnit.SECONDS // don't cache changing modules at all cacheChangingModulesFor 0, TimeUnit.SECONDS } } } 

 

在init.gradle中自定義插件並使用

在咱們的項目中,咱們會使用apply plugin來引用一些插件來加強一些功能,固然在init.gradle也能夠這麼作,咱們就之前面定義公司的倉庫和依賴的更新策略來作演示,將其修改成一個插件而後使用。以下:

//對於一些倉庫的全局定義,也可使用插件的方式定義,如 apply plugin: EnterpriseRepositoryPlugin class EnterpriseRepositoryPlugin implements Plugin<Gradle> { private static String REPOSITORY_URL = "htttp://url/to/maven" void apply(Gradle gradle) { gradle.allprojects { project -> project.buildscript { repositories { maven { url REPOSITORY_URL } jcenter() mavenCentral() mavenLocal() } dependencies { //能夠定義全局的android gradle插件 classpath 'com.android.tools.build:gradle:2.1.2' } } project.repositories { maven { url REPOSITORY_URL } jcenter() mavenCentral() mavenLocal() } project.configurations.all { resolutionStrategy { // cache dynamic versions for 10 minutes cacheDynamicVersionsFor 10 * 60, TimeUnit.SECONDS // don't cache changing modules at all cacheChangingModulesFor 0, TimeUnit.SECONDS } } } } }

 

使用init.gradle重寫日誌

默認的若是我使用gradle assembleDebug來執行構建,控制檯會輸出一系列的log,相似下面的內容

./gradlew --I init.gradle assembleDebug
Incremental java compilation is an incubating feature.
:app:preBuild UP-TO-DATE :app:preDebugBuild UP-TO-DATE :app:checkDebugManifest :app:preReleaseBuild UP-TO-DATE :app:prepareComAndroidSupportAnimatedVectorDrawable2411Library :app:prepareComAndroidSupportAppcompatV72411Library :app:prepareComAndroidSupportSupportV42411Library :app:prepareComAndroidSupportSupportVectorDrawable2411Library :app:prepareDebugDependencies :app:compileDebugAidl :app:compileDebugRenderscript :app:generateDebugBuildConfig :app:mergeDebugShaders :app:compileDebugShaders :app:generateDebugAssets :app:mergeDebugAssets :app:generateDebugResValues UP-TO-DATE :app:generateDebugResources :app:mergeDebugResources :app:processDebugManifest :app:processDebugResources :app:generateDebugSources :app:incrementalDebugJavaCompilationSafeguard :app:compileDebugJavaWithJavac :app:compileDebugJavaWithJavac - is not incremental (e.g. outputs have changed, no previous execution, etc.). :app:compileDebugNdk UP-TO-DATE :app:compileDebugSources :app:prePackageMarkerForDebug :app:transformClassesWithDexForDebug Merged dex #1 (5 defs/15.3KiB) Merged dex #2 (355 defs/574.2KiB) Merged dex #3 (819 defs/997.1KiB) Merged dex #4 (17 defs/48.5KiB) Merged dex #5 (29 defs/89.4KiB) Merged dex #6 (363 defs/280.8KiB) Merged dex #7 (46 defs/7.4KiB) Result is 1634 defs/2438.7KiB. Took 0.5s :app:mergeDebugJniLibFolders :app:transformNative_libsWithMergeJniLibsForDebug :app:processDebugJavaRes UP-TO-DATE :app:transformResourcesWithMergeJavaResForDebug :app:validateDebugSigning :app:packageDebug :app:zipalignDebug :app:assembleDebug BUILD SUCCESSFUL Total time: 29.62 secs 

 

對於這些log,咱們可使用gradle.useLogger()函數從新定義須要輸出什麼內容。好比咱們讓控制檯按咱們的意思進行輸出,則能夠定義一個類,實現BuildListener接口和TaskExecutionListener接口。再調用useLogger函數傳入這個類的實例,以下:

gradle.useLogger(new CustomEventLogger()) //自定義的log輸出 class CustomEventLogger implements BuildListener, TaskExecutionListener { @Override void buildStarted(Gradle gradle) { println "buildStarted" } @Override void settingsEvaluated(Settings settings) { println "settingsEvaluated" } @Override void projectsLoaded(Gradle gradle) { println "projectsLoaded" } @Override void projectsEvaluated(Gradle gradle) { println "projectsEvaluated" } public void beforeExecute(Task task) { println "beforeExecute:[$task.name]" } public void afterExecute(Task task, TaskState state) { println "afterExecute:[$task.name]" } public void buildFinished(BuildResult result) { println 'buildFinished' if (result.failure != null) { result.failure.printStackTrace() } } }

 

 

以後控制檯的輸出就會大變樣,變成下面的內容

./gradlew --I init.gradle assembleDebug settingsEvaluated projectsLoaded Incremental java compilation is an incubating feature. projectsEvaluated beforeExecute:[preBuild] afterExecute:[preBuild] beforeExecute:[preDebugBuild] afterExecute:[preDebugBuild] beforeExecute:[checkDebugManifest] afterExecute:[checkDebugManifest] beforeExecute:[preReleaseBuild] afterExecute:[preReleaseBuild] beforeExecute:[prepareComAndroidSupportAnimatedVectorDrawable2411Library] afterExecute:[prepareComAndroidSupportAnimatedVectorDrawable2411Library] beforeExecute:[prepareComAndroidSupportAppcompatV72411Library] afterExecute:[prepareComAndroidSupportAppcompatV72411Library] beforeExecute:[prepareComAndroidSupportSupportV42411Library] afterExecute:[prepareComAndroidSupportSupportV42411Library] beforeExecute:[prepareComAndroidSupportSupportVectorDrawable2411Library] afterExecute:[prepareComAndroidSupportSupportVectorDrawable2411Library] beforeExecute:[prepareDebugDependencies] afterExecute:[prepareDebugDependencies] beforeExecute:[compileDebugAidl] afterExecute:[compileDebugAidl] beforeExecute:[compileDebugRenderscript] afterExecute:[compileDebugRenderscript] beforeExecute:[generateDebugBuildConfig] afterExecute:[generateDebugBuildConfig] beforeExecute:[mergeDebugShaders] afterExecute:[mergeDebugShaders] beforeExecute:[compileDebugShaders] afterExecute:[compileDebugShaders] beforeExecute:[generateDebugAssets] afterExecute:[generateDebugAssets] beforeExecute:[mergeDebugAssets] afterExecute:[mergeDebugAssets] beforeExecute:[generateDebugResValues] afterExecute:[generateDebugResValues] beforeExecute:[generateDebugResources] afterExecute:[generateDebugResources] beforeExecute:[mergeDebugResources] afterExecute:[mergeDebugResources] beforeExecute:[processDebugManifest] afterExecute:[processDebugManifest] beforeExecute:[processDebugResources] afterExecute:[processDebugResources] beforeExecute:[generateDebugSources] afterExecute:[generateDebugSources] beforeExecute:[incrementalDebugJavaCompilationSafeguard] afterExecute:[incrementalDebugJavaCompilationSafeguard] beforeExecute:[compileDebugJavaWithJavac] :app:compileDebugJavaWithJavac - is not incremental (e.g. outputs have changed, no previous execution, etc.). afterExecute:[compileDebugJavaWithJavac] beforeExecute:[compileDebugNdk] afterExecute:[compileDebugNdk] beforeExecute:[compileDebugSources] afterExecute:[compileDebugSources] beforeExecute:[prePackageMarkerForDebug] afterExecute:[prePackageMarkerForDebug] beforeExecute:[transformClassesWithDexForDebug] Merged dex #1 (5 defs/15.3KiB) Merged dex #2 (355 defs/574.2KiB) Merged dex #3 (819 defs/997.1KiB) Merged dex #4 (17 defs/48.5KiB) Merged dex #5 (29 defs/89.4KiB) Merged dex #6 (363 defs/280.8KiB) Merged dex #7 (46 defs/7.4KiB) Result is 1634 defs/2438.7KiB. Took 0.7s afterExecute:[transformClassesWithDexForDebug] beforeExecute:[mergeDebugJniLibFolders] afterExecute:[mergeDebugJniLibFolders] beforeExecute:[transformNative_libsWithMergeJniLibsForDebug] afterExecute:[transformNative_libsWithMergeJniLibsForDebug] beforeExecute:[processDebugJavaRes] afterExecute:[processDebugJavaRes] beforeExecute:[transformResourcesWithMergeJavaResForDebug] afterExecute:[transformResourcesWithMergeJavaResForDebug] beforeExecute:[validateDebugSigning] afterExecute:[validateDebugSigning] beforeExecute:[packageDebug] afterExecute:[packageDebug] beforeExecute:[zipalignDebug] afterExecute:[zipalignDebug] beforeExecute:[assembleDebug] afterExecute:[assembleDebug] buildFinished 

 

對於useLogger函數來說,其傳入的參數是一個Object類型,咱們讓其能夠實現任何一個addListener方法傳入的參數的接口便可,一旦調用了useLogger方法,默認的gradle事件的日誌會被替換,也就是會被替換成咱們自定義的日誌輸出,而這些接口以下:

  • org.gradle.BuildListener
  • org.gradle.api.execution.TaskExecutionGraphListener
  • org.gradle.api.ProjectEvaluationListener
  • org.gradle.api.execution.TaskExecutionListener
  • org.gradle.api.execution.TaskActionListener
  • org.gradle.api.logging.StandardOutputListener
  • org.gradle.api.tasks.testing.TestListener
  • org.gradle.api.tasks.testing.TestOutputListener
  • org.gradle.api.artifacts.DependencyResolutionListener

使用init.gradle註冊構建監聽

上面咱們提到了不少接口,這些接口可使用gradle.addBuildListener方法或者gradle.addListener方法註冊到整個構建過程。

  • BuildListener

BuildListener在整個構建過程當中的特定點會回調特定的函數,如構建開始時會回調buildStarted,setting.gradle加載和評估完成後會回調settingsEvaluated,全部項目加載進來後會回調projectsLoaded,全部項目配置評估完成會回調projectsEvaluated,構建完成會回調buildFinished,具體例子以下:

//構建監聽 gradle.addBuildListener(new BuildListener() { @Override void buildStarted(Gradle gradle) { //init.gradle被執行前,構建已經發生,且buildStarted已經被回調, // 所以後續加入的BuildListener都不會再調用buildStarted gradle.println("=========BuildListener:buildStarted=========") } @Override void settingsEvaluated(Settings settings) { //setting.gradle加載和評估配置階段完成 gradle.println("=========BuildListener:settingsEvaluated=========") } @Override void projectsLoaded(Gradle gradle) { //項目加載完成 gradle.println("=========BuildListener:projectsLoaded=========") } @Override void projectsEvaluated(Gradle gradle) { //項目評估配置階段結束 gradle.println("=========BuildListener:projectsEvaluated=========") } @Override void buildFinished(BuildResult result) { //構建完成 gradle.println("=========BuildListener:buildFinished=========") } })

 

可是buildStarted這個回調有點特殊,在構建開始後,init.gradle執行前,buildStarted方法就會被回調,所以在init.gradle加入的監聽器buildStarted是不會被回調的,只有gradle內部註冊的纔會回調。這一細節能夠從gradle的源碼中看到。

import javafx.stage.Stage private BuildResult doBuild(final Stage upTo) { return buildOperationExecutor.run("Run build", new Factory<BuildResult>() { @Override public BuildResult create() { Throwable failure = null; try { //回調buildStarted,但此時init.gradle沒有被執行,時機太早 buildListener.buildStarted(gradle); doBuildStages(upTo); } catch (Throwable t) { failure = exceptionAnalyser.transform(t); } BuildResult buildResult = new BuildResult(upTo.name(), gradle, failure); buildListener.buildFinished(buildResult); if (failure != null) { throw new ReportedException(failure); } return buildResult; } }); } private void doBuildStages(Stage upTo) { //執行init.gradle,此時buildStarted已經被回調,以後都不會再次回調,因此init.gradle中加入的監聽器buildStarted都不會被回調 // Evaluate init scripts initScriptHandler.executeScripts(gradle); // Calculate projects settingsLoader.findAndLoadSettings(gradle); // Configure build buildOperationExecutor.run("Configure build", new Runnable() { @Override public void run() { buildConfigurer.configure(gradle); if (!gradle.getStartParameter().isConfigureOnDemand()) { buildListener.projectsEvaluated(gradle); } modelConfigurationListener.onConfigure(gradle); } }); if (upTo == Stage.Configure) { return; } // Populate task graph buildOperationExecutor.run("Calculate task graph", new Runnable() { @Override public void run() { buildConfigurationActionExecuter.select(gradle); if (gradle.getStartParameter().isConfigureOnDemand()) { buildListener.projectsEvaluated(gradle); } } }); // Execute build buildOperationExecutor.run("Run tasks", new Runnable() { @Override public void run() { buildExecuter.execute(gradle); } }); assert upTo == Stage.Build; }

ProjectEvaluationListener

ProjectEvaluationListener主要用於監聽項目的配置評估階段,配置評估開始前和完成後會回調。以下:

//配置評估監聽 gradle.addProjectEvaluationListener(new ProjectEvaluationListener() { @Override void beforeEvaluate(Project project) { //項目配置評估前回調 gradle.println("=========ProjectEvaluationListener:beforeEvaluate ${project.getName()}=========") } @Override void afterEvaluate(Project project, ProjectState state) { //項目配置評估後回調 //若是失敗,則failure不爲null gradle.println("=========ProjectEvaluationListener:afterEvaluate ${state.executed} ${state.failure}=========") } }) 

 

TaskExecutionGraphListener

TaskExecutionGraphListener這個監聽器能夠在項目評估完成後得到須要構建的任務的全部依賴,好比下面的代碼就能夠得到我所執行的task的全部依賴。

gradle.addListener(new TaskExecutionGraphListener() { @Override void graphPopulated(TaskExecutionGraph graph) { gradle.println "=========from gradle.addListener graphPopulated=========" graph.allTasks.each { Task task -> gradle.println "=========TaskExecutionGraph:${task.getName()}=========" } } }

 

輸出的內容以下:

./gradlew --I init.gradle assembleDebug
=========from gradle.addListener graphPopulated========= =========TaskExecutionGraph:preBuild========= =========TaskExecutionGraph:preDebugBuild========= =========TaskExecutionGraph:checkDebugManifest========= =========TaskExecutionGraph:preReleaseBuild========= =========TaskExecutionGraph:prepareComAndroidSupportAnimatedVectorDrawable2411Library========= =========TaskExecutionGraph:prepareComAndroidSupportAppcompatV72411Library========= =========TaskExecutionGraph:prepareComAndroidSupportSupportV42411Library========= =========TaskExecutionGraph:prepareComAndroidSupportSupportVectorDrawable2411Library========= =========TaskExecutionGraph:prepareDebugDependencies========= =========TaskExecutionGraph:compileDebugAidl========= =========TaskExecutionGraph:compileDebugRenderscript========= =========TaskExecutionGraph:generateDebugBuildConfig========= =========TaskExecutionGraph:mergeDebugShaders========= =========TaskExecutionGraph:compileDebugShaders========= =========TaskExecutionGraph:generateDebugAssets========= =========TaskExecutionGraph:mergeDebugAssets========= =========TaskExecutionGraph:generateDebugResValues========= =========TaskExecutionGraph:generateDebugResources========= =========TaskExecutionGraph:mergeDebugResources========= =========TaskExecutionGraph:processDebugManifest========= =========TaskExecutionGraph:processDebugResources========= =========TaskExecutionGraph:generateDebugSources========= =========TaskExecutionGraph:incrementalDebugJavaCompilationSafeguard========= =========TaskExecutionGraph:compileDebugJavaWithJavac========= =========TaskExecutionGraph:compileDebugNdk========= =========TaskExecutionGraph:compileDebugSources========= =========TaskExecutionGraph:prePackageMarkerForDebug========= =========TaskExecutionGraph:transformClassesWithDexForDebug========= =========TaskExecutionGraph:mergeDebugJniLibFolders========= =========TaskExecutionGraph:transformNative_libsWithMergeJniLibsForDebug========= =========TaskExecutionGraph:processDebugJavaRes========= =========TaskExecutionGraph:transformResourcesWithMergeJavaResForDebug========= =========TaskExecutionGraph:validateDebugSigning========= =========TaskExecutionGraph:packageDebug========= =========TaskExecutionGraph:zipalignDebug========= =========TaskExecutionGraph:assembleDebug========= 

 

TaskExecutionListener

TaskExecutionListener這個監聽器能夠用來監聽構建過程當中全部task構建前和構建後。每個任務執行前會回調beforeExecute方法,執行完成後會回調afterExecute,執行的結果保存在入參TaskState中。

//等同gradle.taskGraph.addTaskExecutionListener
gradle.addListener(new TaskExecutionListener() {
    @Override void beforeExecute(Task task) { gradle.println "=========from gradle.addListener beforeExecute=========" gradle.println "=========TaskExecutionListener:beforeExecute:${task.getName()}=========" } @Override void afterExecute(Task task, TaskState state) { gradle.println "=========from gradle.addListener afterExecute=========" gradle.println "=========TaskExecutionListener:afterExecute:${task.getName()}=========" gradle.println "=========TaskState:[executed]${state.executed}=========" gradle.println "=========TaskState:[didWork]${state.didWork}=========" gradle.println "=========TaskState:[failure]${state.failure}=========" gradle.println "=========TaskState:[skipMessage]${state.skipMessage}=========" gradle.println "=========TaskState:[skipped]${state.skipped}=========" gradle.println "=========TaskState:[upToDate]${state.upToDate}=========" } })

 

DependencyResolutionListener

DependencyResolutionListener這個監聽器能夠用來監聽構建過程當中依賴的關係,好比可使用這個監聽器來檢測release構建中是否包含snapshot包,若是包含則扔出異常中止構建。

//依賴監聽
gradle.addListener(new DependencyResolutionListener() { @Override void beforeResolve(ResolvableDependencies resolvableDependencies) { gradle.println "DependencyResolutionListener:beforeResolve:=====${dependencies}=====" } @Override void afterResolve(ResolvableDependencies resolvableDependencies) { gradle.println "DependencyResolutionListener:afterResolve:=====${dependencies}=====" def projectPath = resolvableDependencies.path.toLowerCase() if (projectPath.contains("releasecompile")) { gradle.println "[DependencyResolutionListener] release detect:${resolvableDependencies.path}" resolvableDependencies.resolutionResult.allDependencies.each { dependency -> if (dependency instanceof org.gradle.api.internal.artifacts.result.DefaultUnresolvedDependencyResult) { gradle.println "DefaultUnresolvedDependencyResult reason: ${dependency.reason}" gradle.println "DefaultUnresolvedDependencyResult failure: ${dependency.failure}" } else if (dependency instanceof org.gradle.api.internal.artifacts.result.DefaultResolvedDependencyResult) { String selected = dependency.selected def from = dependency.from gradle.println "[DependencyResolutionListener] current dependency:${selected} which is from:${from}" if (selected != null && (selected.toLowerCase().contains("snapshot") || selected.toLowerCase().contains("beta"))) { String errorMessage = "[DependencyResolutionListener] [Error] ${selected} from ${from} contains a snapshot or beta version. you must fix it." gradle.println errorMessage throw new IllegalStateException(errorMessage) } } } } } })

 

StandardOutputListener

StandardOutputListener這個監聽器能夠獲得控制檯輸出的log,除了輸出到控制檯後,能夠對其進行重定向,好比輸出到文件中去,以下:

//log輸出的監聽,能夠將log輸出到其餘文件中去 gradle.addListener(new StandardOutputListener() { static File logFile = new File("log.txt"); static { if (logFile.exists()) { logFile.delete() } logFile.createNewFile() } @Override void onOutput(CharSequence output) { try { FileWriter writer = new FileWriter(logFile, true); writer.write(output.toString()); writer.close(); } catch (IOException e) { e.printStackTrace(); } } })

TaskActionListener

在一個Task中可能會有不少action,好比咱們經過doFirst和doLast加入的閉包都是action,TaskActionListener監聽器就能夠在這些actions執行前和執行完成後獲得回調,以下:

//TaskAction監聽器,Task.doFirst,Task.doLast等傳入的閉包都是Action gradle.addListener(new TaskActionListener() { @Override void beforeActions(Task task) { //在全部action執行前回調 gradle.println "**********beforeActions:${task}**********" task.getActions().each { Action action -> gradle.println "**********${action}**********" } } @Override void afterActions(Task task) { //在全部action執行後回調 gradle.println "**********afterActions:${task}**********" task.getActions().each { Action action -> gradle.println "**********${action}**********" } } })

TestListener和TestOutputListener

這兩個監聽器主要是用於執行測試相關的task使用的,好比保存測試報告,可是實際測試中發現TestOutputListener中的方法怎麼都不會回調,緣由未知,以下腳本:

//測試監聽器
gradle.addListener(new TestListener() {
    @Override void beforeSuite(TestDescriptor suite) { gradle.println "beforeSuite:=====${suite.className} ${suite.name}=====" } @Override void afterSuite(TestDescriptor suite, TestResult result) { gradle.println "afterSuite:=====${suite.className} ${suite.name} ${result}=====" } @Override void beforeTest(TestDescriptor testDescriptor) { gradle.println "beforeTest:=====${testDescriptor.className} ${testDescriptor.name}=====" } @Override void afterTest(TestDescriptor testDescriptor, TestResult result) { gradle.println "afterTest:=====${testDescriptor.className} ${testDescriptor.name} ${result}=====" } }) //測試的輸出監聽,實際測試並無回調 gradle.addListener(new TestOutputListener() { @Override void onOutput(TestDescriptor testDescriptor, TestOutputEvent outputEvent) { gradle.println "onOutput:=====${testDescriptor} ${outputEvent}=====" gradle.println "message:${outputEvent.message}" gradle.println "destination:${outputEvent.destination}" } })

使用閉包

除了以上監聽器以外,咱們還可使用閉包來監聽構建的過程當中的事件回調,好比我只對構建完成這一事件感興趣,則可使用

gradle.buildFinished { gradle.println "=========buildFinished=========" }

 

 

除了這一閉包,還可使用其餘幾個相關的閉包對感興趣的事件進行註冊,註冊後對應的事件發生便會回調該閉包。

/** * 同上BuildListener和ProjectEvaluationListener */ gradle.buildStarted { gradle.println "=========buildStarted=========" } gradle.settingsEvaluated { gradle.println "=========settingsEvaluated=========" } gradle.projectsLoaded { gradle.println "=========projectsLoaded=========" } gradle.projectsEvaluated { gradle.println "=========projectsEvaluated=========" } gradle.buildFinished { gradle.println "=========buildFinished=========" } gradle.beforeProject { gradle.println "=========beforeProject=========" } gradle.afterProject { gradle.println "=========afterProject=========" }

 

其餘

對於Task的依賴關係的得到,除了上面的註冊TaskExecutionGraphListener監聽器,還有其餘的方式,即經過gradle.taskGraph來得到,具體的腳步以下:

//當前構建的任務依賴關係圖
gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph -> taskGraph.allTasks.each { Task task -> gradle.println "=========whenReady:taskGraph:${task.getName()}=========" } taskGraph.beforeTask { Task task -> gradle.println "=========whenReady:beforeTask:${task.getName()}=========" } taskGraph.afterTask { Task task -> gradle.println "=========whenReady:afterTask:${task.getName()}=========" } } //等同於上面的whenReady閉包中的內容 gradle.taskGraph.addTaskExecutionGraphListener(new TaskExecutionGraphListener() { @Override void graphPopulated(TaskExecutionGraph graph) { gradle.println "=========TaskExecutionGraphListener:graphPopulated=========" graph.allTasks.each { Task task -> gradle.println "=========TaskExecutionGraph:${task.getName()}=========" } } }) //等同於上面的whenReady閉包中的內容 gradle.taskGraph.addTaskExecutionListener(new TaskExecutionListener() { @Override void beforeExecute(Task task) { gradle.println "=========TaskExecutionListener:beforeExecute:${task.getName()}=========" } @Override void afterExecute(Task task, TaskState state) { gradle.println "=========TaskExecutionListener:afterExecute:${task.getName()}=========" gradle.println "=========TaskState:[executed]${state.executed}=========" gradle.println "=========TaskState:[didWork]${state.didWork}=========" gradle.println "=========TaskState:[failure]${state.failure}=========" gradle.println "=========TaskState:[skipMessage]${state.skipMessage}=========" gradle.println "=========TaskState:[skipped]${state.skipped}=========" gradle.println "=========TaskState:[upToDate]${state.upToDate}=========" } }) //得到root project gradle.taskGraph.addTaskExecutionGraphListener(new TaskExecutionGraphListener() { @Override void graphPopulated(TaskExecutionGraph graph) { gradle.println "========${gradle.rootProject}========" } })

 

監聽器的應用(構建時間的監聽)

對於監聽器,咱們可使用它來計算各個task所執行的時間,而後輸出控制檯,以下:

class TimeListener implements TaskExecutionListener, BuildListener { private Clock clock private times = [] @Override void beforeExecute(Task task) { clock = new org.gradle.util.Clock() } @Override void afterExecute(Task task, TaskState taskState) { def ms = clock.timeInMs times.add([ms, task.path]) task.project.logger.warn "${task.path} spend ${ms}ms" } @Override void buildFinished(BuildResult result) { println "Task spend time:" for (time in times) { if (time[0] >= 50) { printf "%7sms %s\n", time } } } @Override void buildStarted(Gradle gradle) {} @Override void projectsEvaluated(Gradle gradle) {} @Override void projectsLoaded(Gradle gradle) {} @Override void settingsEvaluated(Settings settings) {} } gradle.addListener(new TimeListener())

 

監聽器的補充 
其實關於監聽器,並不是必定要在init.gradle中進行註冊,咱們也能夠徹底在咱們項目中註冊監聽,只不過在init.gradle中能夠註冊一些全局的公共功能的監聽器,就像上面的構建時間的計算。

總結

Gradle和init.gradle相關的內容大概就這麼多,總結起來,其有用的東西就是各類各樣的監聽器,可用於構建過程當中的hook,作一些本身的事情,還有就是能夠進行全局的配置等。具體如何使用,可根據本身的需求進行定製。

 

轉載自:https://blog.csdn.net/sbsujjbcy/article/details/52079413

相關文章
相關標籤/搜索