Android中用到的Gradle原理是什么?

系列文章

  1. Android Gradle原理解释
  2. Android Studio点击Run背后发生了什么?

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等等。

参考深入理解Android之Gradle

配置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的项目目录如下:

gradlelist.png

我们先来看看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构建的版本。

上面目录中gradlewgradlew.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两种,如下图所示:

build_gradle.png
  1. Project的build.gradle:整个Project的共有属性,包括配置版本、插件、依赖库等信息
  2. 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的作用和区别是什么呢?

  1. buildscript里是gradle脚本执行所需依赖,分别是对应的maven库和插件
  2. 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插件的作用如下:

  1. 可以添加任务到项目,比如测试、编译、打包
  2. 可以添加依赖配置到项目,帮助配置项目构建过程中需要的依赖,比如第三方库等
  3. 可以向项目中现有的对象类型添加新的扩展属性和方法等,帮助配置和优化构建
  4. 可以对项目进行一些约定,比如约定源代码存放位置

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插件分类

  1. App应用工程:生成可运行apk应用;插件id: com.android.application
  2. Library库工程:生成AAR包给其他的App工程公用,其使用方式和jar包一样,里面有相关的 Android 资源文件;插件id: com.android.library
  3. 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)
  1. assembleBaidu:运行后会生成baidu渠道的release和debug包
  2. assembleRelease:运行后会生成所有渠道的release包
  3. assembleBaiduRelease:运行后只会生成baidu的release包

4. Android Studio Gradle插件构建流程

4.1 Gradle生命周期

gradle_lifecycle.png
  1. Initialization(初始化阶段):Gradle支持单项目和多项目构建。在初始化阶段,Gradle确定将要参与构建的项目,并为每个项目创建一个Project对象。通俗的说就是执行上述settings.gradle文件。
  2. Configuration(配置阶段):在此阶段,解析每个Project中的build.gradle文件,并生成将要执行的task。
  3. Execution(执行阶段):执行 task,进行主要的构建工作

4.2 APK构建流程

构建流程涉及许多将项目转换成 Android 应用软件包 (APK)的工具和流程,具体如下图所示:

android_gradle_build.png

Android 应用模块的构建流程通常按照以下步骤执行:

  1. 编译器将您的源代码转换成 DEX 文件(Dalvik 可执行文件,其中包括在 Android 设备上运行的字节码),并将其他所有内容转换成编译后的资源
  2. APK 打包器将 DEX 文件和编译后的资源合并到一个 APK 中。不过,在将应用安装并部署到 Android 设备之前,必须先为 APK 签名。
  3. APK 打包器使用调试或发布密钥库为 APK 签名
  • a. 如果构建的是调试版应用(即专用于测试和分析的应用),则打包器会使用调试密钥库为应用签名。Android Studio 会自动使用调试密钥库配置新项目。
  • b. 如果构建的是打算对外发布的发布版应用,则打包器会使用发布密钥库为应用签名
  1. 在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,以减少其在设备上运行时所占用的内存。

构建流程结束时,将获得应用的调试版 APK 或发布版 APK,以用于部署、测试或发布给外部用户。

以上摘自Android开发者指南

行文至此,本文已大概理清Gradle的基本概念,以及其在Android Studio中的工作流程,但Android Studio中Gradle的工作具体细节还未解释,如点击Run图标背后的Gradle的具体工作流程是什么?这些会在后续博客中继续分析。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容