目前,Gradle 自动化技术愈来愈重要,也有许多同窗已经可以制做出本身的 Gradle 插件,可是一直有一些 “梗” 遗留在咱们脑海中,无时无刻不提醒着咱们,你真的掌握了吗?例如,“梗1”:Gradle 插件的总体实现架构?我:...,“梗2”:Android Gradle 插件更新历史有哪些重要优化或者改进?我:..., “梗3”:Gradle 构建的核心流程是怎样的?我:...,“梗4”:Gradle 中依赖实现的原理?我:..., “梗5”:AppPlugin 构建流程?我:..., “梗6”:assembleDebug 打包流程?我:...., “梗7”:一些很重要 Task 实现原理可否说说?我:... 。是否有不少点并无真正地去了解过呢?html
Android Gradle plugin 团队在 Android Gradle V3.2.0 以前一直是都是用 Java 编写的 Gradle 插件,在 V3.2.0 便采用了 Kotlin 进行大面积的重写。尽管 Groovy 语法简洁,且其闭包的写法很是灵活,可是 Android Studio 对 Groovy 的支持很是不友好,所以,目前写自定义的 Gradle 插件时咱们仍是尽可能使用 Kotlin,这样能尽可能避免编写插件时提示不够形成的坑。java
下面,咱们就来看看 Gradle 插件的总体实现架构,以下图所示:node
在最下层的是底层 Gradle 框架,它主要提供一些基础的服务,如 task 的依赖,有向无环图的构建等等。android
上面的则是 Google 编译工具团队的 Android Gradle plugin
框架,它主要是 在 Gradle 框架的基础上,建立了不少与 Android 项目打包有关的 task 及 artifacts(每个 task 执行完成以后一般都会输出产物)。git
最上面的则是开发者自定义的 Plugin,关于自定义 Plugin 一般有两种使用套路,以下所示:github
下表列出了各个 Android Gradle 插件版本所需的 Gradle 版本。咱们应该使用 Android Gradle Plugin 与 Gradle 这二者的最新版本以得到最佳的性能。web
插件版本 | 所需的 Gradle 版本 |
---|---|
1.0.0 - 1.1.3 | 2.2.1 - 2.3 |
1.2.0 - 1.3.1 | 2.2.1 - 2.9 |
1.5.0 | 2.2.1 - 2.13 |
2.0.0 - 2.1.2 | 2.10 - 2.13 |
2.1.3 - 2.2.3 | 2.14.1+ |
2.3.0+ | 3.3+ |
3.0.0+ | 4.1+ |
3.1.0+ | 4.4+ |
3.2.0 - 3.2.1 | 4.6+ |
3.3.0 - 3.3.2 | 4.10.1+ |
3.4.0 - 3.4.1 | 5.1.1+ |
3.5.0+ | 5.4.1-5.6.4 |
目前最新的 Android Gradle Plugin 版本为 V3.6.2,Gradle 版本为 V5.6.4。下面,咱们了解下 Android Gradle Plugin 更新历史中比较重要的更新变化。json
本次更新的重中之重是 提升项目的构建速度。bootstrap
若是使用的是 Gradle 5.0 及更高版本,默认的 Gradle 守护进程内存堆大小会从 1 GB 降到 512 MB。这可能会致使构建性能下降。若是要替换此默认设置,请在项目的 gradle.properties 文件中指定 Gradle 守护进程堆大小。设计模式
增长了新的依赖项配置 lintPublish,并更改了原有 lintChecks 的行为,它们的做用分别以下所示:
lintChecks
:
仅用于在本地构建项目时运行的 Lint 检查。
lintPublish
:
在已发布的 AAR 中启用 Lint 检查,这样使用此 AAR 的项目也会应用那些 Lint 检查。
其示例代码以下所示:
dependencies {
// Executes lint checks from the ':lint' project at build time.
lintChecks project(':lint')
// Packages lint checks from the ':lintpublish' in the published AAR.
lintPublish project(':lintpublish')
}
复制代码
在以前的版本可使用 com.android.feature
插件构建免安装应用,如今建议使用动态功能插件,这样即可以经过单个 Android App Bundle 发布安装版应用和免安装应用。
R8 将 desugar(脱糖:将 .class 字节码转换为 .dex 字节码的过程)、压缩、混淆、优化和 dex 处理整合到了一个步骤中,从而显著提高了构建性能。R8 是在 Android Gradle Plugin V3.2.0 中引入的,对于使用插件 V3.4.0 及更高版本的应用和 Android 库项目来讲,R8 已经默认处于启用状态。
能够看到,R8 组合了 Proguard、D8 的功能。若是遇到因 R8 致使的编译失败的问题,能够配置如下代码停用 R8:
# Disables R8 for Android Library modules only.
android.enableR8.libraries = false
# Disables R8 for all modules.
android.enableR8 = false
复制代码
此时使用 ndkBuild 编译原生库会收到构建错误。咱们应该 使用 CMake 或 ndk-build 将 C 和 C++ 代码添加到项目中。
在老版本中,Android Gradle 插件会为项目的每一个依赖项生成一个 R.java 文件,而后将这些 R 类和应用的其余类一块儿编译。如今,插件会直接生成包含应用的已编译 R 类的 JAR,而不会先编译中间的 R.java 类。这不只能够显著提高包含多个库子项目和依赖项的项目的编译性能,还能够加快在 Android Studio 中索引文件的速度。
R8 是一种执行代码压缩和混淆的新工具,替代了 ProGuard。咱们只需将如下代码添加到项目的 gradle.properties 文件中,便可开始使用 R8 的预览版本:
android.enableR8 = true
复制代码
默认状况下,Android Studio 此时会使用名为 D8 的新 DEX 编译器。DEX 编译是指针对 ART (对于较早版本的 Android,则针对 Dalvik)将 .class 字节码转换为 .dex 字节码的过程。与以前的编译器(DX)相比,D8 的编译速度更快,输出的 DEX 文件更小,同时却能保持相同甚至更出色的应用运行时性能。
若是在使用 D8 的过程当中出现了问题,能够在 gradle.properties 配置如下代码暂时停用 D8 并使用 DX:
android.enableD8=false
复制代码
更改依赖项时,Gradle 经过不从新编译那些没法被访问的依赖项 API 模块来加快编译速度。此时能够利用 Gradle 的新依赖项配置(implementation、api、compileOnly 和 runtimeOnly)限制哪些依赖项会将其 API 泄露给其余模块。
每一个类如今都会编译成单独的 DEX 文件,而且只会对修改过的类从新进行 dex 处理。
启用 Gradle 编译缓存可以优化某些任务来使用缓存的输出,从而加快编译速度。
若是在使用 AAPT2 时遇到了问题,咱们能够停用 AAPT2,在 gradle.properties 文件中设置以下代码:
android.enableAapt2=false
复制代码
而后,经过在命令行中运行 ./gradlew --stop 来重启 Gradle 守护进程。
存储编译项目时 Android 插件生成的特定输出。使用缓存时,编译插件的速度会明显加快,由于编译系统在进行后续编译时能够直接重用这些缓存文件,而没必要从新建立。此外,咱们也能够 使用 cleanBuildCache Task 去清除编译缓存。
更老版本的的更新细节请查阅 gradle-plugin。
当咱们输入 ./gradlew/gradle ... 命令以后,一个 Gradle 构建就开始了。它包含以下 三个步骤
:
在开始深刻源码以前,咱们能够先自顶向下了解下 Gradle 构建的核心流程图,以便对 Gradle 的构建流程创建一个总体的感知。
当咱们执行一个 gralde 命令时,便会调用 gradle/wrapper/gradle-wrapper.jar 里面 org.gradle.wrapper.GradleWrapperMain 类的 main 方法,它就是 gradle 的一个入口方法。该方法的核心源码以下所示:
public static void main(String[] args) throws Exception {
...
// 一、索引到 gradle-wrapper.properties 文件中配置的 gradle zip 地址,并由此包装成一个 WrapperExecutor 实例。
WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);
// 二、使用 wrapperExecutor 实例的 execute 方法执行 gradle 命令。
wrapperExecutor.execute(args, new Install(logger, new Download(logger, "gradlew", "0"), new PathAssembler(gradleUserHome)), new BootstrapMainStarter());
}
复制代码
而后,咱们继续看看 wrapperExecutor 的 execute 方法,源码以下所示:
public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {
// 一、下载 gradle wrapper 须要的依赖与源码。
File gradleHome = install.createDist(this.config);
// 二、从这里开始执行 gradle 的构建流程。
bootstrapMainStarter.start(args, gradleHome);
}
复制代码
首先,在注释1处,会下载 gradle wrapper 须要的依赖与源码。接着,在注释2处,便会调用 bootstrapMainStarter 的 start 方法从这里开始执行 gradle 的构建流程。其内部最终会依次调用 DefaultGradleLauncher 的 getLoadedSettings、getConfiguredBuild、executeTasks 与 finishBuild 方法,而它们对应的状态都定义在 DefaultGradleLauncher 中的 Stage 枚举类中,以下所示:
private static enum Stage {
LoadSettings,
Configure,
TaskGraph,
RunTasks {
String getDisplayName() {
return "Build";
}
},
Finished;
private Stage() {
}
String getDisplayName() {
return this.name();
}
}
复制代码
下面,咱们就对这五个流程来进行详细地分析。
当调用 getLoadedSettings 方法时便开始了加载 Setting.gradle 的流程。其源码以下所示:
public SettingsInternal getLoadedSettings() {
this.doBuildStages(DefaultGradleLauncher.Stage.LoadSettings);
return this.gradle.getSettings();
}
复制代码
这里又继续调用了 doBuildStages 方法进行处理,内部实现以下所示:
private void doBuildStages(DefaultGradleLauncher.Stage upTo) {
Preconditions.checkArgument(upTo != DefaultGradleLauncher.Stage.Finished, "Stage.Finished is not supported by doBuildStages.");
try {
// 当 Stage 是 RunTask 的时候执行。
if (upTo == DefaultGradleLauncher.Stage.RunTasks && this.instantExecution.canExecuteInstantaneously()) {
this.doInstantExecution();
} else {
// 当 Stage 不是 RunTask 的时候执行。 this.doClassicBuildStages(upTo);
}
} catch (Throwable var3) {
this.finishBuild(upTo.getDisplayName(), var3);
}
}
复制代码
继续调用 doClassicBuildStages 方法,源码以下所示:
private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
// 一、当 Stage 为 LoadSettings 时执行 prepareSettings 方法去配置并生成 Setting 实例。
this.prepareSettings();
if (upTo != DefaultGradleLauncher.Stage.LoadSettings) {
// 二、当 Stage 为 Configure 时执行 prepareProjects 方法去配置工程。
this.prepareProjects();
if (upTo != DefaultGradleLauncher.Stage.Configure) {
// 三、当 Stage 为 TaskGraph 时执行 prepareTaskExecution 方法去构建 TaskGraph。
this.prepareTaskExecution();
if (upTo != DefaultGradleLauncher.Stage.TaskGraph) {
// 四、当 Stage 为 RunTasks 时执行 saveTaskGraph 方法 与 runWork 方法保存 TaskGraph 并执行相应的 Tasks。 this.instantExecution.saveTaskGraph();
this.runWork();
}
}
}
}
复制代码
能够看到,doClassicBuildStages
方法是个很重要的方法,它对全部的 Stage 任务进行了分发,这里小结一下:
而后,咱们接着继续看看 prepareSettings 方法,其源码以下所示:
private void prepareSettings() {
if (this.stage == null) {
// 一、回调 BuildListener.buildStarted() 回调接口。
this.buildListener.buildStarted(this.gradle);
// 二、调用 settingPreparer 接口的实现类 DefaultSettingsPreparer 的 prepareSettings 方法。
this.settingsPreparer.prepareSettings(this.gradle);
this.stage = DefaultGradleLauncher.Stage.LoadSettings;
}
}
复制代码
在 prepareSettings
方法作了两件事:
咱们继续看到 DefaultSettingsPreparer 的 prepareSettings 方法,以下所示:
public void prepareSettings(GradleInternal gradle) {
// 一、执行 init.gradle,它会在每一个项目 build 以前被调用,用于作一些初始化的操做。
this.initScriptHandler.executeScripts(gradle);
SettingsLoader settingsLoader = gradle.getParent() != null ? this.settingsLoaderFactory.forNestedBuild() : this.settingsLoaderFactory.forTopLevelBuild();
// 二、调用 SettingLoader 接口的实现类 DefaultSettingsLoader 的 findAndLoadSettings 找到 Settings.gradle 文件的位置。
settingsLoader.findAndLoadSettings(gradle);
}
复制代码
在 prepareSettings
方法中作了两项处理:
DefaultSettingLoader 的 findAndLoadSettings 方法关联的实现代码很是多,限于篇幅,我这里直接点出 findAndLoadSettings 方法中的主要处理流程:
当执行完 LoadSetting 阶段以后,就会执行 Configure 阶段,而配置阶段所做的事情就是 把 gradle 脚本编译成 class 文件并执行。由前可知,此时会执行 prepareProjects 方法,以下所示:
private void prepareProjects() {
if (this.stage == DefaultGradleLauncher.Stage.LoadSettings) {
// 一、调用 ProjectsPreparer 接口的实现类 DefaultProjectsPreparer 的 prepareProjects 方法。
this.projectsPreparer.prepareProjects(this.gradle);
this.stage = DefaultGradleLauncher.Stage.Configure;
}
}
复制代码
这里会继续调用 ProjectsPreparer 接口的实现类 DefaultProjectsPreparer 的 prepareProjects 方法。其源码以下所示:
public void prepareProjects(GradleInternal gradle) {
...
// 一、若是在 gradle.properties 文件中指定了参数 configure-on-demand,则只会配置主项目以及执行 task 所须要的项目。
if (gradle.getStartParameter().isConfigureOnDemand()) {
this.projectConfigurer.configure(gradle.getRootProject());
} else {
// 二、若是没有指定在 gradle.properties 文件中指定参数 configure-on-demand,则会调用 ProjectConfigurer 接口的实现类 TaskPathProjectEvaluator 的 configureHierarchy 方法去配置全部项目。
this.projectConfigurer.configureHierarchy(gradle.getRootProject());
(new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
}
this.modelConfigurationListener.onConfigure(gradle);
}
复制代码
在注释1处,若是在 gradle.properties 文件中指定了参数 configure-on-demand,则只会配置主项目以及执行 task 所须要的项目。咱们这里只看默认没有指定的状况。不然,在注释2处,则会调用 ProjectConfigurer 接口的实现类 TaskPathProjectEvaluator 的 configureHierarchy 方法去配置全部项目。
咱们接着继续看到 configureHierarchy 方法,以下所示:
public void configureHierarchy(ProjectInternal project) {
this.configure(project);
Iterator var2 = project.getSubprojects().iterator();
while(var2.hasNext()) {
Project sub = (Project)var2.next();
this.configure((ProjectInternal)sub);
}
}
复制代码
能够看到在 configureHierarchy 方法中使用了 Iterator 遍历并配置了全部 Project。而 configure 方法最终会调用到 EvaluateProject 类的 run 方法,以下所示:
public void run(final BuildOperationContext context) {
this.project.getMutationState().withMutableState(new Runnable() {
public void run() {
try {
EvaluateProject.this.state.toBeforeEvaluate();
// 一、 回调 ProjectEvaluationListener 的 beforeEvaluate 接口。
LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyBeforeEvaluate(EvaluateProject.this.project, EvaluateProject.this.state));
if (!EvaluateProject.this.state.hasFailure()) {
EvaluateProject.this.state.toEvaluate();
try {
// 二、在 evaluate 方法中会设置默认的 init、wrapper task 和 默认插件,而后便会编译、执行 build.gradle 脚本
LifecycleProjectEvaluator.this.delegate.evaluate(EvaluateProject.this.project, EvaluateProject.this.state);
} catch (Exception var10) {
LifecycleProjectEvaluator.addConfigurationFailure(EvaluateProject.this.project, EvaluateProject.this.state, var10, context);
} finally {
EvaluateProject.this.state.toAfterEvaluate();
// 三、回调 ProjectEvaluationListener.afterEvaluate 接口。
LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyAfterEvaluate(EvaluateProject.this.project, EvaluateProject.this.state));
}
}
if (EvaluateProject.this.state.hasFailure()) {
EvaluateProject.this.state.rethrowFailure();
} else {
context.setResult(ConfigureProjectBuildOperationType.RESULT);
}
} finally {
EvaluateProject.this.state.configured();
}
}
});
}
复制代码
在 EvaluateProject 的 run 方法中有以下 三个重要的处理:
执行完 初始化阶段 与 配置阶段 以后,就会 调用到 DefaultGradleLauncher 的 prepareTaskExecution 方法去建立一个由 Tasks 组成的一个有向无环图。该方法以下所示:
private void prepareTaskExecution() {
if (this.stage == DefaultGradleLauncher.Stage.Configure) {
// 一、调用 TaskExecutionPreparer 接口的实现类 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法。
this.taskExecutionPreparer.prepareForTaskExecution(this.gradle);
this.stage = DefaultGradleLauncher.Stage.TaskGraph;
}
}
复制代码
这里继续调用了 TaskExecutionPreparer 接口的实现类 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法,以下所示:
public void prepareForTaskExecution(GradleInternal gradle) {
this.buildOperationExecutor.run(new BuildOperatingFiringTaskExecutionPreparer.CalculateTaskGraph(gradle));
}
复制代码
能够看到,这里使用 buildOperationExecutor 实例执行了 CalculateTaskGraph 这个构建操做,咱们看到它的 run 方法,以下所示:
public void run(BuildOperationContext buildOperationContext) {
// 一、填充任务图
final TaskExecutionGraphInternal taskGraph = this.populateTaskGraph();
buildOperationContext.setResult(new Result() {
getRequestedTaskPaths() {
return this.toTaskPaths(taskGraph.getRequestedTasks());
}
public List<String> getExcludedTaskPaths() {
return this.toTaskPaths(taskGraph.getFilteredTasks());
}
private List<String> toTaskPaths(Set<Task> tasks) {
return ImmutableSortedSet.copyOf(Collections2.transform(tasks, new Function<Task, String>() {
public String apply(Task task) {
return task.getPath();
}
})).asList();
}
});
}
复制代码
在注释1处,直接调用了 populateTaskGraph 填充了 Tasks 有向无环图。源码以下所示:
TaskExecutionGraphInternal populateTaskGraph() {
// 一、这里又调用了 TaskExecutionPreparer 接口的另外一个实现类 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法。
BuildOperatingFiringTaskExecutionPreparer.this.delegate.prepareForTaskExecution(this.gradle);
return this.gradle.getTaskGraph();
}
复制代码
能够看到,在注释1处,又调用了 TaskExecutionPreparer 接口的另外一个实现类 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法。该方法以下所示:
public void prepareForTaskExecution(GradleInternal gradle) {
// 1
this.buildConfigurationActionExecuter.select(gradle);
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
// 二、根据 Tasks 与 Tasks 间的依赖信息填充 taskGraph 实例。
taskGraph.populate();
this.includedBuildControllers.populateTaskGraphs();
if (gradle.getStartParameter().isConfigureOnDemand()) {
(new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
}
}
复制代码
在注释1处,调用了 buildConfigurationActionExecuter 接口的 select 方法,这里采用了 策略 + 接口隔离 设计模式,后续会依次调用 ExcludedTaskFilteringBuildConfigurationAction 的 configure 方法、 DefaultTasksBuildExecutionAction 的 configure 方法、TaskNameResolvingBuildConfigurationAction 的 configure 方法。
下面,咱们依次来分析下其中的处理。
public void configure(BuildExecutionContext context) {
// 一、获取被排除的 Tasks 名称,并依次把它们放入 filters 中。
GradleInternal gradle = context.getGradle();
Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames();
if (!excludedTaskNames.isEmpty()) {
Set<Spec<Task>> filters = new HashSet();
Iterator var5 = excludedTaskNames.iterator();
while(var5.hasNext()) {
String taskName = (String)var5.next();
filters.add(this.taskSelector.getFilter(taskName));
}
// 二、给 TaskGraph 实例添加要 filter 的 Tasks
gradle.getTaskGraph().useFilter(Specs.intersect(filters));
}
context.proceed();
}
复制代码
在注释1处,先获取了被排除的 Tasks 名称,并依次把它们放入 filters 中,接着在注释2处给 TaskGraph 实例添加了要 filter 的 Tasks。
能够看到,这里给 TaskGraph 设置了 filter 去处理须要排除的 task,以便在后面计算依赖的时候排除相应的 task。
public void configure(BuildExecutionContext context) {
StartParameter startParameter = context.getGradle().getStartParameter();
Iterator var3 = startParameter.getTaskRequests().iterator();
TaskExecutionRequest request;
// 一、若是指定了要执行的 Task,则什么也不作。
do {
if (!var3.hasNext()) {
ProjectInternal project = context.getGradle().getDefaultProject();
this.projectConfigurer.configure(project);
List<String> defaultTasks = project.getDefaultTasks();
// 二、若是没有指定 DefaultTasks,则输出 gradle help 信息。
if (defaultTasks.size() == 0) {
defaultTasks = Collections.singletonList("help");
LOGGER.info("No tasks specified. Using default task {}", GUtil.toString(defaultTasks));
} else {
LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks));
}
// 三、不然,添加默认的 Task。
startParameter.setTaskNames(defaultTasks);
context.proceed();
return;
}
request = (TaskExecutionRequest)var3.next();
} while(request.getArgs().isEmpty());
context.proceed();
}
复制代码
能够看到,DefaultTasksBuildExecutionAction 类的 configure 方法的处理分为以下三步:
public void configure(BuildExecutionContext context) {
GradleInternal gradle = context.getGradle();
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
List<TaskExecutionRequest> taskParameters = gradle.getStartParameter().getTaskRequests();
Iterator var5 = taskParameters.iterator();
while(var5.hasNext()) {
TaskExecutionRequest taskParameter = (TaskExecutionRequest)var5.next();
// 一、解析 Tasks。
List<TaskSelection> taskSelections = this.commandLineTaskParser.parseTasks(taskParameter);
Iterator var8 = taskSelections.iterator();
// 二、遍历并添加全部已选择的 Tasks 至 taskGraph 实例之中。
while(var8.hasNext()) {
TaskSelection taskSelection = (TaskSelection)var8.next();
LOGGER.info("Selected primary task '{}' from project {}", taskSelection.getTaskName(), taskSelection.getProjectPath());
taskGraph.addEntryTasks(taskSelection.getTasks());
}
}
context.proceed();
}
复制代码
这里主要作了 两个处理
:
解析 Tasks
:
分析命令行中的 Task 的参数前面是否指定了 Project,例如 ':project:assembleRelease',若是没有指定则选中 Project 下全部符合该 taskName 的 Task。
遍历并添加全部已选择的 Tasks 至 taskGraph 实例之中
:
在内部会处理 dependson finalizedby mustrunafter shouldrunafter 等 Tasks 间的依赖关系,并会把信息保存在 TaskInfo 之中。
最后,咱们再回到 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法,在注释2处,咱们就能够 调用 taskGraph 的 populate 方法去根据这些 Tasks 与 Tasks 之间的依赖信息去填充 taskGraph 实例了。
填充完 taskGraph 以后,咱们就能够开始来执行这些 Tasks 了,咱们看到 DefaultGradleLauncher 实例的 executeTasks 方法,以下所示:
public GradleInternal executeTasks() {
this.doBuildStages(DefaultGradleLauncher.Stage.RunTasks);
return this.gradle;
}
复制代码
在 doBuildStages 方法中又会调用 doClassicBuildStages 方法,源码以下所示:
private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
this.prepareSettings();
if (upTo != DefaultGradleLauncher.Stage.LoadSettings) {
this.prepareProjects();
if (upTo != DefaultGradleLauncher.Stage.Configure) {
this.prepareTaskExecution();
if (upTo != DefaultGradleLauncher.Stage.TaskGraph) {
this.instantExecution.saveTaskGraph();
// 1
this.runWork();
}
}
}
}
复制代码
在注释1处,继续调用了 runWork 方法,以下所示:
private void runWork() {
if (this.stage != DefaultGradleLauncher.Stage.TaskGraph) {
throw new IllegalStateException("Cannot execute tasks: current stage = " + this.stage);
} else {
List<Throwable> taskFailures = new ArrayList();
// 1
this.buildExecuter.execute(this.gradle, taskFailures);
if (!taskFailures.isEmpty()) {
throw new MultipleBuildFailures(taskFailures);
} else {
this.stage = DefaultGradleLauncher.Stage.RunTasks;
}
}
}
复制代码
这里又继续 调用了 buildExecuter 接口的实现类 DefaultBuildWorkExecutor 的 execute 方法,其实现以下所示:
public void execute(GradleInternal gradle, Collection<? super Throwable> failures) {
this.execute(gradle, 0, failures);
}
private void execute(final GradleInternal gradle, final int index, final Collection<? super Throwable> taskFailures) {
if (index < this.executionActions.size()) {
// 1
((BuildExecutionAction)this.executionActions.get(index)).execute(new BuildExecutionContext() {
public GradleInternal getGradle() {
return gradle;
}
public void proceed() {
// 二、执行完 executionActions 列表中的第一项后,便开始执行下一项。
DefaultBuildWorkExecutor.this.execute(gradle, index + 1, taskFailures);
}
}, taskFailures);
}
}
复制代码
能够看到,这里又调用了 BuildExecutionAction 接口的实现类 DryRunBuildExecutionAction 的 execute 方法,以下所示:
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
GradleInternal gradle = context.getGradle();
// 一、若是命令行里包含 --dry-run 参数,则会跳过该 Task 的执行,并输出 Task 的名称与执行的前后关系。
if (gradle.getStartParameter().isDryRun()) {
Iterator var4 = gradle.getTaskGraph().getAllTasks().iterator();
while(var4.hasNext()) {
Task task = (Task)var4.next();
this.textOutputFactory.create(DryRunBuildExecutionAction.class).append(((TaskInternal)task).getIdentityPath().getPath()).append(" ").style(Style.ProgressStatus).append("SKIPPED").println();
}
} else {
context.proceed();
}
}
复制代码
在注释1处,若是命令行里包含了 --dry-run 参数,则会跳过该 Task 的执行,并输出 Task 的名称与执行的前后关系。
执行完 DryRunBuildExecutionAction 后,咱们再回到 DefaultBuildWorkExecutor 类的 execute 方法,在注释2处,会执行 executionActions 列表中的下一项,即第二项:SelectedTaskExecutionAction,咱们看看它的 execute 方法,以下所示:
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
...
taskGraph.addTaskExecutionGraphListener(new SelectedTaskExecutionAction.BindAllReferencesOfProjectsToExecuteListener());
// 一、
taskGraph.execute(taskFailures);
}
复制代码
能够看到,这里直接调用了 TaskExecutionGraphInternal 接口的实现类 DefaultTaskExecutionGraph 的 execute 方法去执行 Tasks,其关键源码以下所示:
public void execute(Collection<? super Throwable> failures) {
ProjectExecutionServiceRegistry projectExecutionServices = new ProjectExecutionServiceRegistry();
try {
// 使用线程池执行 Task
this.executeWithServices(projectExecutionServices, failures);
} finally {
projectExecutionServices.close();
}
}
复制代码
这里又继续调用了 DefaultTaskExecutionGraph 的 executeWithServices 方法使用线程池并行执行 Task,其核心源码以下所示:
private void executeWithServices(ProjectExecutionServiceRegistry projectExecutionServices, Collection<? super Throwable> failures) {
...
this.ensurePopulated();
...
try {
// 1
this.planExecutor.process(this.executionPlan, failures, new DefaultTaskExecutionGraph.BuildOperationAwareExecutionAction(this.buildOperationExecutor.getCurrentOperation(), new DefaultTaskExecutionGraph.InvokeNodeExecutorsAction(this.nodeExecutors, projectExecutionServices)));
LOGGER.debug("Timing: Executing the DAG took " + clock.getElapsed());
} finally {
...
}
}
复制代码
最终,这里是 调用了 PlanExecutor 接口的实现类 DefaultPlanExecutor 的 process 方法,以下所示:
public void process(ExecutionPlan executionPlan, Collection<? super Throwable> failures, Action<Node> nodeExecutor) {
ManagedExecutor executor = this.executorFactory.create("Execution worker for '" + executionPlan.getDisplayName() + "'");
try {
WorkerLease parentWorkerLease = this.workerLeaseService.getCurrentWorkerLease();
// 一、开始使用线程池异步执行 tasks
this.startAdditionalWorkers(executionPlan, nodeExecutor, executor, parentWorkerLease);
(new DefaultPlanExecutor.ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, this.cancellationToken, this.coordinationService)).run();
this.awaitCompletion(executionPlan, failures);
} finally {
executor.stop();
}
}
复制代码
在注释1处,使用了线程池去异步执行 tasks,以下所示:
private void startAdditionalWorkers(ExecutionPlan executionPlan, Action<? super Node> nodeExecutor, Executor executor, WorkerLease parentWorkerLease) {
LOGGER.debug("Using {} parallel executor threads", this.executorCount);
for(int i = 1; i < this.executorCount; ++i) {
executor.execute(new DefaultPlanExecutor.ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, this.cancellationToken, this.coordinationService));
}
}
复制代码
须要了解的是,用于执行 Task 的线程默认是 8 个线程。这里使用线程池执行了 DefaultPlanExecutor 的 ExecutorWorker,在它的 run 方法中最终会调用到 DefaultBuildOperationExecutor 的 run 方法去执行 Task。但在 Task 执行前还须要作一些预处理。
在 DefaultBuildOperationExecutor 的 run 方法中只作了两件事,这里咱们只需大体了解下便可,以下所示:
CatchExceptionTaskExecuter#execute
:
增长 try catch,避免执行过程当中发生异常。
ExecuteAtMostOnceTaskExecuter#execute
:
判断 task 是否执行过。
SkipOnlyIfTaskExecuter#execute
:
判断 task 的 onlyif 条件是否知足执行。
SkipTaskWithNoActionsExecuter#execute
:
跳过没有 action 的 task,若是没有 action 说明 task 不须要执行。
ResolveTaskArtifactStateTaskExecuter#execute
:
设置 artifact 的状态。
SkipEmptySourceFilesTaskExecuter#execut
:
跳过设置了 source file 且 source file 为空的 task,若是 source file 为空则说明 task 没有须要处理的资源。
ValidatingTaskExecuter#execute
:
确认 task 是否能够执行。
ResolveTaskOutputCachingStateExecuter#execute
:
处理 task 输出缓存。
SkipUpToDateTaskExecuter#execute
:
跳过 update-to-date 的 task。
ExecuteActionsTaskExecuter#execute
:
用来真正执行 Task 的 executer。
能够看到,在真正执行 Task 前须要经历一些通用的 task 预处理,最后才会调用 ExecuteActionsTaskExecuter 的 execute 方法去真正执行 Task。
public TaskExecuterResult execute(final TaskInternal task, final TaskStateInternal state, final TaskExecutionContext context) {
final ExecuteActionsTaskExecuter.TaskExecution work = new ExecuteActionsTaskExecuter.TaskExecution(task, context, this.executionHistoryStore, this.fingerprinterRegistry, this.classLoaderHierarchyHasher);
// 使用 workExecutor 对象去真正执行 Task。
final CachingResult result = (CachingResult)this.workExecutor.execute(new AfterPreviousExecutionContext() {
public UnitOfWork getWork() {
return work;
}
public Optional<String> getRebuildReason() {
return context.getTaskExecutionMode().getRebuildReason();
}
public Optional<AfterPreviousExecutionState> getAfterPreviousExecutionState() {
return Optional.ofNullable(context.getAfterPreviousExecution());
}
});
...
}
复制代码
能够看到,这里使用了 workExecutor 对象去真正执行 Task,在执行时便会回调 ExecuteActionsTaskExecuter.TaskExecution 内部类的 execute 方法,其实现源码以下所示:
public WorkResult execute(@Nullable InputChangesInternal inputChanges) {
this.task.getState().setExecuting(true);
WorkResult var2;
try {
ExecuteActionsTaskExecuter.LOGGER.debug("Executing actions for {}.", this.task);
// 一、回调 TaskActionListener 的 beforeActions 接口。
ExecuteActionsTaskExecuter.this.actionListener.beforeActions(this.task);
// 二、内部会遍历执行全部的 Action。
ExecuteActionsTaskExecuter.this.executeActions(this.task, inputChanges);
var2 = this.task.getState().getDidWork() ? WorkResult.DID_WORK : WorkResult.DID_NO_WORK;
} finally {
this.task.getState().setExecuting(false);
// 三、回调 TaskActionListener.afterActions。
ExecuteActionsTaskExecuter.this.actionListener.afterActions(this.task);
}
return var2;
}
复制代码
在 ExecuteActionsTaskExecuter.TaskExecution 内部类的 execute 方法中作了三件事,以下所示:
当执行完 Task 的全部 Action 以后,便会最终在 DefaultBuildOperationExecutor 的 run 方法中回调 TaskExecutionListener.afterExecute 来标识 Task 最终执行完成。
在 Finished 阶段仅仅只干了一件比较重要的事情,就是 回调 buildListener 的 buildFinished 接口,以下所示:
private void finishBuild(String action, @Nullable Throwable stageFailure) {
if (this.stage != DefaultGradleLauncher.Stage.Finished) {
...
try {
this.buildListener.buildFinished(buildResult);
} catch (Throwable var7) {
failures.add(var7);
}
this.stage = DefaultGradleLauncher.Stage.Finished;
...
}
}
复制代码
从对 Gradle 执行 Task 的分析中能够看到 Task 的本质,其实就是一系列的 Actions。深刻了解了 Gradle 的构建流程以后,咱们再从新回归头来看看开始的那一张 Gradle 的构建流程图,以下所示:
此外,zhangyi54 作的 Gradle原理动画讲解 将枯燥的原理流程视觉化了,值得推荐。须要注意区分的是,动画讲解的 Gradle 版本比较老,可是主要的原理仍是一致的,能够放心观看。
注意:build.gradle 脚本的 buildscript 会在脚本的其它内容以前执行。
咱们都知道,DependencyHandler 是用来进行依赖声明的一个类,可是在 DependencyHandler 并无发现 implementation(), api(), compile() 这些方法,这是怎么回事呢?
其实这是 经过 MethodMissing 机制,间接地调用 DependencyHandler 的实现 DefaultDependencyHandler 的 add() 方法将依赖添加进去的。
它是 Groovy 语言的一个重要特性, 这个特性容许在运行时 catch 对于未定义方法的调用。
而 Gradle 对这个特性进行了封装,一个类要想使用这个特性,只要实现 MixIn 接口便可。代码以下所示:
public interface MethodMixIn {
MethodAccess getAdditionalMethods();
}
复制代码
例如以下两个依赖:
DependencyStringNotationConverter
:
将相似于 'androidx.appcompat:appcompat:1.1.0' 的常规依赖声明转换为依赖。
DependencyProjectNotationConverter
:
将相似于 'project(":mylib")' 的依赖声明转换为依赖。
此外,除了 project 依赖,其它的依赖最终都会转换为 SelfResolvingDependency, 而这个依赖能够实现自我解析。
implementation 与 api。可是,承担 moudle 或者 aar 依赖仅仅是 Configuration 表面的任务,依赖的实质就是获取被依赖项构建过程当中产生的 Artifacts。
而对于大部分的 Task 来讲,执行完以后都会有产物输出。而在各个 moudle 之间 Artifacts 的产生与消费则构成了一个完整的生产者-消费者模型。
每个 task 都会调用 VariantScopeImpl 中的 publishIntermediateArtifact 方法将本身的产物进行发布,最后会调用到 DefaultVariant 的 artifact 方法对产物进行发布。
一、Android Gradle Plugin V3.6.2 源码
二、Gradle V5.6.4 源码
三、Android Plugin DSL Reference
七、连载 | 深刻理解Gradle框架之一:Plugin, Extension, buildSrc
九、连载 | 深刻理解gradle框架之三:artifacts的发布
十、Android Gradle Plugin 源码解析(上)
十一、Android Gradle Plugin 源码解析(下)
1三、Gradle 庖丁解牛(构建生命周期核心委托对象建立源码浅析)
欢迎关注个人微信:
bcce5360
因为微信群已超过 200 人,麻烦你们想进微信群的朋友们,加我微信拉你进群。
2千人QQ群,Awesome-Android学习交流群,QQ群号:959936182, 欢迎你们加入~