Android Gradle(三)- gradle

上一篇對groovy語法與核心api做了簡單總結,為gradle具體業(yè)務功能實現(xiàn)做了語言鋪墊,那么接下來進入到gradle api的學習。

一、gradle生命周期

gradle生命周期分為三個階段:
Initialization初始化階段: 各工程初始化,解析settings.gradle,構建所有project對應的project對象。
Configuration配置階段: 執(zhí)行所有工程中build.gradle的配置代碼,解析所有project對象中的task,構建task的拓撲圖。Task的執(zhí)行順序在配置階段就確定好了。
Execution執(zhí)行階段: 執(zhí)行task及其依賴task。

gradle部分生命周期監(jiān)聽回調

//配置階段開始前的監(jiān)聽回調
this.beforeEvaluate {
}

//配置階段完成以后的回調
this.afterEvaluate {
}

//當前project build完成
this.gradle.buildFinished {
}

//project構建之前
this.gradle.beforeProject {
}

//project構建之后
this.gradle.afterProject {
}

//其他監(jiān)聽
this.gradle.addBuildListener(new BuildListener() {
    @Override
   void buildStarted(Gradle gradle) {
    }

    @Override
   void settingsEvaluated(Settings settings) {
    }

    @Override
   void projectsLoaded(Gradle gradle) {
    }

    @Override
   void projectsEvaluated(Gradle gradle) {
    }

    @Override
   void buildFinished(BuildResult result) {
    }
})
二、 project

gradle-5.4.1/src/core-api/org/gradle/api/Project.java
gradle中根工程和各module對應一個project,它是腳本入口。

project相關api
this.getProject() or this.project//獲取project
this.getRootProject() or this.rootProject//獲取根project
this.getSubprojects() or this.subprojects//獲取所有子project 根project獲取的子project即各個module
this.getParent() or this.parent//獲取父project

在build.gradle中方法的定義及調用
this.helloGradle()

def helloGradle() {
    def allprojects = this.getAllprojects()
    allprojects.each { project ->
        println 'project name :' + project.name
   }
}

//對app project 進行配置
project('app') { Project project ->
   apply plugin: ‘...'
   group ‘...'
   version ‘...'
   dependencies {...}
   android {…}
   ...
}
屬性相關api

Project自帶屬性

public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
    /**
    * The default project build file name.
    */
   String DEFAULT_BUILD_FILE = "build.gradle";
  
 /**
    * The hierarchy separator for project and task path names.
    */
   String PATH_SEPARATOR = ":";

   /**
    * The default build directory name.
    */
   String DEFAULT_BUILD_DIR_NAME = "build";
   String GRADLE_PROPERTIES = "gradle.properties";
   String SYSTEM_PROP_PREFIX = "systemProp";
   String DEFAULT_VERSION = "unspecified";
   String DEFAULT_STATUS = "release";
}

