在上一篇文章中 Gradle 之语言基础 Groovy 主要介绍了 Groovy 的基础语法(如果没有 Groovy 的基础,建议先看看上篇文章,如果可以动手敲一下里面的示例代码就更好不过了),也是为本篇文章打基础的。

本篇文章主要介绍 Gradle 在 Android 中的应用(Android DSL 和 Gradle DSL),也是通过一些示例来介绍和理解,主要分为以下一些内容,示例代码都在 GradleForAndroid

原文在此:Gradle 之 Android 中的应用

一. Gradle 构建生命周期

一个 Gradle 的构建通常有如下三个阶段

  • 初始化:项目 Project 实例会在该阶段被创建。如果一个项目中包含有多个模块,并且每一个模块都有其对应的 build.gradle 文件,就会为每一个模块都创建一个对应的 Project 实例
  • 配置:执行各个模块下的 build.gradle 脚本,为 Project实例创建和配置 Task,构造 Task 任务依赖关系图以便在执行阶段按照依赖关系执行 Task
  • 执行:在这个阶段将会决定执行哪个 Task,哪个 Task 被执行取决于开始该次构建的参数配置和该 Gradle 文件的当前目录

在创建完成一个新的 Android 应用项目之后,一般情况下, .gradle 文件的目录结构如下所示:

GradleForAndroid|---- build.gradle|---- setting.gradle\---- app\---- build.gradle
复制代码

其中,两个文件 build.gradlesetting.gradle 位于项目的根目录下,还有一个 build.gradle 位于 \app\ 目录下。\build.gradle 是顶层构建文件,\app\build.gradle 是模块构建文件。 我们以上面这个新创建的项目来学习 Gradle 的构建生命周期

1.1 初始化

  1. 在初始化阶段,会创建一个 Setting 对象,对应着 setting.gradle 文件, Setting 对象的一个主要作用就是声明哪些模块将会参与到构建中去,Setting 文档(Gradle API 5.0)

  2. 在新建的项目中,setting.gradle 文件一般会默认包含一行内容,如下所示

    include ':app'
    复制代码

    上面这一行,其实是一行 groovy 代码的简写,对应的是 Setting#include(String[] projectPaths) 方法,表示 :app 模块将会参与到构建中去。 如果我们创建一个 library 库,setting.gradle 将会变为如下所示,表示 :app:library 两个模块将会参与到构建中

    include ':app', ':library'
    复制代码
  3. setting.gradle 脚本文件可以中读取一些只可读的配置信息,这些配置信息的来源可以有如下三个:

    • 可以在本工程的 gradle.properties 文件中定义配置信息
    • 也可以在系统的 gradle.properties 文件中定义配置信息,系统的 gradle.properties 位于 user's .gradle 目录下
    • 还可以通过 -P 命令参数指定配置信息,比如 ./gradlew clean -P cmd='Hello from commandLine' 便在执行 clean task 的时候,指定了 cmd='Hello from commandLine' 配置信息
  4. 上面讲到,一个 setting.gradle 文件对应着一个 Setting 对象,Setting 对象包含的方法如下图所示

    例如有如下代码

    include ':app', ':library'println propertiesFile
    println DEFAULT_SETTINGS_FILE
    println getRootProject().name
    println getRootProject().pathgetGradle().addBuildListener(new BuildListener() {@Overridevoid buildStarted(Gradle gradle) {println 'buildStarted'}@Overridevoid settingsEvaluated(Settings settings) {println "settingsEvaluated"}@Overridevoid projectsLoaded(Gradle gradle) {println 'projectsLoaded'}@Overridevoid projectsEvaluated(Gradle gradle) {println 'projectsEvaluated'}@Overridevoid buildFinished(BuildResult result) {println 'buildFinished'}
    })
    复制代码

    其输出是:

    Hello from gradle.properties
    settings.gradle
    GradleForAndroid
    :
    settingsEvaluated
    projectsLoaded
    projectsEvaluatedBUILD SUCCESSFUL in 0s
    3 actionable tasks: 3 executed
    buildFinished
    复制代码

