Android Gradle Groovy自動化構建進階篇

Gradle系列分2章
上篇Android Gradle Groovy自動化構建入門篇
下篇Android Gradle Groovy自動化構建進階篇html

上篇,咱們已經介紹了Gradle的基本語法,接下來讓咱們一塊兒學習下Gradle高級知識:構建腳本,自定義任務,構建生命週期,解決依賴衝突,多項目構建等高階技巧。java

接下來,咱們先看下gradle的幾個個簡單應用

  • 因爲項目愈來愈大,組件化盛行,有時咱們不得很少module統一版本管理。通常作法是:
  1. 在 project 根目錄新建****.gradle 文件;
  2. 經過apply from引入該配置文件,而後使用 rootProject.ext引入相關屬性.
//1.好比這裏新建文件爲config.gradle
ext {  
    versions = [  
            sdkMinVersion     : 14,  
            sdkTargetVersion  : 26,  
            ... 
    ]  
   
    depVersion = [  
            appCompatVersion : "26.+",  
            recyclerViewVersion : "26.0.0-alpha1"  
    ]  

    deps = [  
        suport : [  
                appcompat   : "com.android.support:appcompat-v7:${depVersion.appCompatVersion}",  
                recyclerview: "com.android.support:recyclerview-v7:${depVersion.recyclerViewVersion}"  
        ]  
    ]  
}  

// 2. 引入已聲明好的屬性
apply from: 'config/config.gradle' 
android {  
    def versions = rootProject.ext.versions  
    compileSdkVersion versions.sdkCompileVersion  
    buildToolsVersion versions.toolsBuildVersion  
     ...
  }  
  
dependencies {  
    def dependencies = rootProject.ext.deps  
    compile dependencies.suport.appcompat  
}

複製代碼
  • 在好比咱們常常看到的這個錯誤:
Error:Execution failed for task ':test:processDebugManifest'.> Manifest merger failed with multiple errors, see logs
複製代碼

咱們通常的解決方案爲:命令行輸入gradlew processDebugManifest --stacktrace.android

  • 最後咱們在看個簡單的單機執行任務 git

    -w523

  • 因爲開發過程當中常常導入第三方jar包,一不當心就報jar包衝突這,這時咱們會執行 gradle app:dependencies 查看app重複依賴,而後在經過exclude剔除重複的jar。github

compile ('com.android.support:design:22.2.1')
            {
                exclude group: 'com.android.support'
            }

複製代碼

其實當咱們點擊後Gradle會去尋找當前目錄下的 build.gradle 的文件,這個文件是 Gradle 的腳本文件,它裏面定義了工程和工程擁有的全部任務等信息。而後執行相關task。下面咱們一塊兒來一步步揭開它的神祕面紗吧。api

Gradle 中的工程( Project )和任務( Task )

就像上面的截圖同樣,咱們知道,每個 Gradle 的項目都會包含一個或多個工程,每個工程又由一個或多個任務組成,一個任務表明了一個工做的最小單元,它能夠是一次類的編譯、打一個 JAR 包、生成一份 Javadoc 或者是向倉庫中提交一次版本發佈。bash

任務的定義和使用

在任務中,我麼能夠利用dependsOn定義依賴關係,doFirstdoLast對現有任務加強。 咱們仍是使用 IDEA 開發工具打開以前的項目工程,把以前 build.gradle 文件中全部的內容所有刪除,編寫輸入以下代碼markdown

task hello {
    doLast {
        println 'Hello world!'
    }
}

task release() {
    doLast {
        println "I'm release task"
    }
}

// 添任務依賴關係
release.dependsOn hello

//對現有的任務加強
// 法方一,在doFirst動做中添加
hello.doFirst {
    println 'Hello doFirst'
}
// 法方二 在doLast動做中添加
hello.doLast {
    println 'Hello doLast'
}
複製代碼

打開命令行端終,執行命令:gradle -q release,輸出結果以下:app

-w558
另外咱們還能夠爲任務設置屬性,主要經過 ext.myProperty 來初始化值,以下所示

task myTask {
    ext.myProperty = "myValue"
}

task printTaskProperties {
    doLast {
        println myTask.myProperty
    }
}
命令行執行 ➜  gradle -q printTaskProperties
myValue
複製代碼

固然咱們能夠對現有任務進行配置:禁用或者重寫。 首先咱們定義一個 myCopy 的任務,代碼以下:maven

task myCopy(type: Copy) {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}
複製代碼

相似java有API文檔,Gradle也有相似文檔,Gradle 中不少其它經常使用的任務,小夥伴們能夠點擊查看, 若是咱們想重寫 copy任務可經過overwrite屬性爲 true 來現以下所示:

