Gradle基本知識點與經常使用配置

原文地址:http://blog.csdn.net/u0108184...

本文篇幅較長,文中系統地講解了Gradle的基本知識點以及一些經常使用的命令和配置,適合於剛接觸Gradle的同窗;html

在此基礎上,能夠閱讀如下的實戰經驗文章:java

《Gradle實戰:Android批量打包》
《Gradle實戰:不一樣編譯類型的包同設備共存》
《Gradle實戰:發佈aar包到maven倉庫》
《Gradle實戰:執行sql操做hive數據庫》android


1、基本概念

1. Groovy

Domain Specific Language,領域相關語言。

2. Gradle

Gradle是一個框架,它負責定義流程和規則;
每個待編譯的工程都叫一個Project;
每個Project在構建的時候都包含一系列的Task。

3. Closure

Closure(閉包)是一段單獨的代碼塊,它能夠接收參數,返回值,也能夠被賦值給變量:sql

4. Property

Gradle在默認狀況下已經爲Project定義了不少Property,以下:shell

  • project:Project自己數據庫

  • name:Project的名字json

  • path:Project的絕對路徑api

  • description:Project的描述信息服務器

  • buildDir:Project構建結果存放目錄閉包

  • version:Project的版本號

4.1 經過ext來自定義Property:

ext.property1 = "this is property1"
    
    或
    
    ext {
       property2 = "this is property2"
    }
    
    task showProperties << {
       println property1  //直接訪問
       println property2
    }

任何實現了ExtensionAware接口的Gradle對象均可以經過這種方式來添加額外的Property,好比Task也實現了該接口。

4.2 經過「-p」命令行參數定義Property:

task showCommandLineProperties << {
       println propertyTest
    }
    
    gradle -P propertyTest ="this is propertyTest" showCommandLineProperties

4.3 經過JVM系統參數定義Property(須要以「org.gradle.project」爲前綴):

gradle -D org.gradle.project.propertyTest="this is another propertyTest" showCommandLineProperties
    
    另外一種方式:
    
    寫入參數:gradle -DpropertyTest="this is another propertyTest"
    讀取參數:def propertyTest = System.properties['propertyTest']

4.4 經過環境變量設置Property(須要以「ORG_ GRADLE_ PROJECT_ 」爲前綴):

export ORG_GRADLE_PROJECT_propertyTest = "this is yet another propertyTest"
    
    gradle showCommandLineProperties

5. Bean

Groovy會爲每個字段自動生成getter和setter,咱們能夠經過像訪問字段自己同樣調用getter和setter,如:

class GroovyBeanExample {
        private String name
    }

6. delegate

delegate機制可使咱們將一個閉包中的執行代碼的做用對象設置成任意其餘對象

class Child {
        private String name
    }

7. task

task有兩個生命週期,配置階段和執行階段

gradle在執行task時,都會先對task進行配置,task中最頂層的代碼就是配置代碼,在配置階段執行,其餘代碼實在執行階段執行的;
task關鍵字其實是一個方法調用,咱們不用將參數放在括號裏面。
    task Task1 {
        println "hello」 // 這段代碼是在配置階段執行的
    }

    task Task2 {
        def name = "hello」 // 這段代碼是在配置階段執行的
        doLast {
            println name  
        } // 這段代碼是在執行階段執行的,至關於:
        
        // doLast({
        //      println 'Hello world!'
        //  })
    }

    task Task3 << {
        println name
    }
    // 「<<」語法糖,表示追加執行過程,至關於doLast,所以整個代碼都是在執行階段執行的;與之相反的是doFirst。
    //若是代碼沒有加「<<」,則這個任務在腳本initialization的時候執行(也就是你不管執行什麼任務,這個任務都會被執行,「hello」都會被輸出);
    //若是加了「<<」,則在輸入命令gradle Task3後才執行

經過TaskContainer的create()方法建立Task

8. 自定義task

class HelloWorldTask extends DefaultTask {
        @Optional
        String message = 'I am davenkin'
    