1.2 配置

  1. 在配置阶段,会执行所有的 build.gradle,包括项目根目录下的 build.gradle 和各个 module 下的 build.gradle
  2. 在执行 build.gradle 的时候,会为每个 build.gradle 创建一个对应的 Project 对象,Project 文档(Gradle API 5.0)
  3. 配置阶段会执行 build.gradle 里面的所有代码和 Task 里面的配置代码,比如下面的 printProperties Task,只执行了 doLast{} 之外的代码,doLast{} 之外的代码是 Task 的配置代码
  4. 配置执行完成之后,会根据各个 Task 的依赖关系生成一个有向无环图,可以通过Gradle对象的getTaskGraph方法访问,对应的类为TaskExecutionGraph
  5. 在执行所有的 Gradle Task 之前,都会执行 初始化阶段配置阶段 的代码
  6. 比如有如下代码
    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    println "/build.gradle 开始配置"
    buildscript {println "/build.gradle buildscript 开始配置"ext.kotlin_version = '1.2.71'repositories {google()jcenter()}dependencies {classpath 'com.android.tools.build:gradle:3.0.1'classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"// NOTE: Do not place your application dependencies here; they belong// in the individual module build.gradle files}println "/build.gradle buildscript 结束配置"
    }allprojects {println "/build.gradle allprojects 开始配置"repositories {google()jcenter()}println "/build.gradle allprojects 结束配置"
    }  task clean(type: Delete) {delete rootProject.buildDir
    }ext {local = 'Hello from build.gradle'
    }task printProperties {println "/build.gradle task printProperties 开始配置"println '/build.gradle task printProperties'println "/build.gradle task printProperties 结束配置"doLast {println localprintln propertiesFileif (project.hasProperty('cmd')) {println cmd}}
    }
    println "/build.gradle 结束配置"
    复制代码

    在 Terminal 里面执行 ./gradlew clean 会有如下输出

    Hello from gradle.properties
    settings.gradle
    GradleForAndroid
    :
    settingsEvaluated
    projectsLoaded// 配置阶段,执行 /build.gradle 里面的代码
    > Configure project :
    /build.gradle buildscript 开始配置
    /build.gradle buildscript 结束配置
    /build.gradle 开始配置
    /build.gradle allprojects 开始配置
    /build.gradle allprojects 结束配置
    /build.gradle allprojects 开始配置
    /build.gradle allprojects 结束配置
    /build.gradle allprojects 开始配置
    /build.gradle allprojects 结束配置
    /build.gradle task printProperties 开始配置
    /build.gradle task printProperties
    /build.gradle task printProperties 结束配置
    /build.gradle 结束配置projectsEvaluatedBUILD SUCCESSFUL in 0s
    3 actionable tasks: 3 executed
    buildFinished
    复制代码

1.3 执行

执行阶段就是指执行某个具体的任务 Task。说道 Task,我想大家应该比较熟悉,在 Android 项目中依赖了 Android Gradle 插件以后,会有许多自带的 Task,比如常用的 cleanassemble 等,而且大家更应该掌握的是如何自定义 Task,关于 Task 会单独抽一节来讲述。

二. 自定义 Task

  1. 任务 Task 代表了在构建过程中的一个单原子性的动作,比如:编程生成 .class 文件或者生成 javadoc 等.
  2. 每一个 task 都是属于某一个 Project 对象的,每一个 task 都有自己的名字,在 projecttask 的名字是唯一的,如果在整个项目 projects 范围内需要指定某个 task 的话,也需要指定 project 的名字,projecttask 的名字中间使用 : 相连接,比如:./gradlew :app:clean
  3. 创建 Task 对象的方法有以下几种
    // 通过 TaskContainer.create(String) 创建 `Task`
    getTasks().create('helloTask') {doLast {println 'create Task by TaskContainer'}
    }task helloTask1 {doLast {println 'create Task by task(String name)'}
    }class HelloTask extends DefaultTask {def message = 'create Task by extends DefaultTask'@TaskActiondef hello() {println message}
    }
    // 通过 type 参数可以指定该 task 的父类,默认的父类是 DefaultTask
    task helloTask2(type: HelloTask)
    复制代码
  4. 一个 Task 是由一系列的 Action 组成的,当一个 Task 执行的时候就是按照一定的顺序执行这些 Action,可以有以下两种方式向 Task 中添加 Action
    • 通过闭包 Closure 的方式添加 Action

      class HelloTask extends DefaultTask {def message = 'create Task by extends DefaultTask'@TaskActiondef hello() {println message}
      }task helloTask2(type: HelloTask) {doFirst {println 'helloTask2 doFirst'}doLast {println 'helloTask2 doLast'}
      }
      复制代码
    • 直接添加 Action 实例对象
      def taskDef = task helloTask3(type: HelloTask)
      taskDef.doFirst(new Action<Task>() {@Overridevoid execute(Task task) {println 'helloTask3 Action execute doFirst'}
      })
      taskDef.doLast(new Action<Task>() {@Overridevoid execute(Task task) {println 'helloTask3 Action execute doLast'}
      })
      复制代码
  5. Task 依赖关系 & Task 执行顺序 在 Task 中有两个很重要的概念 dependsOnmustRunAfterdependsOn 用于声明两个 Task 对象之间的依赖关系,mustRunAfter 用于声明一个 Task 必须在另一个 Task 之后运行,虽然感觉差不多,但是实际上还是有区别的
    • helloTaskB.dependsOn(helloTaskA) 中,可以单独运行 helloTaskA,但是运行 helloTaskB 的时候会触发 helloTaskA 的执行
    • helloTaskC.mustRunAfter(helloTaskA)中,helloTaskAhelloTaskC 都是可以单独运行的,但是当 helloTaskChelloTaskA 同时运行时,helloTaskC 一定会在 helloTaskA 之后运行
    task helloTaskA {doFirst {println 'helloTaskA doFirst'}
    }task helloTaskB {doFirst {println 'helloTaskB doFirst'}
    }helloTaskB.dependsOn(helloTaskA)task helloTaskC {doFirst {println 'helloTaskC doFirst'}
    }helloTaskC.mustRunAfter(helloTaskA)
    复制代码
  6. Android 中使用自定义 Task 在 Gradle 构建的时候,需要将自定义的 Task 添加到构建过程中时,需要把握好添加自定义 Task 的时机与位置
    • 下面一幅图清晰地展示了 Gradle 构建过程中一些关键的回调,可以在下面一些回调中添加自定义 Task
    • project 对象中,可以通过 gradle 对象得到 TaskExecutionGraph 的实例对象,也可以通过 TaskExecutionGraph 实例对象一些关键回调添加自定义的 Task。比如下面这个例子,就是在 TaskExecutionGraph 实例对象准备好之后,弹出一个 dialog 用于输入 storePasskeyPass,然后将 storePasskeyPass 设置到 android.signingConfigs
    apply plugin: 'com.android.application'
    import groovy.swing.SwingBuilder//......gradle.taskGraph.whenReady { taskGraph ->if (taskGraph.hasTask(':app:assembleRelease')) {def storePass = ''def keyPass = ''if (System.console() == null) {System.setProperty('java.awt.headless', 'false')new SwingBuilder().edt {dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {vbox { // Put everything below each otherlabel(text: "Please enter store passphrase:")def input1 = passwordField()label(text: "Please enter key passphrase:")def input2 = passwordField()button(defaultButton: true, text: 'OK', actionPerformed: {storePass = input1.password;keyPass = input2.password;dispose();})}}}} else {storePass = System.console().readPassword("\nPlease enter store passphrase: ")keyPass = System.console().readPassword("\nPlease enter key passphrase: ")}if (storePass.size() <= 0 || keyPass.size() <= 0) {throw new InvalidUserDataException("You must enter the passwords to proceed.")}storePass = new String(storePass)keyPass = new String(keyPass)android.signingConfigs.release.storePassword = storePassandroid.signingConfigs.release.keyPassword = keyPass}
    }
    复制代码

