首先,我要说的是,我没想到写这篇文章会遇到那么多的难点。其次在写这篇文章的时候,我还是处于一个半吊子的状态,但是我想应该还是会比现有的大部分blog要好的多。我几乎将Google到的索引到的前几页文章全部看了一遍,但是大部分都是相同的内容,就只有一篇我印象比较深,写的比较全面,但是我仍然还有很多疑问。
下面的文章我会提出我自己在学习这个知识点时想要问的问题,有些问题我可以自己解答,但是有些还是摸棱两可。
首先列出阅读这篇文章所需要的基础知识,如果你连这些都没有掌握的话,就不建议往下看了,会很痛苦,除非你只是想了解一下。
- Goorvy 基本语法
- Gradle 构建
- ASM
前两个知识点有一个快速掌握的方法,阅读这个 PDF 文件,写的还是非常不错的,我花了一个小时看完,我看的比较快,因为我看过《Gradle权威指南》这本书。
好了,从这里开始,我就当你已经掌握了上面的相关知识点。
Gradle 工作流程
Gradle 是一个框架,它定义一套自己的游戏规则。我们要玩转 Gradle,必须要遵守它设计的规则。
下面我们来讲讲 Gradle 的基本组件:
- Gradle 中,每一个待编译的工程都叫一个 Project。每一个 Project 在构建的时候都包含一系列的 Task。比如
一个 Android APK 的编译可能包含:Java 源码编译 Task、资源编译 Task、JNI 编译 Task、lint 检查 Task、打包生成 APK 的 Task、签名 Task 等。 - 一个 Project 到底包含多少个 Task,其实是由编译脚本指定的插件决定。插件是什么呢?插件就是用来定义 Task,并具体执行这些 Task 的东西。
Gradle 作为框架,它负责定义流程和规则,而具体的编译工作则是通过插件的方式来完成的。比如编译 Java 有 Java 插件,编译 Groovy 有 Groovy 插件,编译 Android APP 有 Android APP 插件,编译 Android Library 有 Android Library 插件。好了,到现在为止,你知道 Gradle 中每一个待编译的工程都是一个 Project,一个具体的编译过程是由一个一个的 Task 来定义和执行的。
在 Android Stuido 中,每个 moudle 都有自己的 build.gradle 文件。在构建的时候,每一个 build.gradle 文件都会转换成一个 Project 对象。
一个 Project 会包含若干 Tasks。另外,由于 Project 对应具体的工程,所以需要为 Project 加载所需要的插件,比如:为 Java 工程加载 Java 插件,为 Android 工程加载 Android 插件。
这里就为该工程加载了 3 个插件。一般的插件可以直接使用,但是有的插件可能还需要配置扩展。
如上图所示,这是属于 com.android.application
插件的一个 android 扩展。在这里我们就可以配置该扩展的一些属性。
了解了这些,我们继续。
Gradle 工作包含三个阶段:
- 首先是
Initiliazation
阶段:对我们前面的 multi-project build 而言,就是执行 settings.gradle。 - 然后是
Configration
阶段:Configration
阶段的目标是解析每个 project 中的 build.gradle。在这两个阶段之间,我们可以加一些定制化的Hook。这当然是通过 API 来添加的。 Configuration
阶段完了后,整个 build 的 project 以及内部的 Task 关系就确定了。前面说过,一个Project 包含很多 Task,每个 Task 之间有依赖关系。Configuration 会建立一个有向图来描述 Task 之间的依赖关系。所以,我们可以添加一个 HOOK,即当 Task 关系图建立好后,执行一些操作。- 最后一个阶段就是执行任务了。
Transform API 为什么可以修改 class 文件
我们知道,一个 project 的构建是由很多 task 组成的,而这些 task 是有依赖关系的。我们结合一下 App 的打包流程来看一下,各个 task 是发生在什么时候。
在 App 打包的时候,首先需要先将 java 文件编译为 class 文件(这里不关心一些其他的 AIDL 之类的),然后将 jar 与 class 文件达成 dex 文件。由于工程是 Gradle 构建的,Gradle 的构建是基于 Task 的,所以这些编译java文件,打包 class 文件都是在 task 中执行的。
在构建的过程中,这些 Task 都是由 TaskManager 管理的:
com.android.build.gradle.internal.TaskManager#createCompileTask
protected void createCompileTask(@NonNull VariantScope variantScope) {
TaskProvider<? extends JavaCompile> javacTask = createJavacTask(variantScope);
addJavacClassesStream(variantScope);
setJavaCompilerTask(javacTask, variantScope);
createPostCompilationTasks(variantScope);
}
这里是先执行了 javac 的编译任务,然后执行 post 编译任务。
com.android.build.gradle.internal.TaskManager#createPostCompilationTasks
public void createPostCompilationTasks(
@NonNull TaskFactory tasks,
@NonNull final VariantScope variantScope) {
...
// ----- External Transforms -----
// 添加自定义的 Transform
List<Transform> customTransforms = extension.getTransforms();
List<List<Object>> customTransformsDependencies = extension.getTransformsDependencies();
for (int i = 0, count = customTransforms.size() ; i < count ; i++) {
Transform transform = customTransforms.get(i);
AndroidTask<TransformTask> task = transformManager
.addTransform(tasks, variantScope, transform);
...
}
...
// ----- Minify next -----
// minifyEnabled 为 true 表示开启混淆
// 添加 Proguard Transform
if (isMinifyEnabled) {
boolean outputToJarFile = isMultiDexEnabled && isLegacyMultiDexMode;
createMinifyTransform(tasks, variantScope, outputToJarFile);
}
...
// non Library test are running as native multi-dex
if (isMultiDexEnabled