1 Gradle的一些概念

Android Studio默许的构建东西为Gradle。在运用Gradle的进程中会碰到一些概念,理清他们的意义联系对咱们运用和深化理解Gradle至关重要。

1.1 Gradle 、AGP(Android Gradle Plugin)、 buildTools分别是什么,他们之间什么联系?

视角拉高,系统性地梳理下Gradle

1.1.1 Gradle

Gradle是根据JVM的构建东西。他自身运用jave写的,gradle的脚本也便是build.gradle通常是用groovy言语。

1.1.2 Android BuildTools

Android SDK Build-Tools 是构建 Android apk、AAR文件等Android渠道产品所需的一个 Android SDK 组件,装置在 <sdk>/build-tools/ 目录下。

//build-tools/
├── ⋮
├── aapt2
├── d8
├── apksigner
├── zipalign
├── ⋮
​
  • AAPT2:Android 资源打包东西)是一种构建东西,Android Studio 和 Android Gradle 插件运用它来编译和打包运用的。AAPT2 会解析资源、为资源编制索引,并将资源编译为针对 Android 渠道进行过优化的二进制格式
  • apksigner:东西为 APK 签名,并保证 APK 的签名将在该 APK 支撑的一切版别 Android 渠道上成功经过验证
  • d8:Android Gradle 插件运用该东西来将项目的 Java 字节码编译为在 Android 设备上运行的 DEX 字节码
  • Zipalign:在将 APK 文件分发给最终用户之前,先运用 zipalign 进行优化

1.1.3 Android Gradle Plugin

是根据Gradle的插件,Android Gradle 首要便是调用[Android BuildTools]这个包里的东西完结编译打包Apk等功能。

注:AGP3.0.0或更高版别,插件会运用默许版别的build Tools无需指定。

android { buildToolsVersion "33.0.1"}

1.2 gradleWrapper、gradle-user-home、GradleHome

1.2.1 GradleWrapper

项目的根目录的gradle/wrapper下

   /gradle/wrapper/
   ├── gradle-wrapper.jar 
   └── gradle-wrapper.properties 

担任下载办理特定版别的gradle,保证不同环境中项目运行在相同个gradle版别里,还能到达复用效果。

  • gradlewraper目录下的gradle.jar负载下载gradle
  • gradle-wrapper.properties内指定gradle的版别,下载地址,本地方位等装备信息。

1.2.1 GRADLE-USER-HOME

   gradle-user-home
   ├── caches  // modules-2和jars-3缓存依靠和产品,且各个版别各个项目中共用
   │  ├── jars-3 
   |  ├── transforms-3
   │  └── modules-2 
   ├── wrapper //存放不同版别的gradle
   │  └── dists 
   │    ├── ⋮
   │    └── gradle-7.4-bin
   |      └── xxxxxxxx
   |         └──gradle-7.3.3 //其实这是gradle home路径
   └── gradle.properties 

默许在方位位于/.gradle。这个目录下包括用户自界说的设置、maven本地仓库、gradle wrapper版别、gradle插件和一些缓存。其间该路径下caches文件夹有repo缓存也便是项目的依靠缓存,这个缓存各个项目是公用的,提升编译速度。

1.2.3 Gradle Home

gradle-home
├── bin
│  ├── gradle.bat
│  └── gradle
├── init.d
│   ├──..
│   └── xx.gradle
└── lib
    ├──...
    ├── gradle-wrapper-7.3.3.jar
    ├── gradle-tooling-api-7.3.3.jar
    ├──...
    └── plugins
        ├── ...
        ├── gradle-publish-7.3.3.jar
        ├── commons-codec-1.15.jar  
        └──...

其实便是gradle的装置目录,里面首要包括Gradle 的可履行文件、库文件、插件等,gradle履行时会自动加载运用装置目录内的文件插件。

2 Gradle生命周期

Gradle履行构建是有生命周期的,分三个阶段初始化阶段(Initialization Phases),装备阶段(Configuration Phases)和履行阶段(Execution Phases)。

