本文主要总结的内容如下:
Groovy介绍
一、Gradle简介(定义与特性)
-
二、Gradle使用
- 1、Multi-Projects Build
- 2、gradle命令
- 3、gradle的工作流程
- 4、Gradle编程模型
-
三、Android中使用Gradle
- 1、相关文件
- 2、Android tasks
- 3、相关配置
- 4、Gradle模板举例
0、Groovy介绍:
Gradle
选择了Groovy
。Groovy
基于Java
并拓展了Java
。
Gradle选择了Groovy的原因:
Groovy
基于Java并拓展了Java。 Java程序员可以无缝切换到使用Groovy开发程序。Groovy说白了就是把写Java程序变得像写脚本一样简单。写完就可以执行,Groovy内部会将其编译成Javaclass
然后启动虚拟机来执行。
1、定义:Groovy是在 java平台上的、 具有像
Python
,Ruby
和Smalltalk
语言特性的灵活动态语言, Groovy保证了这些特性像 Java语法一样被 Java开发者使用。2、Groovy是一种动态语言。
-
3、Groovy与Java的关系:
当我执行Groovy脚本时,Groovy会先将其编译成Java类字节码,然后通过Jvm来执行这个Java类。
-
4、特性:
- Groovy注释标记和Java一样,支持//或者/**/
- Groovy语句可以不用分号结尾。
- Groovy中支持动态类型,即定义变量的时候可以不指定其类型。Groovy中,变量定义可以使用关键字def。注意,虽然def不是必须的,但是为了代码清晰,建议还是使用def关键字。
- 函数定义时,参数的类型也可以不指定。
- 除了变量定义可以不指定类型外,Groovy中函数的返回值也可以是无类型的
//无类型的函数定义,必须使用def关键字 def nonReturnTypeFunc(){ last_line //最后一行代码的执行结果就是本函数的返回值 } //如果指定了函数返回类型,则可不必加def关键字来定义函数 String getString(){ return"I am a string" }
快速学习攻略:Groovy脚本基础全攻略
一、Gradle简介
1、定义
1、Gradle是一个工具,同时它也是一个编程框架。
2、Gradle中,每一个待编译的工程都叫一个
Project
。
每一个Project
在构建的时候都包含一系列的Task
。
比如一个Android APK的编译可能包含:Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task、打包生成APK的Task、签名Task等。3、Gradle是一个框架,作为框架,它负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译Java有Java插件,编译Groovy有Groovy插件,编译Android APP有Android APP插件,编译Android Library有Android Library插件。
2、特性:
- 使用灵活的语言来写构建规则。
-
Gradle
是一种DSL
,即Domain Specific Language,领域相关语言。
二、Gradle使用
1、Multi-Projects Build
将多个Project
进行统一编译,类似这种操作,在Gradle中,可以称之为Multi-Projects Build
。
1.1、使用方式:
1、在工程根目录(如图中gradleProjects)下添加一个
build.gradle
文件(用于配置其他子Project的)-
2、在工程根目录(如图中gradleProjects)下添加一个
settings.gradle
文件(名称必须为settings.gradle
用于告知Gradle包含多少个子Project
)。
1.2、.gradle
内容:
1、build.gralde:
为子Project添加一些属性。这个build.gradle有没有都无所属。-
2、
settings.gradle
#settings.gradle include 'project1', 'project2', 'project3', 'project4'
2、gradle命令:
2.1、查看工程信息:
- 命令:
gradle projects
在根目录(如gradleProjects)下打开终端,执行此命令 - 结果:显示有多少个
project
2.2、查看任务信息:
- 命令:
gradleproject-path:tasks
在子目录(如project1)下打开终端,执行此命令。若不在子目录中则需要加上project-path
。 - 结果:显示当前项目的任务信息
由于我这个子目录下什么也没有,所以显示的信息是这个样子。
2.3、执行任务(task)
- 命令:
gradle task-name
task-name
为指定任务的名称,如clean
清理任务 - 示例:
-
gradle clean
是执行清理任务,和make clean类似。 -
gradle properites
用来查看所有属性信息。
-
3、gradle的工作流程:
包含三个阶段:
1、首先是初始化阶段(
Initiliazation phase
)。
对我们前面的multi-project build
而言,就是执行settings.gradle
。-
2、
Configration
阶段的目标是解析每个project
中的build.gradle
。比如multi-project build例子中,解析每个子目录中的build.gradle。在这两个阶段之间,我们可以加一些定制化的Hook。这当然是通过API来添加的。
Configuration
阶段完了后,整个build的project以及内部的Task关系就确定了。一个Project包含很多Task,每个Task之间有依赖关系。Configuration
会建立一个有向图来描述Task之间的依赖关系。所以,我们可以添加一个HOOK
,即当Task
关系图建立好后,执行一些操作。
3、最后一个阶段就是执行任务了。
你在gradle xxx中指定什么任务,gradle就会将这个xxx任务链上的所有任务全部按依赖顺序执行一遍!
任务执行完后,我们还可以加Hook。
4、Gradle编程模型
Gradle基于Groovy,Groovy又基于Java。所以,Gradle执行的时候和Groovy一样,会把脚本转换成Java对象。
Gradle主要有三种对象,这三种对象和三种不同的脚本文件对应,在gradle执行的时候,会将脚本转换成对应的对端:
Gradle对象:
当我们执行gradle xxx
或者什么的时候,gradle会从默认的配置脚本中构造出一个Gradle对象
。在整个执行过程中,只有这么一个对象。Gradle对象的数据类型就是Gradle。
我们一般很少去定制这个默认的配置脚本。Project对象:
每一个build.gradle
会转换成一个Project对象
。Settings对象:
每一个settings.gradle
都会转换成一个Settings对象
。
各种类型Gradle对应的对象类型:
脚本类型 | 关联对象类型 |
---|---|
Build script | Project |
Init script | Gradle |
Settings script | Settings |
4.1、Gradle对象:
gradle对象的属性如图,其中的几个属性说明如下:
-
hashCode()
在settings.gradle和build.gradle中,gradle实例对象的hashCode是一样的 -
HomeDir
是指在哪个目录存储的gradle可执行程序 -
User Home Dir
gradle自己设置的目录,里边存储了一些配置文件,以及编译过程中的缓存文件,生成的类文件,编译中依赖的插件等等。
4.2、Project对象:
1、每一个
build.gradle
文件都会转换成一个Project对象。在Gradle术语中,Project对象对应的是BuildScript
。2、Project包含若干Tasks。由于Project对应具体的工程,所以需要为Project加载所需要的插件,比如为Java工程加载Java插件。其实,一个Project包含多少Task往往是插件决定的。
-
3、一个项目在构建时都具备如下流程:
- 为当前项目创建一个Settings类型的实例。
- 如果当前项目存在
settings.gradle
文件,则通过该文件配置刚才创建的Settings实例。 - 通过Settings实例的配置创建项目层级结构的Project对象实例。
- 最后通过上面创建的项目层级结构Project对象实例去执行每个Project对应的
build.gradle
脚本。
-
4、在Project中,需要:
- 加载插件(调用apply函数):
//二进制插件(如jar包) //Android中的build.gradle apply plugin: 'com.android.library' <==如果是编译Library,则加载此插件 apply plugin: 'com.android.application' <==如果是编译Android APP,则加载此插件 //加载一个gradle文件 apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
- 不同插件有不同的配置。在Project中配置后,插件就知道从何处读取源文件
- 设置属性:
单个脚本,不需要考虑属性的跨脚本传播。
extra property
(额外属性):通过ext
前缀标示是一个额外属性。定义好之后,后面的存取就不需要ext前缀了。ext属性支持Project和Gradle对象。即Project和Gradle对象都可以设置ext属性://第一次定义或者设置它的时候需要ext前缀 gradle.ext.api =properties.getProperty('sdk.api') println gradle.api //再次存取api的时候,就不需要ext前缀了
- 加载插件(调用apply函数):
三、Android中的Gradle
Android自己定义了好多Script Block。Android定义的DSL参考文档在
https://developer.android.com/tools/building/plugin-for-gradle.html下载。
1、相关文件
- Android中gradle项目基本的目录结构:
demoApp |-- build.gradle |-- settings.gradle |-- app |-- build.gradle |-- gradlew |-- gradlew.bat |-- gradle |-- wrapper |-- gradle-wrapper.jar |-- gradle-wrapper.properties |-- gradle.properties |-- local.properties
1.1、local.properties
对于Android来说,local.properties
是必须的,下面两个配置sdk.dir和ndk.dir是Android Gradle必须要指定的。
#设置sdk目录
sdk.dir=xxx
#设置ndk目录
ndk.dir=yyy
1.2、项目根目录(顶层)的build.gradle
一般情况下,这个build.gradle
是做一些全局配置,其配置最终会被应用到所有项目中。它典型的配置如下:
apply from: 'dependencies.gradle'
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
buildscript
:定义了 Android 编译工具的类路径。repositories
中的 jCenter和
mavenCentral` 是两个仓库。allprojects
:中定义的属性会被应用到所有module
中,但是为了保证每个项目的独立性,我们一般不会在这里面操作太多共有的东西。(一般外部依赖库都在其中,gradle会通过查找在这里配置的仓库来比编译指定的依赖库?)
1.3、每个子项目中的build.gradle
针对每个module 的配置,如果其build.gradle
中定义的选项和顶层build.gradle
定义的相同,则顶层中的配置会被覆盖。典型的配置内容如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.demo.testapp"
minSdkVersion 14
targetSdkVersion 28
versionCode 1.1.1
versionName "111"
}
signingConfigs {
debug {
storeFile file("../debug.jks")
storePassword "123456"
keyAlias "haha"
keyPassword "123456"
}
release {
storeFile file("../release.jks")
storePassword "123456"
keyAlias "haha"
keyPassword "123456"
}
}
buildTypes {
debug {
minifyEnabled false //是否混淆
shrinkResources false //去除没有用到的资源文件
}
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro"
signingConfig signingConfigs.release
}
}
repositories {
//添加aar
flatDir {
dirs 'libs'
}
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
api "com.android.support:appcompat-v7:27.1.1"
}
apply plugin:gradle插件,作为Android 的应用程序,这一步是必须的,因为plugin中提供了Android 编译、测试、打包等等的所有task。
-
android:关于android 的所有特殊配置都在这个代码块中,这就是由上面声明的 plugin 提供的。
- defaultConfig:程序的默认配置;这里配置的相关属性会覆盖
AndroidManifest.xml
中定义的属性(如versionName) - applicationId:定义了APP的包名,不同于
AndroidManifest.xml
中的package
属性。
- defaultConfig:程序的默认配置;这里配置的相关属性会覆盖
buildTypes:定义了编译类型,针对每个类型我们可以有不同的编译配置,不同的编译配置对应的有不同的编译命令。默认的有
debug
、release
的类型。dependencies:gradle 的依赖配置。它定义了当前项目需要依赖的其他库。
1.4、Gradle Wrapper
gradle wrapper
是针对gradle
新版本对旧版本的向后兼容性问题而使用的。
gradlw wrapper 包含一些脚本文件和针对不同系统下面的运行文件。wrapper 有版本区分,但是并不需要你手动去下载,当你运行脚本的时候,如果本地没有会自动下载对应版本文件。
在不同操作系统下面执行的脚本不同,在 Mac 系统下执行./gradlew ...,在windows 下执行gradle.bat进行编译。
- gradle wrapper目录结构:
demoApp |-- gradlew |-- gradlew.bat |-- gradle |-- wrapper |-- gradle-wrapper.jar |-- gradle-wrapper.properties
2、Android tasks
2.1、基本的tasks:
-
assemble
:对buildType
下的所有配置类型生成相应的apk包 -
clean
:移除所有编译输出的文件,如apk -
check
:执行lint
检测编译 -
build
:同时执行assemble
和check
这些基本的task,在实际项目中会根据不同的配置,会对这些task 设置不同的依赖。如默认的 assmeble
会依赖 assembleDebug
和assembleRelease
,如果直接执行assmeble
,最后会编译debug
和release
的所有版本出来。如果我们只需要编译debug
版本,我们可以运行assembleDebug
。
2.2、新增task:
-
install
,会将编译后的apk 安装到连接的设备。
3、相关配置
3.1、BuildConfig
这个类是由gradle根据配置文件生成的,通过配置一些key-value
的键值对,可以用BuildConfig获取相应的字段。例如:
//module下的build.gradle
buildTypes {
debug {
//配置网络请求根地址
buildConfigField 'String', 'API_URL', '"http://test.com/api/debug/"'
//配置app名称
resValue "string", "app_name", "测试版"
}
release {
//配置网络请求根地址
buildConfigField 'String', 'API_URL', '"http://test.com/api/release/"'
//配置app名称
resValue "string", "app_name", "上线版"
}
}
在使用时,只需要调用BuildConfig.API_URL
,就能获得当前环境(debug或release)下的值。
而用resValue
配置的,则不需要再strings.xml
中配置相应名称的值,否则会报错。
3.2、Repositories
repositories中配置的是代码仓库。在dependencies
中配置的一些依赖库都是从这里下载的。
Gradle 支持三种类型的仓库:Maven
、Ivy
和一些静态文件或者文件夹。在编译的执行阶段,gradle 将会从仓库中取出对应需要的依赖文件,当然,gradle 本地也会有自己的缓存,不会每次都去取这些依赖。
-
gradle 支持多种
Maven
仓库,一般常用的是jCenter
。//项目根目录下的build.gradle repositories { jcenter() google() }
-
有一些项目,可能是一些公司私有的仓库中的,这时候需要手动加入仓库连接,而有的需要用户名和密码,
//项目根目录下的build.gradle repositories { maven { url 'https://jitpack.io' credentials { username 'xxx' password 'yyy' } } }
-
可以使用相对路径配置本地仓库,通过配置项目中存在的静态文件夹作为本地仓库:
//module下的build.gradle android { ...... repositories { flatDir { dirs 'libs' } } }
3.3、Dependencies
依赖库的配置。
- File dependencies
通过files()方法可以添加文件依赖,如果有很多jar文件,我们也可以通过fileTree()方法添加一个文件夹,除此之外,我们还可以通过通配符的方式添加,如下:
//module下的build.gradle
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
}
- aar dependencies
可以将项目打包成aar
文件,通过文件的形式来引用:
//module下的build.gradle
//其中的aarname是打包的aar文件的名称,后面的ext是固定的
dependencies {
api(name: 'aarname', ext: 'aar')
}
3.4、Source sets
封装所有变体的源集配置。
- 1、Native libraries
配置本地 .so库。在配置文件中做如下配置,然后在对应位置建立文件夹,加入对应平台的.so文件。
//方式一:
android {
sourceSets {
main {
jniLibs.srcDirs = ['libs', , 'src/main/jni']
}
}
}
//方式二
android {
sourceSets.main {
jni.srcDirs 'libs'
}
}
- 2、配置源集:
sourceSets { main { //更改Java源的目录。默认目录是:'src/main/java'。 java.srcDirs = ['other/java'] // 默认目录是'src/main/res' res.srcDirs = [ 'other/res1', 'other/res2' ] //设置清单。默认目录是:src/main/AndroidManifest.xml manifest.srcFile 'other/AndroidManifest.xml' ... } //创建其他块以配置其他源集。 androidTest { setRoot 'src/tests' ... } }
main
中的res.srcDirs
如果列出多个目录,Gradle将使用它们来收集源。由于Gradle为这些目录提供了相同的优先级,如果在多个目录中定义相同的资源,则在合并资源时会出现错误。对于每个源集,只能指定一个AndroidManifest.xml。
如果源集的所有文件都位于单个根目录下,则可以使用setRoot属性指定该目录。收集源集的源时,Gradle仅在相对于您指定的根目录的位置中查找。例如,在将配置应用于androidTest源集之后,Gradle仅在
src/tests/java/
目录中查找Java源。
3.5、Product flavors:
关于构建不同的Product flavors
,可以参考如下:
Build Variants
技术:Android打包签名总结
4、Gradle模板举例
-
4.1、Project的
build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules. //全局引入gradle文件 apply from: 'dependencies.gradle' //gradle脚本执行所需依赖,包含依赖仓库和插件 buildscript { //配置远程仓库 repositories { //从Android Studio3.0后新增了google()配置,可以引用google上的开源项目 google() //一个类似于github的代码托管仓库,声明了jcenter()配置,可以轻松引用 jcenter上的开源项目 jcenter() //本地仓库 mavenLocal() //maven中央仓库 mavenCentral() //指定maven仓库 maven { url "https://jitpack.io" } maven { url 'https://maven.google.com' } } //配置插件 dependencies { //此处是android的插件gradle,gradle是一个强大的项目构建工具 classpath 'com.android.tools.build:gradle:3.2.1' //其他插件,这里是数据库greendao的插件 classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' } } //项目本身需要的依赖,比如项目所需的maven库 allprojects { repositories { jcenter() google() maven { url 'https://jitpack.io' } maven { url 'https://maven.google.com' } } } //清除任务 task clean(type: Delete) { delete rootProject.buildDir }
-
4.2、Module的
build.gradle
//app应用插件,声明为Android应用程序 apply plugin: 'com.android.application' //表示是一个应用程序模块,直接运行 //apply plugin: 'com.android.library' //表示是一个库模块,被其他module依赖 apply plugin: 'walle' //其他插件,这里是打包插件 //定义变量 def versionConfigs = rootProject.extensions.getByName("ext") android { //编译时用的Android版本 compileSdkVersion versionConfigs.androidCompileSdkVersion //构建工具的版本 buildToolsVersion versionConfigs.androidBuildToolsVersion //默认配置,会被下面的相同的配置覆盖 defaultConfig { //项目包名,唯一标识,和AndroidManifest.xml中的package(Java文件包名)不同 applicationId "com.example.app" //程序最低兼容的运行版本,低于此版本无法安装 minSdkVersion versionConfigs.androidMinSdkVersion //项目的目标版本 targetSdkVersion versionConfigs.androidTargetSdkVersion //版本号 versionCode VERSION_CODE as int //版本名称,给用户看的 versionName VERSION_NAME //支持multidex // multiDexEnabled true //表明要使用AndroidJUnitRunner进行单元测试 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } //程序在编译的时候会检查lint,有任何错误提示会停止build,我们可以关闭这个开关 lintOptions { //打包release版本的时候进行检测 checkReleaseBuilds false //即使报错也不会停止打包 abortOnError false //屏蔽translate引起的warning disable "MissingTranslation" } //自动化打包配置,可以自定义配置多种打包配置 signingConfigs { //测试配置 debug { //debug签名文件路径 storeFile file("../debug.jks") //签名相关信息,配置在了gradle.properties中了 storePassword SIGNINGCONFIGS_PSW keyAlias SIGNINGCONFIGS_KEYALIAS keyPassword SIGNINGCONFIGS_PSW } //上线配置 release { //release签名文件路径 storeFile file("../release.jks") //签名相关信息,配置在了gradle.properties中了 storePassword SIGNINGCONFIGS_PSW keyAlias SIGNINGCONFIGS_KEYALIAS keyPassword SIGNINGCONFIGS_PSW } } //构建类型,可自定义多种类型 buildTypes { debug { minifyEnabled false //是否混淆 shrinkResources false //去除没有用到的资源文件 } release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), "$rootDir/ModuleLibs/config/proguard-rules.pro" signingConfig signingConfigs.release } } repositories { //添加本地aar目录 flatDir { dirs 'libs' } } //配置源集 sourceSets {//目录指向配置 main { jniLibs.srcDirs = ['libs']//指定lib库目录 } } } //依赖 dependencies { //本地文件依赖 api fileTree(include: ['*.jar'], dir: 'libs') //测试用例库 testImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) //依赖corelib的module api project(':corelib') //定义外部变量的引用 def andlibs = rootProject.ext.andlibs def libs = rootProject.ext.libs api andlibs.appcompat_v7 }
相关链接:
Android Plugin DSL Reference
Gradle Android插件用户指南翻译
深入理解Android之Gradle
史上最全Android build.gradle配置详解
Gradle 完整指南(Android)
Gradle 提速:每天为你省下一杯喝咖啡的时间