系列文章:
1. 前言
我们都知道利用Android Studio编写APP时,会使用Gradle这个工具,那么Gradle到底是什么呢?它在APP编写中起到什么作用呢?
Gradle是一个项目自动化建构工具。构建就是根据输入信息执行一系列操作,最后得到几个产出物(APK包)。
传统的构建工具有Ant和Maven,但他们有一些缺点,例如Maven使用XML来制定构建规则。XML虽然通俗易懂,但是很难在xml中描述if{某条件成立,编译某文件}/else{编译其他文件}这样有不同条件的任务。针对这类问题自然需要编程来解决,所以,Gradle选择了Groovy语言。
Gradle的另一个特点是它是一种DSL(Domain-Specific-Language),即特定领域语言,就是针对某一领域而产生的语言。DSL的好处是一句话可以包含很多意思,因为只针对特定领域解决问题。
Gradle当前其支持的语言限于Java、Groovy和Scala,计划未来将支持更多的语言。Gradle可以帮你管理项目中的差异,依赖,编译,打包,部署...,你可以定义满足自己需要的构建逻辑,写入到build.gradle中供日后复用,通俗的说:gradle是打包用的。
1.1 Groovy基础
Groovy是个灵活的动态脚本语言,基于JVM虚拟机,语法和Java很相似,又兼容Java,且在此基础上增加了很多动态类型和灵活的特性,如支持闭包和DSL。Groovy的开发环境配置可以参考Groovy 环境配置,具体语言特性教程可以参考-Groovy教程。
Groovy基于Java,又扩展了Java,运行过程中首先会先将其编译成Java类字节码,然后通过JVM来执行这个Java类。
1.2 Gradle介绍
Gradle是一个工具,也是一个编程框架。要弄清楚Gradle,则必须知道其组成的基本组件,Gradle中每个待被编译的工程叫Project,每个Project在构建时都包含一系列Task,如Android Studio构建过程中包括Java代码编译Task,资源编译Task,Lint规则检查Task,签名Task等等。
配置Gradle环境前,确保已经安装配置好Java环境,下载Gradle后解压并配置环境变量,具体可以参考-配置Gradle
下面是一个Gradle语言版的Hello word例子:
// Gradle版Hello word
// 新建build.gradle文件:
task hello{ // 定义一个任务Task名为hello
doLast{ // 添加一个动作Action,表示在Task执行完毕后回调doLast闭包中的代码
println'Hello World'//输出字符串,单双号均可
}
}
// 命令行:
gradle hello // 执行build.gradle中名为Hello的任务
// 输出:
Hello World
总而言之,学习Gradle我们需要掌握Groovy语言,以及Gradle在Android Studio中的工作方式,工作流程,工作原理。
2. Android studio中的Gradle文件
Android Studio 会使用高级构建工具包 Gradle 来自动执行和管理构建流程,同时也允许开发者定义灵活的自定义版本配置。每个版本配置均可定义自己的一组代码和资源,同时重复利用应用各个版本的共用部分。
Gradle提供了一种编译、构建和打包 Android 应用或库的灵活方式。
一个Android Studio和Gradle的项目目录如下:
我们先来看看Android Gradle项目中那些涉及到gradle的文件分别是什么意思。
一个Android项目中所有文件的具体含义可参考Android开发者指南
2.1 Gradle wrapper(gradle包装)
上图中涉及到Gradle wrapper的部分如下所示,具体有上图中的gradle文件夹,gradlew文件和gradlew.bat批处理文件。
|--gradle
| |--wrapper
| |--gradle-wrapper.jar
| |--gradle-wrapper.properties
|--gradlew
|--gradlew.bat
gradle文件夹中包含wrapper,wrapper顾名思义是对Gradle的一层包装,便于在团队开发过程中统一Gradle构建的版本。
上面目录中gradlew
和gradlew.bat
分别是Linux和Windows下的可执行脚本,gradle-wrapper.jar
是具体业务逻辑实现的jar包,gradlew
可执行脚本最终还是使用这个jar包来执行相关Gradle
操作,gradle-wrapper.properties
是配置文件,用于配置使用哪个版本的Gradle,配置文件中的具体内容如下所示:
#Wed Jun 19 10:09:08 GMT+08:00 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
2.2 Settings.gradle (多工程配置)
此文件用于初始化以及工程树的配置,大多数用于配置子工程,在Gradle中多个工程是通过工程树来表示的,相当于我们在Android Studio看到的Project和Module概念一样,根工程相当于Project,子工程相当于Module,一个Project可以有很多Module,一个子工程只有在Setting.gradle
中配置了才会生效。
配置举例:
// 添加:app和:common这两个module参与构建
include ':app'
project(':app').projectDir = new File('存放目录')
include':common'
project(':common').projectDir = new File('存放目录')
如果不指定上述存放目录,则默认为是Settings.gradle
其同级目录。
2.3 build.gradle文件(版本文件)
每个工程都会有build.gradle文件,该文件是该工程的构建入口,在此文件中可以对该工程进行配置,如配置版本,插件,依赖库等。
既然每个工程都有一个build文件,那么根工程也不例外,在根工程中可以对子Module进行统一配置,全局管理版本号或依赖库。
build文件分为Project和Module两种,如下图所示:
- Project的build.gradle:整个Project的共有属性,包括配置版本、插件、依赖库等信息
- Module的build.gradle:各个module私有的配置文件
2.3.1 Project中build.gradle文件(顶层版本文件)
buildscript {
// gradle脚本执行所需依赖仓库
repositories {
google()
jcenter()
}
// gradle脚本执行所需依赖
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
}
}
allprojects {
// 项目本身需要的依赖仓库
repositories {
google()
jcenter()
}
}
那么buildscript中的repositories和allprojects的repositories的作用和区别是什么呢?
- buildscript里是gradle脚本执行所需依赖,分别是对应的maven库和插件;
- allprojects里是项目本身需要的依赖,比如我现在要依赖maven库的xx库,那么我应该将maven {url '库链接'}写在这里,而不是buildscript中,否则找不到所需要的库。
参考 作者:CalvinNing -原文链接
2.3.2 Module中build.gradle文件(模块级版本文件)
此部分内容参考下文中3.3.2节。
2.4 gradle.properties(属性文件)
此文件主要在其中配置项目全局 Gradle 设置,如 Gradle 守护进程的最大堆大小。如需了解详情,请参阅构建环境
3. Gradle插件
3.1 插件介绍
Gradle的设计非常好,本身提供一些基本的概念和整体核心的框架,其他用于描述真实使用场景逻辑的都以插件扩展的方式来实现,比如构建Java应用,就通过Java插件来实现,那么自然构建Android应用,就通过Android Gradle插件来实现。
Gradle 提供了很多官方插件,用于支持Java、Groovy等工程的构建和打包。同时也提供了自定义插件机制,让每个人都可以通过插件来实现特定的构建逻辑,并可以把这些逻辑打包起来,分享给其他人。
Android Gradle插件是基于内置的Java插件实现的。Gradle插件的作用如下:
- 可以添加任务到项目,比如测试、编译、打包等
- 可以添加依赖配置到项目,帮助配置项目构建过程中需要的依赖,比如第三方库等
- 可以向项目中现有的对象类型添加新的扩展属性和方法等,帮助配置和优化构建
- 可以对项目进行一些约定,比如约定源代码存放位置等
3.2 插件种类及用法
3.2.1 插件种类
- 二进制插件:实现了org.gradle.api.Plugin接口的插件,拥有plugin id,这个 id 是插件全局唯一的标识或名称
- 脚本插件:严格上只是一个脚本,即自定义的以 .gradle 为后缀的脚本文件,可以来自本地或网络
3.2.2 插件用法
下面分别说下二进制插件和脚本插件的使用方法,
- 二进制插件:
id式:apply plugin:'plugin id'
类型式:apply plugin:org.gradle.api.plugins.JavaPlugin
简写式:apply plugin:JavaPlugin
- 脚本插件:apply from:'version.gradle'
- 第三方发布插件:apply plugin:'com.android.application'
3.3 Android Gradle插件
从Gradle的角度看,Android其实就是Gradle的一个第三方插件,它是由Google的Android团队开发的,Android 开发 IDE Android Studio 就采用 Gradle 构建项目。
3.3.1 Android Gradle插件分类
- App应用工程:生成可运行apk应用;插件id: com.android.application
- Library库工程:生成AAR包给其他的App工程公用,其使用方式和jar包一样,里面有相关的 Android 资源文件;插件id: com.android.library
- Test测试工程:对App应用工程或Library库工程进行单元测试;插件id: com.android.test
3.3.2 Android Gradle插件的应用
主要来看下Android Gradle的build.gradle配置文件:
// 插件id
apply plugin:'com.android.application'
// 自定义配置入口,后续详解
android{
compileSdkVersion 23 // 编译Android工程的SDK版本
buildToolsVersion "23.0.1" // 构建Android工程所用的构建工具版本
defaultConfig{
applicationId "com.example.myapplication" // 配置包名
minSdkVersion 14 // 最低支持的Android系统的Level
targetSdkVersion 23 // 表示基本哪个Android版本开发
versionCode 1 // APP应用内部版本名称
versionName "1.0" // APP应用的版本名称
}
buildTypes{
release{ // 构建类型
minifyEnabled false // 是否启用混淆
proguardFiles getDefaultPraguardFile('proguard-andrcid.txt'), 'proguard-rules.pro' // 配置混淆文件
}
}
}
// 配置第三方依赖
dependencies{
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
android{}是Android Gradle插件提供的一个扩展类型,可以让我们自定义Android Gradle工程。defaultConfig{}是默认的配置,是一个ProductFlavor(构建渠道),ProductFlavor允许我们根据不同的情况同时生成不同的APK包。buildTypes{}是一个NamedDomainObjectContainer类型,是一个域对象,可以在buildTypes{}里新增任意多个我们需要构建的类型,比如debug类型。
NamedDomainObjectContainer具体可以参考-NamedDomainObjectContainer详解
3.3.3 多渠道构建
由于发布或者推广APP的渠道不同,就造成了Android APP可能会有很多个,所以需要针对不同的渠道做不同的处理。
在Android Gradle中,定义了一个叫Build Variant(构建变体/构建产物)的概念,一个构建变体(Build Variant)=构建类型(Build Type)+构建渠道(Product Flavor),下面举个例子:
- Build Type有release、debug两种构建类型
- Product Flavor有baidu、google两种构建渠道
- Build Variant有baiduRelease、baiduDebug、googleRelease、googleDebug四种构件产物
配置好发布渠道后,Android Gradle插件就会生成很多task,比如assembleBaidu,assembleRelease,assembleBaiduRelease等
Gradle中一个原子性的操作叫做task,简单理解为task是Gradle脚本中的最小可执行单元。
- assemble开头的Task负责生成构件产物(Apk)
- assembleBaidu:运行后会生成baidu渠道的release和debug包
- assembleRelease:运行后会生成所有渠道的release包
- assembleBaiduRelease:运行后只会生成baidu的release包
4. Android Studio Gradle插件构建流程
4.1 Gradle生命周期
- Initialization(初始化阶段):Gradle支持单项目和多项目构建。在初始化阶段,Gradle确定将要参与构建的项目,并为每个项目创建一个Project对象。通俗的说就是执行上述settings.gradle文件。
- Configuration(配置阶段):在此阶段,解析每个Project中的build.gradle文件,并生成将要执行的task。
- Execution(执行阶段):执行 task,进行主要的构建工作
4.2 APK构建流程
构建流程涉及许多将项目转换成 Android 应用软件包 (APK)的工具和流程,具体如下图所示:
Android 应用模块的构建流程通常按照以下步骤执行:
- 编译器将您的源代码转换成 DEX 文件(Dalvik 可执行文件,其中包括在 Android 设备上运行的字节码),并将其他所有内容转换成编译后的资源;
- APK 打包器将 DEX 文件和编译后的资源合并到一个 APK 中。不过,在将应用安装并部署到 Android 设备之前,必须先为 APK 签名。
- APK 打包器使用调试或发布密钥库为 APK 签名:
- a. 如果构建的是调试版应用(即专用于测试和分析的应用),则打包器会使用调试密钥库为应用签名。Android Studio 会自动使用调试密钥库配置新项目。
- b. 如果构建的是打算对外发布的发布版应用,则打包器会使用发布密钥库为应用签名
- 在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,以减少其在设备上运行时所占用的内存。
构建流程结束时,将获得应用的调试版 APK 或发布版 APK,以用于部署、测试或发布给外部用户。
以上摘自Android开发者指南
行文至此,本文已大概理清Gradle的基本概念,以及其在Android Studio中的工作流程,但Android Studio中Gradle的工作具体细节还未解释,如点击Run图标背后的Gradle的具体工作流程是什么?这些会在后续博客中继续分析。