如下图所示 TaskExecutionGraph 的方法结构如下图所示,都是非常实用方便的方法

三. Android DSL & Gradle DSL

3.1 Android DSL

Android DSL 是 Gradle 的一个 Android 插件,其实在使用 Android Studio 开发的时候经常会和 Android DSL 打交道,比如下面 android{ } 闭包 里面的内容都是 Android DSL

apply plugin: 'com.android.application'
import groovy.swing.SwingBuilderandroid {compileSdkVersion 27defaultConfig {applicationId "com.lijiankun24.gradleforandroid"minSdkVersion 15targetSdkVersion 27// ......}buildTypes {// ......}signingConfigs {// ......}
}
复制代码

至于里面都有哪些 API,可以去 Android DSL 文档 查看,也可以去 GitHub 上面搜 android-gradle-dsl

3.2 Gradle DSL

Gradle DSL 在上面介绍 Gradle 生命周期和自定义 Task 的时候已经介绍过了,比如上面介绍的 SettingTaskExecutionGraph 都是 Gradle DSL 中的类,其他的类和方法等 API 可以去 Gradle DSL 文档 查看,或者可以在 Android Studio 中像查看 Android SDK 源码一样去查看 Gradle DSL 的源码

Gradle 之 Android 中的应用相关推荐

  1. android中gradle的作用,Gradle 之 Android 中的应用

    在上一篇文章中 Gradle 之语言基础 Groovy 主要介绍了 Groovy 的基础语法(如果没有 Groovy 的基础,建议先看看上篇文章,如果可以动手敲一下里面的示例代码就更好不过了),也是为 ...

  2. Gradle在Android中的简单使用

    Gradle在Android中简单的使用 还望支持个人博客站:http://www.enjoytoday.cn Android Studio 使用gradle进行工程构建,为了更好的了解整个andro ...

  3. Gradle For Android系列4:创建Build Variants

    当你在开发一款应用时,通常会面临发布不同的版本需求.举两个常见的场景,场景一:你正在增加新功能,然后你需要发布版本提交给QA,测试通过后再发布线上版本,可能线下版本和测试版本的服务器接口域名不一样又或 ...

  4. 使用gradle构建android项目,Android中使用Gradle来构建App项目的入门指南

    gradle是Android开发中引入的全新的构建系统,因为全新的构建系统主要是出于下面的目的: 1. 方便复用代码和资源 2. 构建多种版本的apk更见简单,不论是为多渠道构建不同的apk还是构建不 ...

  5. Android中的Gradle之配置及构建优化

    一.Gradle简介 1.Gradle是什么? Gradle是一种项目自动化构建工具,基于Groovy语言来声明项目设置,同时支持kotlin文件xxx.gradle.kts作为DSL(Domain ...

  6. 【Android Gradle 插件】自定义 Gradle 插件优化图片 ① ( Android 中的 WebP 图片格式使用 | WebP 格式转换 | WebP 参考文档 )

    文章目录 一.Android 中的 WebP 图片格式使用 二.WebP 格式转换 三.WebP 参考文档 Android Plugin DSL Reference 参考文档 : Android St ...

  7. Android中清单文件引入配置参数,Android 使用gradle打包的各种配置

    原标题:Android 使用gradle打包的各种配置 在AS中利用gradle打包,可以高效并且自由地配置各种参数,发布不同的版本.关于配置gradle文件的一些做法,总结为如下. 一.替换Andr ...

  8. Android中导入项目编译时报错:Java home supplied via ‘org.gradle.java.home‘ is invalid. Invalid directory...

    编写不易,如有转载,请声明出处:http://blog.csdn.net/zxc514257857/article/details/73500775 报错内容 Error:Failed to comp ...

  9. Android中的网络(字节跳动)

    文章目录 RESTful API 对REST的解释 资源与URI 什么是URI HTTP URL的组成 Http 接口 JSON Http资源 XML JSON Android中对JSON的处理 方法 ...

最新文章

  1. 数字证书及网络加解密原理
  2. QT旋转按钮控件的实现
  3. web笔记Error:That IP address
  4. Oracle 之 用户与权限
  5. voip和rtc_为什么开发WebRTC与VoIP开发不一样?(上)
  6. matlab sdk7.1,免费试用MATLAB Compiler SDK
  7. java swt 布局_Java开发网 - 基于SWT的类XUL实现: SWT-XUI
  8. 60-130-336-源码-source-kafka相关-Flink读取kafka
  9. JavaScript之jQuery够用即可(事件委托、动画效果、扩展插件)
  10. 字符串的碎片整理。。。
  11. picasa csdn_如何将发送到Facebook的功能添加到Picasa
  12. 用74ls90组成二十四进制计数器_89c52定时计数器T2
  13. LayaBox---TypeScript---基础数据类型
  14. 打造自己的win10精简系统
  15. gps面积测量 java_GPS面积距离测量
  16. 嵌入式开发需要学习什么?
  17. 模拟实现图片长按保存功能
  18. Cinemachine 之简单的相机跟随
  19. oracle之schema
  20. Win32窗口程序实例

热门文章

  1. 每日学英语20040715
  2. C++ STACK Queue
  3. 体感Kinect手势识别开发基本原理
  4. 理解Java枚举类型
  5. 【旧文章搬运】Win7可变对象头结构之InfoMask解析
  6. 基本拖拽效果,使用 mousedown , mousemove , mouseup实现
  7. 【codeforces 796A】Buying A House
  8. DecimalFormat格式化输出带小数的数字类型
  9. (转)Android SharedPreferences的使用
  10. Fennec Alpha 1 for Windows Mobile available