Gradle是什么?我们先看官网里对Gradle的定义:
Gradle is an open-source build automation tool focused on flexibility and performance. Gradle build scripts are written using a Groovy or Kotlin DSL.
Gradle是专注于灵活性和性能的开源构建自动化工具。Gradle构建脚本是使用Groovy或Kotlin DSL 编写的
相关概念解释:
DSL:领域特定语言(domain-specific language)指的是专注于某个应用程序领域的计算机语言。
由上可知,Gradle是一款用来实现构建自动化的工具,使用Groovy和Kotlin作为其使用脚本语言。其中Groovy是Gradle为应对其需求开发,设计的一门特定的语言,即DSL。
Gradle构建过程本质是将其模型分解为task的有向无环图(DAG)。
所以构建实质上配置了一组任务,并根据它们的依赖关系将它们连接在一起以创建成DAG。创建任务图后,Gradle将确定需要按顺序运行的任务,然后继续执行它们。
这些Task既可以由插件定义,也可以由用户自己的构建脚本定义,任务通过任务依赖机制链接在一起。
下图显示了两个示例任务图,一个是抽象图,另一个是具体图,其中任务之间的依赖性表示为箭头
Gradle的自动化构建分为三大步骤:
Android Studio 利用Android Gradle Plugin 与Gradle搭配,完成管理和自动执行的构建流程,同时也允许用户自定义插件构建配置。
其中构建最重要的目的,就是将源代码和资源打包生成apk。
Android Gradle Plugin ,Gradle,用户自定义插件关系如下:
在我们新创建一个项目时,Android Studio 会自动创建其中的部分文件,并为其设定默认值。如下图
下面我们分析与Gradle配置相关的文件
a.settings.gradle
位置:位于项目的根目录
作用:指示 Gradle 在构建应用时应将哪些模块包含在内。
对大多数项目而言,该文件很简单,只包含以下内容:
include ‘:app’
b.根目录build.gradle
位置:位于项目的根目录下
作用:用于定义适用于项目中所有模块的构建配置。
默认情况下,根目录build.gradle使用 buildscript 代码块定义项目中所有模块共用的 Gradle 代码库和依赖项。以下代码示例说明了创建新项目后可在顶层 build.gradle 文件中的默认设置和代码
/**
* buildscript块是为Gradle本身配置存储库和依赖项的地方,
* 这意味着,不应该在这里包含模块的依赖项。
* 下面的代码中设置Gradle的Android插件作为依赖项,
* 它提供了Gradle构建Android应用程序模块所需的附加指令。
*/
buildscript {
/**
* repositories块配置Gradle用于搜索或下载依赖项的存储库。
* Gradle预先配置了对远程存储库(如JCenter、Maven Central和Ivy)的支持
* 你还可以使用本地存储库或定义自己的远程存储库。
* 下面的代码将JCenter定义为Gradle应该用来查找其依赖项的存储库。
*
* 使用androidstudio3.0及更高版本创建的新项目还包括
* Google's Maven 存储库.
*/
repositories {
google()
jcenter()
}
/**
* dependencies块配置Gradle在构建项目时需要使用的依赖项.
* 下面一行添加了gradleversion3.6.0的Android插件作为类路径依赖项
*/
dependencies {
classpath 'com.android.tools.build:gradle:3.6.0'
}
}
/**
* allprojects块用于配置项目中所有模块使用的存储库和依赖项, 例如第三方插件或库.
* 但应该在每个模块生成.gradle文件中,配置特定于模块的依赖项。
* 对于新项目,Android Studio默认包括JCenter和Google的Maven存储库,
* 但它不配置任何依赖项(除非选择的模板需要某些依赖项)。
*/
allprojects {
repositories {
google()
jcenter()
}
}
// 对于多模块的项目,可能需要设置全模块可见的参数,下面的代码块可设置全局参数
ext {
// 以下是可以定义的属性类型的几个示例。
compileSdkVersion = 28
// 还可以创建属性以指定依赖项的版本。
// 在模块之间保持一致的版本可以避免与行为的冲突。
supportLibVersion = "28.0.0"
...
}
c.模块下build.gradle
位置:位于每个 project/module/ 目录,例如根目录/app/
作用:用于为其所在的特定模块配置构建设置。
可以通过配置这些构建设置提供自定义打包选项(如多渠道apk)
/**
*将Android Gradle Plugin引入该项目中,用于构建Android代码
*/
apply plugin: 'com.android.application'
/**
* Android代码块是配置所有android特定构建选项的地方。
*/
android {
/**
* compileSdkVersion指定Gradle编译应用程序时应使用的Android API级别。
* 这意味着的应用程序可以使用此API级别及更低级别中包含的API功能。
*/
compileSdkVersion 28
/**
* buildToolsVersion指定SDK构建工具、命令行、实用程序的版本,
* 以及Gradle用来构建你的应用程序的编译器.
* 需要使用SDK管理器下载构建工具。
* 此属性是可选的,因为默认情况下插件使用建议版本的生成工具。
*/
buildToolsVersion "29.0.2"
/**
* defaultConfig块封装所有生成变量的默认设置和条目,
* 并且可以构建系统中动态覆盖main/AndroidManifest.xml中的一些属性
* 可以对不同版本配置不同的属性。
*/
defaultConfig {
/**
* applicationId对要发布的包的唯一标识。
* 但是,源代码仍应引用main/AndroidManifest.xml file.中
* 由package属性定义的包名称
*/
applicationId 'com.example.myapp'
// 定义运行应用程序所需的最低API级别。
minSdkVersion 15
// 指定用于测试应用程序的API级别。
targetSdkVersion 28
//定义应用程序的版本号。
versionCode 1
// 为你的应用定义一个面向用户的版本名。。
versionName "1.0"
}
/**
* buildTypes块用于配置多个生成类型.
* 默认情况下,生成系统定义了两种生成类型:debug和release.
* debug类型未在默认生成配置中显示,它包含调试工具并用debug密钥签名
* release版本类型应用了Proguard设置,并且没有由debug签名
*/
buildTypes {
/**
* 默认情况下,Android Studio会配置release build类型以启用code shrinking ,
* 使用minifyEnabled,并指定默认的Proguard规则文件。
*/
release {
minifyEnabled true // 启用版本生成类型的code shrinking 。
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
/**
* productflavorites块是你可以配置多个 build types的地方。
* 允许创建应用程序的不同版本,这些版本可以用自己的设置覆盖defaultConfig块。
* 产品 flavors的设置,在默认情况下,系统不会创建它们。
* 下面例子创建了一个免费和付费的产品flavor. 每个产品flavor指定自己的应用程序ID,
* 这样他们就可以在GooglePlay上发布了。
* 如果声明产品flavors,还必须声明flavors维度。
*/
flavorDimensions "tier"
productFlavors {
free {
dimension "tier"
applicationId 'com.example.myapp.free'
}
paid {
dimension "tier"
applicationId 'com.example.myapp.paid'
}
}
/**
* 在splits块中,可以配置不同的APK版本,
* 每个构建只支持对应的屏幕密度或ABI的代码和资源.
* 还可以配置构建,使每个每个APK都有不同的版本代码。
*/
splits {
// 根据屏幕密度建立多个APK的设置。
density {
// 启用或禁用生成多个APK。
enable false
// 构建多个APK时排除这些密度。
exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
}
}
}
/**
* dependencies块仅定义对应模块中,生成配置文件需要的依赖项。
*/
dependencies {
implementation project(":lib")
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
d.Gradle 属性文件
Gradle 还包含两个属性文件,它们位于项目的根目录下,可用于指定 Gradle 构建工具包本身的设置:
前文我们看了Gradle的一下基础知识,下面我们看一下如何配置项目中的gradle。让编译流程更加快速。在这之前,先了解两个用于Gradle性能分析的工具
Profile report是gradle团队早些时候出品的用来诊断gradle的工具
使用方法
./gradlew assembleDebug --profile(mac)
Build Scan 是官方推出的用于诊断应用构建过程的性能检测工具,它能分析出导致应用构建速度慢的一些问题。用下面命令开启
./gradlew build --scan
前文我们看了用于分析Gradle的工具,下面我们看一下如何配置项目中的gradle。
a.使用最新的Gradle和JVM版本
Gradle 开发团队会持续的更新 Gradle 版本,来优化构建速度以及提供一些新的特性,而使用新版本的 JVM,是因为 Gradle 运行在 JVM 上,所以,如果新版本的 JVM 提升了性能,同样也会让 Gradle 跑的更快。
b.并行执行
大多数构建都包含一个以上的项目,其中一些项目通常是彼此独立的。然而,默认情况下,Gradle一次只能运行一项任务。
通过使用该–parallel开关,可以强制Gradle并行执行任务,只要这些任务位于不同的项目中即可。
还可以通过将以下设置添加到项目的gradle.properties文件中,将并行构建作为项目的默认设置
gradle.properties
org.gradle.parallel=true
c.避免引入多余的插件
应用于项目的每个插件和脚本都会增加总体配置时间。
一些插件比其他插件具有更大的影响。
但这并不意味着应该避免使用插件,但应注意仅在需要的地方应用它们。
例如,注意区分是否所有项目都使用该插件,即allprojects {}或subprojects {}即使不是每一个项目都需要它们。
d.配置阶段避免耗时操作
在配置阶段应该减少一下网络等耗时操作
e.依赖相关
尽可能动态版本(例如“ 2. +”)的使用,这样会导致在构建过程中,进行耗时操作。避免不必要和未使用的依赖项。
f.增量编译
Gradle 的构建方式通常来说细分为以下 三种:
tasks.withType(JavaCompile) {
options.incremental = true
}
a.对debug版本进行单独设置
对开发调试都debug包进行单独设置,例如避免编译和打包不测试的资源(其他语言本地化和屏幕密度资。
android {
...
productFlavors {
dev {
...
// The following configuration limits the "dev" flavor to using
// English stringresources and xxhdpi screen-density resources.
resConfigs "en", "xxhdpi"
}
...
}
}
如果不需要运行 Crashlytics 报告,请按如下方法停用该插件,以提高调试 build 的构建速度
android {
...
buildTypes {
debug {
ext.enableCrashlytics = false
}
}
对于debug包,可以禁止自动生成 build ID
android {
...
buildTypes {
debug {
ext.alwaysUpdateBuildId = false
}
}
将始终会进入调试 build 类型的清单文件或资源文件的属性 使用静态/硬编码值。
int MILLIS_IN_MINUTE = 1000 * 60
int minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE
android {
...
defaultConfig {
versionCode 1
versionName "1.0"
...
}
applicationVariants.all {
variant ->
if (variant.buildType.name == "release") {
variant.mergedFlavor.versionCode = minutesSinceEpoch;
variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName;
}
}
}
b.启用离线模式
如果网络连接速度比较慢,那么在 Gradle 尝试使用网络资源解析依赖项时,构建时间可能会延长。可以指示 Gradle 仅使用已缓存到本地的工件,从而避免使用网络资源.
c.使用 WebP 格式的图片
有效减少图像文件大小,而不必执行构建时压缩,可以加快你的构建
d.关闭 PNG crunching
加快构建速度通过禁用自动图像压缩,Gradle 3.0 版本以上在 debug 的构建类型下是默认关闭的。
a.配置 AS 的最大堆内存
在默认情况下, AS 的最大堆内存为 1960MB,我们可以选择 Help => Edit Custom VM Options,此时,会打开一个 studio.vmoptions 文件,我们将第二行的 -Xmx1960m 改为 -Xmx3g 即可将可用内存提升到 3GB。
b.删除不必要的 Moudle 或合并部分 Module
过多的 Moudle 会使项目中 Module 的依赖关系变得复杂,Gradle 在编译构建的时候会去检测各个 Module 之间的依赖关系,然后,它会花费大量的构建时间帮我们梳理这些 Module 之间的依赖关系,以避免 Module 之间相互引用而带来的各种问题。除了删除不必要的 Moudle 或合并部分 Module 的方式外,我们也可以将稳定的底层 Module 打包成 aar,上传到公司的本地 Maven 仓库,通过远程方式依赖。
c.删除Module中的无用文件
d.配置 DexOptions
我们可以将 dexOptions 配置项中的 maxProcessCount 设定为 8,这样编译时并行的最大进程数数目就可以提升到 8 个
gradle命令行格式
在window下可以直接运行 gradlew 如果是Linux 或者 mac 命令为 gradle gradlew (./gradlew)这里都简写成 gradle
启动行为具有长形式的选项,可以由指定的反函数–no-。如下
–build-cache
–no-build-cache
长格式命令很多都可以简写,比如
- help
-H
a.运行task及其所有依赖项
gradle myTask
b.多项目中执行task
在多项目构建中,子项目task可以使用“:”执行,以分隔子项目名称和任务名称。从根项目运行时,以下内容等效。
gradle: mySubproject: taskName
如果在子项目中调用Gradle时,应省略项目名称
gradle: taskName
也可以只使用任务名运行tast,此时所有的子项目中该task都会运行
gradle: taskName
c.执行多项任务
gradle test1 test2
d.从执行中排除任务
可以使用-x或–exclude-task命令行来排除正在执行的任务。
gradle dist --exclude-task test
e.强制执行任务
可以使用–rerun-tasks选项强制Gradle执行所有任务,从而忽略最新检查
gradle test --rerun-tasks
f.发生故障时继续构建
默认情况下,任何任务失败后Gradle将中止执行。这样可以使构建更快完成,但隐藏其他可能发生的故障。为了在一次构建执行 中发现尽可能多的故障,可以使用该–continue选项。
gradle test --continue
任务名称缩写
在命令行上指定任务时,不必提供任务的全名。只需要提供足够的任务名称即可唯一地标识任务。例如,gradle che可以让Gradle识别出是check任务就足够了。
以下是内置和大多数主要Gradle插件应用的任务约定
a.构建gradle
gradle build
b.运行应用
应用程序通常与run任务一起运行,该任务将组装应用程序并执行一些脚本或二进制文件
gradle run
c.运行所有ckeck task
gradle check
e.清除所有输出
可以使用clean任务删除构建目录的内容,尽管这样做会导致丢失之前计算的输出,从而导致后续任务执行需要大量额外的构建时间
gradle clean
a.显示项目
通过运行gradle projects,您可以显示所选项目的子项目列表,以层次结构显示。
gradle projects
b.显示任务
通过运行gradle tasks,可以列出所选项目的主要任务。该报告显示项目的默认任务(如果有)以及每个任务的描述。
gradle tasks
默认情况下,此报告仅显示已分配给任务组的那些任务。您可以使用该–all选项在任务列表中获取更多信息。
gradle tasks --all
c.显示task依赖
gradle myTask --scan扫描后,会生成提供完整的依赖可视化报告
gradle myTask --scan
d.列出项目依赖项
gradle dependencies 提供了所选项目的依赖项列表,并按配置进行了细分。对于每种配置的直接依赖关系和传递依赖关系都显示在树中
gradle dependencies
由于依赖性报告可能会很大,可以通过-configuration将报告限制为特定配置。
e.列出项目属性
运行gradle properties将提供所选项目的属性列表。
gradle properties
f.软件model报告
你可以通过gradle model来获得model的分层视图
gradle model
-?,-h,–help
显示帮助消息。
-v, --version
打印Gradle,Groovy,Ant,JVM和操作系统版本信息。
-S, --full-stacktrace
打印出完整的堆栈跟踪以了解任何异常。
-s, --stacktrace
还打印出堆栈跟踪信息以了解用户异常(例如,编译错误)。
–scan
使用有关Gradle构建各个方面的详细信息创建构建扫描。
-Dorg.gradle.debug=true
调试Gradle客户端进程。localhost:5005默认情况下,Gradle将等待连接调试器。
-Dorg.gradle.daemon.debug=true
调试Gradle守护进程。
–build-cache, --no-build-cache
切换为Gradle构建缓存。Gradle将尝试重用以前版本的输出。默认为关闭。
–configure-on-demand, --no-configure-on-demand
切换为按需配置。在此构建运行中仅配置相关项目。默认为关闭。
–max-workers
设置Gradle可以使用的最大worker。默认值为处理器数量。
–parallel, --no-parallel
并行构建项目。默认为关闭。
–profile
在$buildDir/reports/profile目录中生成高级性能报告。–scan是首选。
–include-build
将构建作为组合运行,包括指定的构建。
–offline
离线构建,在在不访问网络资源的情况下运行。
–refresh-dependencies
刷新依赖关系的状态。
–dry-run
在禁用所有任务操作的情况下运行Gradle。使用它来显示将要执行的任务。
–write-locks
表示所有可锁定的配置都保留其锁定状态。
–update-locks group:name[,group:name]*
指示在锁定文件中更新指定模块的版本。此标志还暗含–write-locks。
您可以通过以下选项自定义许多方面,以了解构建脚本,设置,缓存等的位置。
-b, --build-file
指定构建文件。例如:gradle --build-file=foo.gradle。默认为build.gradle,然后build.gradle.kts,然后myProjectName.gradle。
-c, --settings-file
指定设置文件。例如:gradle --settings-file=somewhere/else/settings.gradle
-g, --gradle-user-home
指定Gradle用户的主目录。默认值为.gradle用户主目录中的目录。
-p, --project-dir
指定Gradle的起始目录。默认为当前目录。
–project-cache-dir
指定特定于项目的缓存目录。默认值.gradle在根项目目录中。
-D, --system-prop
设置JVM的系统属性,例如-Dmyprop=myvalue。
-I, --init-script
指定初始化脚本。
-Dorg.gradle.jvmargs
设置JVM参数。
-Dorg.gradle.java.home
设置JDK主目录。
深度探索 Gradle 自动化构建技术(一、Gradle 核心配置篇)
[官方文档]什么是Gradle
[官方文档]配置构建
[官方文档]改善Gradle构建的性能
[官方文档]优化编译速度
[官方文档]Gradle与命令行
Gradle 提速:每天为你省下一杯喝咖啡的时间
Gradle Android-build 常用命令参数及解释