一、了解gradle
1.概述
1.1 gradle是什么
gradle是一款基于JVM的专注于灵活性和性能的开源构建工具。
gradle用的是一种基于 Groovy 的领域特定语言(DSL,Demain Specific Language)来声明项目设置,摒弃了 XML(如 ANT 和 Maven)的各种繁琐配置。
1.2 作用
1.3 为什么用gradle?
附上:Gradle官网:https://gradle.org
2.Android gradle plugin
Android gradle plugin是Gradle插件,也就是AndroidStudio用于开发Android项目的gradle插件。
gradle是构建工具,可以构建java应用,web应用。而gradle plugin只是google用来构建android应用的一个android studio插件。
3.gradle wrapper
每个基于gradle构建的工程都有一个gradle本地代理,叫做 gradle wrappe。在 /gradle/wrapper/gralde-wrapper.properties 目录中声明了指向目录和版本。
每一个Wrapper都会绑定到一个特定版本的Gradle,当用户第一次执行如下的命令时,Wrapper会自动地下载并安装对应版本的Gradle,方便用户构建项目。
二、Groovy基本语法
1、基础语法
1、语句可以不以分号结尾
2、函数调用可以不需要参数括号
println 'hello world'
3、动态类型
Groovy 定义变量的方式和 Java 是类似的,区别在于 Groovy 提供了def关键字供使用,它可以省略变量类型的定义,根据变量的值进行类型推导。
如:
def a = 123
def b = 'b'
def c = true
boolean d = false
int e = 123
4、函数写法
Groovy 方法的默认访问修饰符是public,方法的返回类型可以不需要声明,但需添加def关键字。有返回值的方法return可以被省略,默认返回最后一行代码的运行结果,如果使用了return关键字则返回指定的返回值。
例:
String method1() {
return 'hello'
}
assert method1() == 'hello';
def method2() {
return 'hello'
}
assert method2() == 'hello';
def method3() {
'hello'
}
assert method3() == 'hello';
Groovy 方法的参数类型可以被省略,默认为Object类型。
例:
def add(int a, int b) {
return a + b
}
//与上面的等价
def add(a, b) {
a + b
}
Groovy 方法的其他特性与Java一样,比如支持重载、不定长参数(…)等。
5、不需要main函数
在Java中要输出“hello world”需要像下面这样,创建一个类,然后创建一个main方法。
public class Hello {
public static void main(String[] args) {
System.out.println("hello world");
}
}
在Groovy中,这些都可以省略,实例如下:
例:在文本中写如下groovy语句
println 'Groovy world!'
上面我们写的groovy文件编译后的class其实是Java类,该类从Script类派生而来(查阅API);可以发现,每个脚本都会生成一个static main方法,我们执行groovy脚本的实质其实是执行的这个Java类的main方法,脚本源码里所有代码都被放到了run方法中,脚本中定义的方法(该例暂无)都会被定义在Main类中。如下:
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
def run() {
println 'Groovy world!'
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}
6、Groovy快速入门博客
https://www.jianshu.com/p/e8dec95c4326
2、闭包
闭包其实就是一段代码块。在gradle中,我们主要是把闭包当参数来使用
例如1:
//定义一个闭包
def b1 = {
println “hello b1”
}
//定义一个方法,方法里面需要闭包类型参数
def method1 (Closure closure) {
closure()
}
//调用方法
method1(b1)
结果:输出hello b1
例如2:
//定义一个闭包,带参数
def b2 = {
v->
println "hello ${v}"
}
//定义一个方法,方法里面需要闭包类型参数
def method2 (Closure closure) {
closure("xiaoma")
}
//调用方法
method2(b2)
结果:输出hello xiaoma
例如3:
//多个参数以逗号分隔,参数类型和方法一样可以显式声明也可省略。
def closure = { String x, int y ->
println "hey {y}"
}
3、元编程
groovy运行时类方法调用流程:
在java中,如果对象调用了一个类中没有定义过的方法时,连编译都编译不过,但是在groovy中,情况则不同(可以编译通过),根据图中流程可以知道,运行期间,当对象调用了一个类中没有的方法时,会依次调用metaClass中的同名方法,类中的methodMissing(String name, Object args)方法,类中的invokeMethod(String name, Object args)方法,执行到其中一个便停止后续方法查找调用。
三、Gradle项目编译
1.Android Gradle项目结构
含有两个子模块(app和remoteDiagnosisLibrary)的项目结构如下:
1.1gradle.properties
可以在 gradle.properties 文件中配置一些变量,这些变量在这个工程下的所有module的build.gradle文件里都可以使用。这样就可以把一些共用的变量放到这里,这样后面修改的时候就可以只修改这个变量,不用各个模块都要修改了。
上图项目结构中的gradle.properties如下:
1.2settings.gradle
Gradle试图找到一个设置(settings.gradle)。为此,运行时将目录树的层次结构遍历到根目录。一旦找到设置文件,算法就停止搜索。
总是添加一个设置到构建的根目录,以避免初始性能影响。
上图项目结构中的settings.gradle如下:
1.3build.gradle
配置脚本文件名默认是不变的build.gradle,每一个project(模块)对应一个build.gradle。
2.编译执行流程
一次Gradle的工作流分为3大部分:
第一:初始化。
Gradle支持单个和多个项目的构建。在初始化阶段,Gradle确定哪些项目将参与构建,并为每个项目创建一个项目实例。
第二:配置。
在此阶段,将配置项目对象。作为构建的一部分的所有项目的构建脚本都被执行。
第三:执行。
Gradle确定在配置阶段创建和配置的要执行的任务的子集。子集由传递给gradle命令和当前目录的任务名参数决定。然后Gradle执行每一个选择的任务。
实例1:创建task
task haha{
println("hahaha")
doLast{
println("ccccc")
}
doFirst{
println("aaaaa")
}
doLast{
println("bbbbbb")
}
println("endendend")
}
注:
doFirst:将给定添加Action到此任务的操作列表的开头。
doLast:将给定添加Action到此任务的操作列表的最后。
执行haha task,结果如下
Configure project:打印表明是第二阶段:配置阶段
Task:haha打印表明是第三阶段:执行阶段这个地方特别理解一下:
1、dolast方法创建的任务,在配置阶段只是创建执行的任务,真正执行是在执行阶段。所以hahaha打印在configure阶段,cccccc打印在task阶段
2、执行阶段task的顺序
没有顺序之前是按照字母顺序排列,可以通过依赖方法(dependsOn)、doFirst、doLast调整顺序
3.模块Project
1、每个项目都会有自己的gradle领域,配置脚本文件名默认是不变的build.gradle
2、Project之间如果出现父子关系,只有根Project才会有setting.gradle配置文件,该配置文件的作用是声明其包含的子项目。
3、Project代表一个项目,在jvm中的一个实例。Build.gradle中无主的方法都可以在project中找到
4.任务Task介绍
1.概述
task,如其名:任务,gradle就是由一个一个任务来完成的。他其实也是一个类,有自己的属性,也可以"继承",甚至他还有自己的生命周期。Task是构建中的最小执行单元。
task的基类是DefaultTask ,我们也可以自定义一个task,必须继承DefaultTask,如下:
class MyTask extends DefaultTask {
String message = 'This is MyTask'
// @TaskAction 表示该Task要执行的动作,即在调用该Task时,hello()方法将被执行
@TaskAction
def hello(){
println "Hello gradle. $message"
}
}
2.默认Task
Gradle 允许在脚本中定义一个或多个默认任务.
2.1 添加默认任务的方法
在build.gradle中调用defaultTasks方法,将要设置成默认的task方法传入进去。
2.2 实例
build.gradle
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
gradle -q 命令的输出:
gradle -q
Default Cleaning!
Default Running!
结果等价于执行编译命令gradle clean run。
在一个多项目构建中, 每一个子项目都可以有它特别的默认任务. 如果一个子项目没有特别的默认任务, 父项目的默认任务将会被执行.
3.自定义Task
如下:vpsclient项目的gradle.build中创建了一个clean任务。
4.Gradle、Settings、Project、Task之间关系
Gradle
表示对Gradle的调用。
Settings
声明实例化和配置Project要参与构建的实例的层次结构所需的配置。
对应的文件是setting.gradle。
Project
Project代表一个项目,在jvm中的一个实例。该接口是用于与构建文件中的Gradle交互的主要API。从中Project,您可以通过编程方式访问Gradle的所有功能。
Project和build.gradle 文件之间存在一对一的关系。
Task
Task代表构建的一项基本工作,例如编译类或生成javadoc。
四者之间的联系:
1、执行gradle命令时,会创建一个gradle对象。
2、在构建初始化过程中,Gradle为每个要参与构建的项目装配一个项目对象,具体如下:
为构建创建Settings实例。
Settings。gradle脚本,如果存在,针对设置对象来配置它。
使用已配置的Settings对象创建Project实例的层次结构。
最后,Project通过build.gradle针对项目执行其文件(如果存在)来评估每个文件。这些项目以广度顺序进行评估,因此在其子项目之前先对其进行评估。可以通过调用Project.evaluationDependsOnChildren()或添加使用的显式评估依赖项来覆盖此顺序Project.evaluationDependsOn(java.lang.String)。
3、Project本质上是Task对象的集合。每个Task都属于一个Project。
四、Gradle配置
1、Build.gradle配置文件Demo
重要的属性:
android属性
设置编译android项目的参数,构建android项目的所有配置都写在这里。
实例说明:
android {
// 编译SDK的版本
compileSdkVersion 22
// build tools的版本
buildToolsVersion "23.0.1"
//aapt配置
aaptOptions {
//不用压缩的文件
noCompress 'pak', 'dat', 'bin', 'notice'
//打包时候要忽略的文件
ignoreAssetsPattern "!.svn:!.git"
//分包
multiDexEnabled true
//--extra-packages是为资源文件设置别名:意思是通过该应用包名+R,com.android.test1.R和com.android.test2.R都可以访问到资源
additionalParameters '--extra-packages', 'com.android.test1','--extra-packages','com.android.test2'
}
//默认配置
defaultConfig {
//应用的包名
applicationId "com.example.heqiang.androiddemo"
minSdkVersion 21
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
//编译配置
compileOptions {
// java版本
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
//源文件目录设置
sourceSets {
main {
//jni lib的位置
jniLibs.srcDirs = jniLibs.srcDirs << 'src/jniLibs'
//定义多个资源文件夹,这种情况下,两个资源文件夹具有相同优先级,即如果一个资源在两个文件夹都声明了,合并会报错。
res.srcDirs = ['src/main/res', 'src/main/res2']
//指定多个源文件目录
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
//签名配置
signingConfigs {
debug {
keyAlias 'androiddebugkey'
keyPassword 'android'
storeFile file('keystore/debug.keystore')
storePassword 'android'
}
}
buildTypes {
//release版本配置
release {
debuggable false
// 是否进行混淆
minifyEnabled true
//去除没有用到的资源文件,要求minifyEnabled为true才生效
shrinkResources true
// 混淆文件的位置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.debug
//ndk的一些相关配置,也可以放到defaultConfig里面。
//指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,arm-v8之类的so会被过滤掉)
ndk {
abiFilter "armeabi"
}
}
//debug版本配置
debug {
debuggable true
// 是否进行混淆
minifyEnabled false
//去除没有用到的资源文件,要求minifyEnabled为true才生效
shrinkResources true
// 混淆文件的位置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.debug
//ndk的一些相关配置,也可以放到defaultConfig里面。
//指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,arm-v8之类的so会被过滤掉)
ndk {
abiFilter "armeabi"
}
}
}
// lint配置
lintOptions {
//移除lint检查的error
abortOnError false
//禁止掉某些lint检查
disable 'NewApi'
}
}
除了上面写的,在android{}块中可以包含以下直接配置项:
productFlavors{ } 产品风格配置,ProductFlavor类型
testOptions{ } 测试配置,TestOptions类型
dexOptions{ } dex配置,DexOptions类型
packagingOptions{ } PackagingOptions类型
jacoco{ } JacocoExtension类型。用于设定 jacoco版本
splits{ } Splits类型。
dependencies属性
gradle中所有的jar包的座标都放在这个属性内,每个jar包都包含三个基本元素(group,name,version)。
2、Gradle构建语言帮助文档地址
Gradle配置Build.gradle脚本语言帮助文档地址:
https://docs.gradle.org/current/dsl/
3、修改成国内源(阿里源)
在 project 的 build.gradle中修改如下:
allprojects {
repositories {
//jcenter()
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
}
}
然后点击 gradle rync 即可。
4、自定义gradle插件
4.1 二进制插件
apply plugin: 'xxx' //声明引用插件的类型
如腾讯shadow中buildScripts/gradle/maven.gradle:
4.2 应用脚本插件
apply from:'xxx' //表示引用其他的配置文件
如腾讯shadow中gradle.build:
就是引用了buildScripts/gradle/下面的两个配置文件
五、Gradle自定义构建
1、构建的变体
1.1 概述
构建变体是构建版本和生产版本的结合体。当你创建了一个构建版本或者生产版本,同样的,新的变体也会被创建。
像下图便有这么多的变体:
1.2 创建构建变体
flavorDimensions "channel","money"
android {
productFlavors {
vivo {
dimension "channel"
applicationId "vivo"
versionCode 1
minSdkVersion 15
}
oppo {
dimension "channel"
applicationId "oppo"
versionCode 2
minSdkVersion 15
}
free {
dimension "money"
resValue "color", "colorfree", "#ff8888"
}
vip {
dimension "money"
resValue "color", "colorfree", "#ff0000"
}
}
}
2、自定义构建流程
2.1在某任务之前执行
Task diyTask = project.task('diyTask') {
doLast {
Utils.println("diy task run")
}
}
project.tasks.whenTaskAdded { Task theTask ->
if (theTask.name == 'assembleDebug') {
theTask.dependsOn(diyTask)
theTask.mustRunAfter(diyTask) // diyTask在assembleRelease之前执行
}
}
2.1在某任务之后执行
Task diyTask = project.task('diyTask') {
doLast {
Utils.println("diy task run")
}
}
project.tasks.whenTaskAdded { Task theTask ->
if (theTask.name == 'assembleRelease') {
theTask.dependsOn(diyTask) // diyTask在assembleRelease之后执行
}
}
六、Gradle命令
1、任务查询和运行命令
查看任务
./gradlew tasks
查看所有任务 包括缓存任务等
./gradlew tasks --all
对某个module [moduleName] 的某个任务[TaskName] 运行
./gradlew :moduleName:taskName
2、快速构建命令
查看构建版本
./gradlew -v
清除build文件夹
./gradlew clean
检查依赖并编译打包
./gradlew build
编译并安装debug包
./gradlew installDebug
编译并打印日志
./gradlew build --info
译并输出性能报告,性能报告一般在 构建工程根目录 build/reports/profile
./gradlew build --profile
调试模式构建并打印堆栈日志
./gradlew build --info --debug --stacktrace
强制更新最新依赖,清除构建并构建
./gradlew clean build --refresh-dependencies
3、指定构建目标命令
编译并打Debug包
./gradlew assembleDebug
这个是简写 assembleDebug
./gradlew aD
编译并打Release的包
./gradlew assembleRelease
这个是简写 assembleRelease
./gradlew aR