        @TaskAction
        def hello(){
            println "hello world $message"
        }
    }
    
    task hello(type:HelloWorldTask)
    
    task hello1(type:HelloWorldTask){
       message ="I am a programmer"
    }

@TaskAction表示該Task要執行的動做,@Optional表示在配置該Task時,message是可選的

9. 任務配置

方法一:在定義Task的時候對Property進行配置

task hello1 << {
        description = "this is hello1"
        println description
    }

方法二:經過閉包的方式來配置一個已有的Task

task hello2 << {
        println description
    }
    
    hello2 {
        description = "this is hello2"
    } //Gradle會爲每個task建立一個同名的方法,該方法接受一個閉包
    
    或
    
    hello2.description = "this is hello2"//Gradle會爲每個task建立一個同名的Property,因此能夠將該Task看成Property來訪問

注:對hello2的description的設置發生在定義該Task以後,在執行gradle hello2時,命令行依然能夠打印出正確的「this is hello2」,這是由於Gradle在執行Task時分爲兩個階段:配置階段、執行階段。
因此在執行hello2以前,Gradle會掃描整個build.gradle文檔,將hello2的description設置爲「this is hello2」,再執行hello2。

方法三:經過Task的configure()方法完成Property的設置

task hello3 << {
        println description
    }

10. 任務依賴

task A << {
        println 'Hello from A'
    }
    task B << {
        println 'Hello from B'
    }
    B.dependsOn A
    
    或
    
    task A << {
        println 'Hello from A'
    }
    task B {
        dependsOn A
        doLast {
            println 'Hello from B'  
        }
    }
    
    或
    
    task B(dependsOn: A) {
       println 'Hello from B'
    }

11. 順序執行

指之間無依賴關係的任務

task unit << {
        println 'Hello from unit tests'
    }
    task ui << {
        println 'Hello from UI tests'
    }
    task tests << {
        println 'Hello from all tests!'
    }
    task mergeReports << {
        println 'Merging test reports'
    }

12. 增量式構建

爲一個Task定義輸入(inputs)和輸出(outputs),在執行該Task時,若是它的輸入和輸出與前一次執行時沒有變化,那麼Gradle便會認爲該Task是最新的(日誌會輸出「UP-TO-DATE「),所以不會重複執行

task combineFileContent {
       def sources = fileTree('sourceDir')
       def destination = file('destination.txt')
    
       inputs.dir sources        // 將sources聲明爲該Task的inputs
       outputs.file destination  // 將destination聲明爲outputs
    
       doLast {
          destination.withPrintWriter { writer ->
             sources.each {source ->
                writer.println source.text
             }
          }
       }
    }

當首次執行combineFileContent時,Gradle會完整地執行該Task,可是緊接着再執行一次,命令行顯示:

:combineFileContent UP-TO-DATE //被標記爲UP-TO-DATE,表示該Task是最新的,不執行
    BUILD SUCCESSFUL
    Total time: 2.104 secs

若是修改inputs(上述即sourceDir文件夾)中的任何一個文件或刪除destination.txt,再次調用「gradle combineFileContent」時,該Task又會從新執行

13. 自定義Plugin

在當前工程中的buildSrc/src/main/groovy/davenkin目錄下建立DateAndTimePlugin.groovy文件和DateAndTimePluginExtension.groovy文件

// DateAndTimePlugin.groovy
    
    package com.gradle.test

    import org.gradle.api.Plugin
    import org.gradle.api.Project
    
    class DateAndTimePlugin implements Plugin<Project> {
        void apply(Project project) {
            
            //每一個Gradle的Project都維護了一個ExtenionContainer,咱們能夠經過project.extentions訪問額外的Property和定義額外的Property
            project.extensions.create("dateAndTime", DateAndTimePluginExtension) 
    
            project.task('showTime') << {
                println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
            }
    
            project.tasks.create('showDate') << {
                println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
            }
        }
    }
    
    // DateAndTimePlugin.groovy
    
    package com.gradle.test

    class DateAndTimePluginExtension {
        String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
        String dateFormat = "yyyy-MM-dd"
    }