task copy(type: Copy)

task copy(overwrite: true) {
    doLast {
        println('overwrite the copy.')
    }
}
命令行執行 
> gradle -q copy
overwrite the copy.
複製代碼

最後咱們看下如何禁用某些任務。直接看代碼吧

copy.enabled = false
複製代碼

實戰篇

接下來咱們來自定義插件,有三種方式來編寫

  1. 在咱們構建項目的 build.gradle 腳本中直接編寫,這種方式的好處是插件會自動被編譯加載到咱們的 classpath 中,可是它有很明顯的侷限性,就是除了在包括它的腳本外別的地方沒法複用。

  2. 在咱們構建項目的rootProjectDir/buildSrc/src/main/groovy 目錄下編寫,Gradle 會自動編譯到當前項目的 classpath 中,該項目下全部編譯腳本均可以使用,可是除了當前項目以外的都沒法複用。

  3. 以單獨的工程方式編寫,這個工程最終編譯發佈爲一個 JAR 包,它能夠在多個項目或不一樣的團隊中共享使用。

接下來咱們一步步把按照第三種方式寫個Demo吧。

首先使用IDEA新建gradle 工程選擇groovy(跟上面同樣就不細說了),而後按照下面截圖新建src/main/groovy/你的包名,接着在resources 目錄下創建 META-INF/gradle-plugins 文件夾,在其中新建 hello.properties 文件,敲黑板注意此處文件名,就是之後使用時要用的名字。此處是hello,因此咱們得按照這樣引入apply plugin: 'hello',裏面像這樣輸入插件的全路徑名字:implementation-class=org.gradle.HelloPlugin

-w1092

接下來分 2 步編寫代碼:

  1. 繼承自DefaultTask的,使用TaskAction進行標註,這樣 Gradle 就會在任務執行的時候默認調用它
  2. 而後經過實現Plugin接口來實現自定義插件類,實現apply(Project project) 方法。

按照步驟,首先咱們新建MyTask.groovy文件,裏面僅僅是簡單聲明瞭一個成員變量,而後打印。

class MyTask extends DefaultTask {
    String input = 'hello from MyTask'

    @TaskAction
    def greet() {
        println input
    }
}

複製代碼

而後咱們新建Hello.groovy文件.咱們向這個plugin添加了一個hello任務,咱們知道gradle中能夠配置參數好比:defaultConfig {} ndk {}等,其實gradle是使用 extension objects來現實給插件傳參,具體實現看下面代碼的註釋:

class Hello implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // 向extension container保存para參數,並應用給HelloPluginExtension
        project.extensions.create("para", HelloPluginExtension)
        // 向project對象添加hello任務
        project.task('hello',type:MyTask) {
            input = 'Hello Plugin input!'
            doLast {
                println "${project.para.first}${project.para.last}"
            }
        }
    }
}
複製代碼

接下來發布工程到本地倉庫,供其餘項目使用,在build.gradle中輸入

//使用 maven-publish 插件先發布到本地
apply plugin: 'maven-publish'
publishing{
    publications {
        mavenJava(MavenPublication) {
            from components.java

            groupId 'org.gradle'
            artifactId 'customPlugin'
            version '1.0-SNAPSHOT'

        }
    }

    repositories{
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url "../repo"
        }
    }
}
複製代碼

點擊publish任務,看到成功發佈工程到本地倉庫../repo中了。

-w1215
最後用 IDEA 開發工具新建立一個 Gradle 工程來驗證咱們的插件。看到右側gradle任務中多了咱們添加的hello任務,點擊查當作功輸出了Hello world。
-w1086

補充及常見問題

文件樹是有層級結構的文件集合,一個文件樹它能夠表明一個目錄結構或一 ZIP 壓縮包中的內容結構。使用Project.fileTree(java.util.Map)建立,可使用過慮條件來包含或排除相關文件。

// 指定目錄建立文件樹對象
FileTree tree = fileTree(dir: 'src/main')
// 給文件樹對象添加包含指定文件
tree.include '**/*.java'
//andoid中使用文件樹
implementation fileTree(include: ['*.jar'], dir: 'libs')
複製代碼

多module的編譯配置

注意 settings.gradle引入的module纔會參與編譯include ':app', ':plugin_common', ':plugin_gallery',能夠在跟guild.gradle 中統一設置公共行爲;好比下圖添加一個hello任務。

-w1615

一個工程的路徑爲:以冒號(: 它表明了根工程)開始,再加上工程的名稱。例如「:common」。 一個任務的路徑爲:工程路徑加上任務名稱,例如「:common:hello」. 好比:僅僅執行 gradle :plugin_common:hello

源碼下載

相關文章
相關標籤/搜索