2.1 初始化阶段

  • 履行init.gradle脚本:init.gradel脚本能够放置在gradle-user-home目录下、gradle-user-home/init.d/和gradle-home/init.d/目录下,其间后两者下的脚本称号只要一.gralde结束即可。他们的履行顺序为依次履行。在脚本里咱们能够设置一些个性化的装备,如装备repo源、鉴权等。
  • 履行setting脚本:gradle会嗅探项目里的settings文件,settings文件中界说哪些项目参加到构建中。在settings.gradle文件中能够设置一些对一切参加的构建的项目做装备,也能够有针对性的做装备。
  • 创立project实例:为参加到构建中的项目创立project实例。咱们在项目的build.gradle脚本里运用的project目标便是在这个时机创立的。

2.2 装备阶段

  • 运用插件:下载运用声明的插件,脚本里有两种写法一种是apply plugin和plugins{}。他们的差异暂不作打开。
  • 装备特点:给插件做参数装备,咱们最熟悉的android{}闭包其实便是对AGP里的com.android.application插件做参数装备。
  • 运用依靠:gradle脚本中声明运用的依靠也会在装备阶段下载运用。
  • 构建有向无环task使命图。

*注意:*履行任何task都会走初始化阶段和装备阶段

2.3 履行阶段

履行上一个阶段也便是装备阶段结构好的有向无环图使命。

tasks.register('test') {
 println '该语句会在装备阶段履行'
  doLast {
    println '该语句会在履行阶段运行'
   }
}

3 监听Gradle生命周期回调

视角拉高,系统性地梳理下Gradle

3.1 监听初始化阶段回调

初始化阶段首要有两个能接回收调的地方settingEvaluated{}和 gradle.projectsLoaded {}

 //settings.gradle装备履行完结
  gradle.settingsEvaluated {
     ...
   }

settingEvaluated{}setting创立加载成功。在此之前有几项gradle有几项重要的工作现已完结。

  • gradle.properties 加载完结
  • init脚本履行完结
  • Settings目标创立成功,并且从gradle.properties加载的值也注入到了settings中
  // 一切 Project 目标创立(注意:此刻 build.gradle 中的装备代码还未履行)
  gradle.projectsLoaded {
    ...
  }

初始化阶段还有扫描项目下的一切包括位于根project和子project中的build.gradle并对应生成Project目标,目标创立完结之后就会调用gradle.projectsLoaded{},但注意此刻build.gradle 中的装备代码还未履行。

3.2 装备阶段的回调

装备阶段会对项目下的每个build.gradle进行装备,如上图,beforeProject{}/project.beforeEvaluated{}和afterProject{}/after.beforeEvaluate会履行屡次,这取决于构建项目下有几个project。

  • beforeProject{}/project.beforeEvaluated{}:会在每个project装备之前调用.
  • afterProject{}/after.beforeEvaluate:会在build.gradle脚本”从头跑到尾”之后调用。
  • 当一切的gradle.build都履行结束后,会调用projectEvaluted{}
  • 最终,task图构建完结后,回调gradle.taskGraph.whenReady {}和gradle.taskGraph.taskExecutionGraphListener.graphPopulated()

3.3 hook履行阶段

每个task履行前后,咱们也有方法去监听:首要是运用gradle.taskGraph.beforeTask{} 和gradle.taskGraph.afterTask {},如下:

gradle.taskGraph.beforeTask { Task task ->
  println "executing $task ..."
}
​
gradle.taskGraph.afterTask { Task task, TaskState state ->
  if (state.failure) {
    println "FAILED"
   }
  else {
    println "done"
   }
}
  • !!!注意: 这些办法在gradle8.0现已直接被移除掉了统统不能用,原因简单的说便是影响cofigurationCache详细看这儿: task_execution_events
  • 替代的方法:运用build_service

4 Gradle项目结构

root-project
├── buildSrc
|  ├── ...
│  └── build.gradle
├── sub-project
│  └── build.gradle
├── build.gradle
├── settings.gradle
├── gradle.properties
├── gradle
│  └── wrapper
│    ├── gradle-wrapper.jar
│    └── gradle-wrapper.properties
├── gradlew(Unix Shell script)
└── gradlew.bat(Windows batch file)

4.1 buildSrc

  • buildSrc是位于gradle项目根目录的特殊目录,咱们能够在这编写Gradle的插件和使命。
  • 这儿面的代码会在gardle的装备阶段履行。

4.2 gradle.Properties

  • 在gradle-user-home目录下,项目根目录下和子项目目录下(和build.gradle同级)下都能够存在。
  • gradle.properties界说的值有些时装备gradle环境特点,也能够增加自己自界说的特点,在咱们的构建脚本中能够直接访问这些值。