build.gradle文件中,再apply該Plugin

apply plugin: com.gradle.test.DateAndTimePlugin

    // 能夠經過如下方式對這兩個Property進行從新配置
    dateAndTime {
        timeFormat = 'HH:mm:ss.SSS'
        dateFormat = 'MM/dd/yyyy'
    }

2、經常使用命令和配置

1. 編譯、打包

注:執行「./gradlew xxx」等同於執行「gradle xxx」,但執行「gradle xxx」需配置環境變量

1.1 清除build文件夾

./gradlew clean

1.2 檢查依賴並編譯打包

./gradlew build

1.3 編譯並打Debug包

./gradlew assembleDebug

1.4 編譯並打Release包

./gradlew assembleRelease

1.5 獲取gradle版本號

./gradlew -v

1.6 查看全部任務

./gradlew tasks 或 gradle tasks

1.7 查看全部工程

gradle projects

1.8 查看全部屬性

gradle properties

2. 經常使用任務

2.1 執行任務

task A << {
        println 'Hello from A'
    }
    終端輸入:gradle A

2.2 拷貝

task copyFile(type: Copy) {
       from 'source'
       into 'destination'
    }
    將source文件夾中的全部內容拷貝到destination文件夾中,
    這兩個文件夾都是相對於當前Project而言的,即build.gradle文件所在的目錄

2.3 刪除文件或文件夾

task deleteTest(type: Delete) {
        delete 'file' ,'dir'
    }
    文件和文件夾是相對於當前Project而言的,即build.gradle文件所在的目錄

2.4 執行shell命令

task runShell1(type: Exec) {
        executable "sh"
        args "-c", "rm ./app/libs/test.jar" //路徑是相對於當前build.gradle文件
    }
    
    或者
    
    def cmd = 'date +%Y-%m-%d'
    task shellTest << {
        String date = cmd.execute().text.trim().toString() //帶返回值
        print  date //打印系統日期
    }

2.5 執行java代碼

task runJava(type: JavaExec) {
        classpath = sourceSets.main.runtimeClasspath  //執行文件所在路徑
        main = 'com.example.MyClass' // 執行方法所在類
        // arguments to pass to the application
        args 'haha','xixi' //多個參數用逗號隔開
    }

2.6 生成jar包

方法一:
    task deleteDes(type: Delete) {
        delete 'build/intermediates/bundles/release/class.jar', 'libs/mylib.jar'
    }

    task makeJar(type: Copy) {
        from('build/intermediates/bundles/release/') {
            include '*.jar' // 只拷貝jar格式的文件
        }
        into('libs')
        //include('classes.jar') // 只拷貝classes.jar這個文件
        rename('classes.jar', 'mylib.jar') // 重命名爲mylib.jar
    }

    task releaseLib(type: Copy, dependsOn: [deleteDes, build, makeJar]) {  // 依賴多個任務
        into "../app/libs"
        from 'libs'
    }
    // 手動打包,gradle releaseLib

    方法二:
    // 如下是在編譯流程中插入生成jar包的task
    android.libraryVariants.all { variant ->
        variant.outputs.each { output ->
            def file = output.outputFile
            def fileName = 'classes.jar'
            def name = variant.buildType.name
    
            task "makeJar${variant.name.capitalize()}" << {
                copy {
                    from("${projectDir}/build/intermediates/bundles/"+"${name}") {
                        include(fileName)
                    }
                    into(file.parent) // 可自定義存放路徑
                    rename (fileName, "${project.name}"+"-${name}.jar")
                }
            }
        }
    
    }
    
    project.tasks.whenTaskAdded { task ->
        android.libraryVariants.all { variant ->
            if (task.name == "bundle${variant.name.capitalize()}") {
                task.finalizedBy "makeJar${variant.name.capitalize()}"
            }
        }
    }

2.7 文件讀取

