Gradle理論與實踐三:Gradle構建腳本基礎

Gradle系列相關文章
1、Gradle理論與實踐一:Gradle入門
2、Gradle理論與實踐二:Groovy介紹
3、Gradle理論與實踐三:Gradle構建腳本基礎
4、Gradle理論與實踐四:自定義Gradle插件
5、Gradle配置subprojects和allprojects的區別:subprojects和allprojects的區別

Gradle構建腳本基礎

  • Project:根據業務抽取出來的一個個獨立的模塊

  • Task:一個操作,一個原子性操作。比如上傳一個jar到maven中心庫等

  • Setting.gradle文件:初始化及整個工程的配置入口

  • build.gradle文件:

每個Project都會有個build.gradle的文件,是Project構建的入口。Root Project也有一個build.gradle文件,可以獲取到所有的Child Project,並且可以對所有的Child Project進行統一配置:如應用的三方插件、三方依賴庫等。如,我們可以在Root Project的build.gradle文件裏配置:

allprojects {
      repositories {
       jcenter()
      }
}

這樣項目中所有依賴的三方庫都可以在jcenter中下載了,省去了對每個Project去配置的情況。

上面用到的是allprojects,還可以配置subprojects,他們的區別在於:allprojects是對所有project的配置,包括Root Project。而subprojects是對所有Child Project的配置。更詳細的請移步:https://blog.csdn.net/u013700502/article/details/85231687

1、創建一個task

Task的創建方式,可以是:

task hello {
     doFirst {
       print 'hello:doFirst\n'
     }
     doLast {
       print 'hello:doLast\n'
     }
}

也可以是:

tasks.create("hello") {
     doFirst {
       print 'hello:doFirst'
     }
     doLast {
       print 'hello:doLast'
     }
}

他們執行的結果都是一樣的:

bogon:test_gradle mq$ gradle -q hello
hello:doFirst
hello:doLast

task是Project對象的一個函數,原型爲Task create(String name, Closure configureClosure),最後一個參數是閉包的時候,可以放到括號外面,並且括號可以省略,task中的doFirst和doLast分別在任務前後執行。

2、創建Task的幾種方式

  • 1、調用Project對象的task(String name)方法,如:
def Task hello = task(hello);

hello << {
    print 'hello\n'
}

輸出:

bogon:test_gradle mq$ gradle -q hello
hello
  • 2、任務名字+閉包方式,如:
task hello {
    description '任務描述'
    doLast {
        print "方法原型: Task task(String name, Closure configureClosure)\n"
        print "任務描述: ${description}"
    }
}

輸出結果:

bogon:test_gradle mq$ gradle -q hello
方法原型: Task task(String name, Closure configureClosure)
任務描述: 任務描述
  • 3、TaskContainer方式創建:
tasks.create('hello') {
    description '任務描述'
    doLast {
        print "方法原型: Task create(String name, Closure configureClosure)\n"
        print "任務描述: ${description}"
    }
}

輸出結果:

方法原型: Task create(String name, Closure configureClosure)
任務描述: 任務描述

tasks是Project的屬性,其類型是TaskContainer。其中1和2的創建最終也是調用TaskContainer方式創建的。

3、Task內部執行順序

當我們執行Task的時候,就是執行其擁有的actions列表,是一個List。把Task執行之前、Task本身執行、Task之後執行分別稱爲doFirst、doSelf、doLast,先來看個例子:

def Task hello = task myTask(type: CustomTask);

hello.doFirst {
    print 'Task執行之前 do-First\n'
}

hello.doLast {
    print 'Task執行之後 do-Last\n'
}

class CustomTask extends DefaultTask {

    @TaskAction
    def doself() {
        print 'Task執行自身 do-self\n'
    }
}

輸出:

bogon:test_gradle mq$ gradle -q hello
Task執行之前 do-First
Task執行自身 do-self
Task執行之後 do-Last

通過結果發現確實是按照我們想要的順序執行的。Gradle在執行hello這個任務的時候,Gradle會解析其帶有@TaskAction註解的方法作爲其Task執行的Action,並且把其加入到actionList中。而doFirst、doLast分別會在actionList的最前面和最後面加入,所以之後就達到了按順序執行。

4、Task任務依賴

任務之間是可以有依賴關係的,使用dependsOn執行當前task依賴的任務,如:

task hello << {
   print 'hello '
}

task world(dependsOn: hello) {
   doLast {
       print 'world'
   }
  }

此時執行gradle -q world,結果如下:

bogon:test_gradle mq$ gradle -q world
hello world

因爲world任務是依賴hello的,所以當執行world後,先去執行了hello任務,再執行world任務。dependsOn是Task類的一個方法,可以接受多個依賴的任務作爲參數。
修改以下程序:

task hello << {
   print 'hello\n'
}

task world(dependsOn: hello) {
   doLast {
       print 'world\n'
   }
}

world.doFirst {
   print 'doFirst\n'
}

world.doLast {
   print 'doLast2\n'
}

結果:

bogon:test_gradle mq$ gradle -q world
hello
doFirst
world
doLast2

通過結果可以看出,doFirst和doLast可以使用多次,並且按順序執行。doLast可以用 << 操作符替代。

5、自定義屬性

Project和Task允許添加額外自定義屬性,通過對應的ext屬性即可,如

//自定義一個Project的屬性
ext.buildTime = '2018'

//自定義多個屬性
ext {
   buildTime = '2018'
   month = '12'
}

task time {
     doLast {
       print "構建時間${buildTime} 年${month}月 \n"
     }
}

執行gradle -q time,執行結果:

bogon:test_gradle mq$ gradle -q time
構建時間2018 年12月

可見我們自定義的屬性正確地取到了,自定義屬性的作用域很廣,只要能得到對應的Project,就能獲取到定義的屬性值。在Android中我們通常使用自定義屬性值來定義我們的版本號、版本名稱等,把這些放到一個單獨的gradle文件中,因爲他們在發版前就會變動,放到單獨的gradle文件中便於管理,在AS根目錄下新建config.gradle如下:

//config.gradle
ext {
      android = [
            compileSdkVersion: 26,
            buildToolsVersion: "25.0.0",
            versionName      : "6.2.1",
            versionCode      : 6210,
            minSdkVersion    : 16,
            targetSdkVersion : 23
      ]
    }

在APP對應的build.gradle中取值:

//build.gradle
apply from: rootProject.getRootDir().getAbsolutePath() + '/config.gradle'

compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion

就可以獲取到自定義的屬性值。

上例中,除了能獲取到config.gradle中的屬性值,還可以在builg.gradle中調用config.gradle中的方法,具體實現:

//config.gradle
ext {
    .......其他.........
    //注意方法和屬性寫法的區別
    copyApk = this.&copyApk
}

def copyApk() {

}

在build.gradle調用:

//build.gradle
apply from: rootProject.getRootDir().getAbsolutePath() + '/config.gradle'

copyApk()

這樣就實現了在build.gradle中調用config.gradle中的copyApk()方法了。

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