//gradle.properties中
mVersionName=1.12.1
​
//build.gradle
println("mVersion name in gradle.properties ${mVersionName}")

4.3 build.gradle和settings.gradle 文件

Gradle国际里经过初始化阶段后,build.gradle文件会对应生成Poject目标,settings.gradle文件会生成Settings目标,其实还有Gradle目标,每次构建启动时就会创立。

5 plugin 与 task

5.1 Gradle Plugin

Gradle是一个构建框架,自身不具备特别强的构建才能,详细构建才能依托于Gradle Plugin ,比如要打包APK就要依托AGP。AGP 内部经过调用Android Build Tool 去详细履行诸如编译class,打包资源等使命。

5.1.1 Apply plugin方法引进

Gradle Plugin的是运用首先是引进,就跟咱们在项目里需求某个第三方库需求引进相同。在跟目录的build.gradle中就可声明这些依靠,然后在构建脚本里声明运用,然后做装备。

//in rootproject/build.gradle
buildscript {
  ...
   dependencies {
     classpath:'com.android.tools.build:gradle:x.x.x'
   }
}
​
//in subProject/build.gradle
apply plugin: 'com.android.application'//用于打包生成Apk
android {//构建Apk的装备
}
​
//in subProject2/build.gradle
apply plugin: 'com.android.library'//用于打包产出AAR
android{ //构建发生aar装备
}

如果在脚本gradle脚本中想运用一个第三方库,也需求经过classpath引进,然后就能够在脚本中运用了,示例如下。

//in root project build.gradle
buildscript {
   dependencies {
     classpath: 'com.squareup.okhttp3:okhttp:3.14.9'
   }
}
import okhttp3.OkHttpClient
task("checkClasspath").doFirst {
  //在脚本中运用引进了的okhttp
  def client = new OkHttpClient()
  ..,
}

5.1.2 plugin{}脚本块引进

以上这种运用plugin的方法是分两步【引进+运用】,gradle还有引进和运用一步搞定的方法。

plugin{ id 'com.android.library' version 'x.x.x' }

默许的这种不需求引进就能运用插件的方法,插件来源只能是gradle 插件官网plugins.gradle.org/,如果想运用自己的插件需求在pluginManagement中装备源如下

//settings.gradle
pluginManagement {
  repositories {
    maven {
      url './maven-repo'
     }
   } 
 }

5.1.3 其他

Gradel插件分两种:二进制插件和脚本插件;二进制插件便是被打包成了jar包的插件。脚本插件.gradle文件能够被作为插件运用。这种插件的运用只能经过apply plugin方法不能运用plugin{}的方法。

//config.gradle中

ext {
  mVersion = '1.1.0'
}

//build.gradle

apply from: "../config.gradle"
println("mVersion${ext.mVersion}")

5.2 Task

5.2.1 履行动作

视角拉高,系统性地梳理下Gradle

  • 上文也提到过,gradle的一次构建,便是一系列task的履行,task便是gradle的一个履行单元。
  • 一个gradle项目中包括若干个project,每个project中包括若干个task。
  • 一个gradle task里面会包括若干个action。

5.2.2 创立task

task一般都界说在plugin中,咱们也能够自己界说task,给其装备姓名,描绘,分组,action,依靠联系等。

//build.gradle
project.tasks.register("aTask") {
  println 'in configuration phase'
  it.description("this is a sample task")
  it.dependsOn("hello")
  group("build")//IDE右边的Gradle便利东西栏中,会看到该task被归类到build分组内,便利查找
  description "this is a gradle hello sample" //描绘
  it.doLast {
    println("do action >>1") //向当时task的action链路后追加action
   }
  it.doFirst {
    println("do aciton >>2")//向当时task的action链路前查action
   }
}
​
project.tasks.register("hello") {
  it.doLast {
    println("hello task is excuted-")
   }
}
​

以上只是一个简单的比如,task的创立运用能够单开一个章节。

6 结

本文首要是在一个可能比较高的视角,谈了谈gradle相关的概念,生命周期特性,插件task等。把握了这些之后,还有一些更深化更详尽的论题值得探索。比如

  • 自界说插件,详尽的Task详解
  • gradle tansformer
  • 构建性能怎么提升
  • AGP常见的装备
  • Gradle项目实战

今后会写系列文章去逐个探索,关注作者获取更新

写文不易,过错不足之处望不吝赐教,点赞鼓励