//以讀取properties文件中保存的簽名信息爲例
    
    def File propFile = new File('signing.properties')
    if (propFile.canRead()) {
        def Properties props = new Properties()
        props.load(new FileInputStream(propFile))
    
        if (props != null && props.containsKey('RELEASE_STORE_FILE') && props.containsKey('RELEASE_STORE_PASSWORD') &&
                props.containsKey('RELEASE_KEY_ALIAS') && props.containsKey('RELEASE_KEY_PASSWORD')) {
    
            android.signingConfigs.release.storeFile = file(props['RELEASE_STORE_FILE'])
            android.signingConfigs.release.storePassword = props['RELEASE_STORE_PASSWORD']
            android.signingConfigs.release.keyAlias = props['RELEASE_KEY_ALIAS']
            android.signingConfigs.release.keyPassword = props['RELEASE_KEY_PASSWORD']
            println 'all good to go'
        } else {
            android.buildTypes.release.signingConfig = null
            println 'signing.properties found but some entries are missing'
        }
    } else {
        println 'signing.properties not found'
        android.buildTypes.release.signingConfig = null
    }

3. 經常使用配置

3.1 設置全局參數(同額外屬性設置)

ext {
        compileSdkVersion = 22
        buildToolsVersion = "22.0.1"
    }
    
    在module中引用全局參數:
    android {
        compileSdkVersion rootProject.ext.compileSdkVersion
        buildToolsVersion rootProject.ext.buildToolsVersion
    }

將屬性或方法放入ext{}就能夠被全局引用

3.2 設置全局編碼

allprojects {
        tasks.withType(JavaCompile) {
            options.encoding = "UTF-8"
        }
    }

3.3 設置全局編譯器的版本

allprojects {
        tasks.withType(JavaCompile) {
            sourceCompatibility = JavaVersion.VERSION_1_7
            targetCompatibility = JavaVersion.VERSION_1_7
        }
    }

3.4 去掉重複依賴

compile 'com.alibaba.fastjson.latest.integration' { //latest.integration 獲取服務器上最新版本
          exclude module: 'annotations', group: 'com.google.android'
    }

3.5 本地aar包依賴

allprojects {
       repositories {
          jcenter()
          flatDir {
            dirs 'libs'
          }
       }
    }
    
    dependencies {
        compile(name:'本地庫aar的名字,不帶後綴', ext:'aar')
    }

4. java Plugin

Gradle的每一個source set都包含有一個名字,而且包含有一個名爲java的Property和一個名爲resources的Property,他們分別用於表示該source set所包含的Java源文件集合和資源文件集合。在實際應用時,咱們能夠將他們設置成任何目錄值,如下將資源文件按功能分包,使得與java文件分包保持一致

sourceSets {
    main {
        manifest.srcFile 'src/main/AndroidManifest.xml'
        java.srcDirs = ['src/main/java','.apt_generated']
        aidl.srcDirs = ['src/main/aidl','.apt_generated']
        assets.srcDirs = ['src/main/assets']
        res.srcDirs =
                [
                        'src/main/res/bindmobile', //綁定手機資源
                        'src/main/res/bycaptcha',  //驗證碼登陸資源
                        'src/main/res/bypwd',      //密碼登陸資源
                        'src/main/res/pwdmodify',  //密碼修改資源
                        'src/main/res/pwdreset',   //密碼重置資源
                        'src/main/res/resource',   //其餘資源
                        'src/main/res/'

                ]
    }
}

3、配置gradle,加快編譯速度

1. 配置「.gradle」中的「gradle.properties」

cd ~/.gradle/gradle.properties //添加以下配置(沒有該文件則新建一個):
    org.gradle.daemon=true //獨立進程,中止後臺進程命令:gradle --stop
    org.gradle.parallel=true //並行構建,須要將項目拆分紅多個子項目,經過aar引用才能起效
    org.gradle.configureondemand=true //按需配置,目前還在試驗孵化階段,默認是關閉的

2. 設置離線編譯

打開settings->Build,Execution,Deployment->Build Tools->Gradle,
    選中Offlie Work //更新依賴包時要取消它

3. 命令行構建

在命令後面加上以下參數

--daemon 
    --parallel
    --offline
    --dry-run

深刻學習

相關文章
相關標籤/搜索