//使用ext閉包拓展屬性
ext {
    compileSdkVersion = 29
}
//這里修改compileSdkVersion為例
Android{
    compileSdkVersion [this.project.compileSdkVersion](http://this.project.compilesdkversion/)
}

//在gradle中引入文件
apply from :this.file('common.gradle’)

//在gradle中引入插件
apply plugin:'gradle-plugin’

//property基本操作
getProperty(‘')
setProperty('')
hasProperty(‘')

另外還可以在gradle.properties中配置 key - value形式的全局屬性
#key-value
isLoadTest=true
# 這里可以以key-value的形式定義全局的屬性,使用的時候需要用toBoolean() toInteger()等轉換
# 另外屬性命名不能與已有方法重名,這樣容易找不到屬性

//三方庫引入方式對比
2.X
compile: 編譯運行期都參與。
provided: 編譯期參與,運行時不參與
3.0之后:
compile 延伸出api 和 implementation。
api : 與compile效果一樣。
implementation : implementation依賴的庫只能自己庫本身訪問,例如:A依賴B,B依賴C,如果B依賴C是使用的implementation依賴,那么在A中是訪問不到C 中的方法的,如果需要訪問,請使用api依賴。其他與compile一致。
compileOnly: 與provided效果一樣。
其他:
runtimeOnly: 和apk效果一樣,打包時有效,不參與編譯。
testImplementation:和testCompile效果一樣,在單元測試和打包測試apk的時候有效。
debugImplementation:和debugCompile效果相同, 在debug模式下有效。
releaseImplementation:和releaseCompile效果相同,只在release模式和打包release包情況下有效。
文件相關api

路徑:

//工程根目錄
getRootDir().absolutePath //or this.rootDir

//工程目錄/build
getBuildDir().absolutePath //or this.buildDir

//module目錄
getProjectDir().absolutePath //or this.projectDir

//獲取文件
getFile('build.gradle')
def getFile(String path) {
    try {
        //new file要傳入絕對路徑,file()傳入相對路徑,相對于當前project開始查找
       def file = file(path)//project的file方法獲取文件,files方法定位多個符合條件文件
       return file.text
   } catch (GradleException e) {
        println 'file not found'
   }
    return null
}

//文件拷貝 from into
copy {
    from file('build/outputs/apk/')
    into getRootProject().getBuildDir().path + '/apk/'
   //附加功能
   exclude {} //包含
   rename {} //重命名
}

//對文件樹進行遍歷
fileTree('build/outputs/apk/') { FileTree filetree ->
    filetree.visit { FileTreeElement element ->
        println 'the file name is:' + element.file.name
       copy {
            from element.file
           into getRootProject().getBuildDir().path + 'test'
       }
    }
}
其他
buildscript { ScriptHandler scriptHandler ->
    //gradle本身配置工程的倉庫地址
   scriptHandler.repositories {}
    //gradle本身配置工程的三方庫依賴地址
   scriptHandler.dependencies {}
    //對應project中的dependencies,是配置應用程序三方庫的依賴
}
三、task

gradle-5.4.1/src/core-api/org/gradle/api/Task.java
一個Task表示構建的單個原子動作。構建工作就是由各種Task構成的。

新建task兩種寫法:
//用task函數(shù)創(chuàng)建
task myTask {
    println 'hello task'
}

//使用taskContainer容器創(chuàng)建
this.tasks.create(name: 'myTask') {
    println 'hello task'
}

task所有可配置信息
public interface Task extends Comparable<Task>, ExtensionAware {
   String TASK_NAME = "name";
   String TASK_DESCRIPTION = "description";
   String TASK_GROUP = "group";
   String TASK_TYPE = "type";
   String TASK_DEPENDS_ON = "dependsOn";
   String TASK_OVERWRITE = "overwrite";
   String TASK_ACTION = "action";
...
}

task在執(zhí)行階段的兩個回調:
doFirst{}//在已有的task之前去添加邏輯
doLast{}//在已有的task之后去添加邏輯

調用方式:
task myTask {
    doLast{ //內部調用
    }
}
//or
myTask.doLast{ //外部調用
}

小實例:計算prebuild到build的總時長
def startTime, endTime
//配置階段執(zhí)行完以后
this.afterEvaluate { Project project ->
    //保證要找的task配置完成
   def preBuildTask = project.tasks.getByName('preBuild')
    preBuildTask.doFirst {
        startTime = System.currentTimeMillis()
    }

    def buildTask = project.tasks.getByName('build')
    buildTask.doLast {
        endTime = System.currentTimeMillis()
        println "the build time is  ${endTime - startTime}"
   }
}

gradle在配置階段會構建task的拓撲圖,這個過程組織好task的執(zhí)行順序
task依賴

dependsOn配置依賴

task taskX {
   doLast {
       println 'taskX'
   }
}

靜態(tài)配置
//taskY在taskX之后執(zhí)行
task taskY(dependsOn:taskX) {
   doLast {
       println 'taskY'
   }
}

//or
task taskY {
    dependsOn taskX
    doLast {
        println 'taskY'
   }
}

//or
taskY.dependsOn taskX

指定依賴之后,執(zhí)行taskY,會先執(zhí)行它依賴的taskX ,然后執(zhí)行它自己。

動態(tài)配置
task taskZ() {
    dependsOn this.tasks.findAll { task ->
        return task.name.startsWith('lib')//動態(tài)依賴lib開頭的task
   }
    doLast {
        println 'taskZ'
   }
}
task執(zhí)行順序

mustRunAfter()、shouldRunAfter()
只指定順序執(zhí)行,沒有依賴關系。

task taskZ {
   mustRunAfter taskX //強制task在指定的task之后執(zhí)行
   shouldRunAfter taskX //不強制性的
   doLast {
        println 'taskZ'
   }
}

如果單獨執(zhí)行taskZ,那么就只會執(zhí)行taskZ,跟taskX和taskY無關,只有taskX、taskY、taskZ都執(zhí)行的時候,這個條件能約束執(zhí)行順序。

finalizedBy

taskX.finalizedBy taskY //執(zhí)行完taskX之后會拉起執(zhí)行taskY

總結:dependsOn指定依賴關系,先執(zhí)行依賴的task再執(zhí)行自己;finalizedBy是當前task執(zhí)行完成拉起讓自己結束的task;而mustRunAfter是多個執(zhí)行的task之前約束一個執(zhí)行順序,默認情況下無依賴關系的task執(zhí)行順序是隨機的。

task輸入輸出

TaskInputs、TaskOutputs

輸入輸出在Gradle中用于增量構建,執(zhí)行一個任務,如果在編譯時,gradle判斷在從上一次編譯中,該task的輸入輸出沒有任何改變,那么gradle就會跳過該task,前提是這個task至少有一個輸入或輸出。

支持的輸入輸出類型參考TaskInputs接口
inputs.file/files/property
outputs.file/files

四、Settings

在gradle中,通過執(zhí)行Settings類來完成構建的初始化階段。
最重要的是inlcude方法

include ':app', ':lib_network’ //配置工程子project
rootProject.name = ‘GradleDemo'

這里可以做條件判斷是否引入子project
if (hasProperty('isLoadTest') ? isLoadTest.toBoolean() : false) {
    include ':Test'
}

對應兩個監(jiān)聽
gradle.settingsEvaluated {
   println “Settings.gradle 初始化執(zhí)行結束"
}

gradle.projectsLoaded {Gradle gradle ->
   println “Settings.gradle所有在 settings 中 include 的 Project 對象都創(chuàng)建完成了"
}
五、SourceSet
//5.4.1版本配置方法
android {
    sourceSets {
        // sourceSets的main對象,該對象屬于默認對象。
        main {
            resources {
                srcDirs 'src/main/res', 'src/main/res-ad', 'src/main/res-player'
           }
        }
    }
}

//3.0版本配置方法
// 配置源碼路徑。這個sourceSets是java插件引入的
sourceSets {
   // 還可以根據(jù)productFlavors中的其他渠道配置對應的sourceSets對象。編譯時,會首先加載對應productFlavors中的資源,沒有則加載main中默認資源。
   main {
        manifest.srcFile 'AndroidManifest.xml'// 這是一個函數(shù)
       java.srcDirs = ['src']
        resources.srcDirs = ['src']
        aidl.srcDirs = ['src']
        renderscript.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
        jniLibs.srcDirs = ['libs']
    }

groovy和gradle文章寫下來,基本是代碼的形式,可能閱讀并不是那么直觀,但是這個比較符合我的習慣。方便查詢吧。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者。

相關閱讀更多精彩內容

友情鏈接更多精彩內容