Android Gradle Plugin 简称AGP 是Android编译链中的核心部分,它在Gradle插件的位置如下

本文主要介绍在打出一个APK时 AGP构建的流程以及打包核心流程

AGP的构建流程

由于AGP版本更新变化较大,比如AGP8.0 Transform API将被移除,具体版本变化可以参考Android Gradle 插件版本说明

本文基于

implementation ‘com.android.tools.build:gradle:4.2.1’

App Plugin

我们在项目中会自动添加一个核心plugin

apply plugin: ‘com.android.application’

这个是构建的关键,之前在自定义插件文章中介绍 plugin对应一个具体实现类, 对应的插件 properties 为 ‘com.android.internal.application’,内部标明的插件实现类如下所示:

implementation-class=com.android.build.gradle.internal.plugins.AppPlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/** Gradle plugin class for 'application' projects, applied on the base application module */
public class AppPlugin extends AbstractAppPlugin {
...

// 应用指定的 plugin,这里是一个空实现
@Override
protected void pluginSpecificApply(@NonNull Project project) {
}

...

// 获取一个扩展类:应用 application plugin 都会提供一个与之对应的 android extension
@Override
@NonNull
protected Class<? extends AppExtension> getExtensionClass() {
return BaseAppModuleExtension.class;
}

...
}

AppPlugin 的父类是 AbstractAppPlugin,AbstractAppPlugin 的父类是 BasePlugin,插件的开始就在 BasePlugin#apply 方法里面代码如下,在打包时会执行到插件的Apply方法

1
2
3
4
5
6
7
8
@Override
public final void apply(@NonNull Project project) {
CrashReporting.runAction(
() -> {
basePluginApply(project);
pluginSpecificApply(project);
});
}

重点进入 pluginSpecificApply中,这个方法主要做了一些重要的前置工作,包括路径、AGP版本等,代码及注释如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private void basePluginApply(@NonNull Project project) {

...

// 1、DependencyResolutionChecks 会检查并确保在配置阶段不去解析依赖。
DependencyResolutionChecks.registerDependencyCheck(project, projectOptions);

// 2、应用一个 AndroidBasePlugin,目的是为了让其他插件作者区分当前应用的是一个 Android 插件。
project.getPluginManager().apply(AndroidBasePlugin.class);

// 3、检查 project 路径是否有错误,发生错误则抛出 StopExecutionException 异常。
checkPathForErrors();

// 4、检查子 moudle 的结构:目前版本会检查 2 个模块有没有相同的标识(组+名称),如果有则抛出 StopExecutionException 异常。(组件化在不同的 moudle 中需要给资源加 prefix 前缀)
checkModulesForErrors();

// 5、插件初始化,必须立即执行。此外,需要注意,Gradle Deamon 永远不会同时执行两个构建流程。
PluginInitializer.initialize(project);

// 6、初始化用于记录构建过程中配置信息的工厂实例 ProcessProfileWriterFactory
RecordingBuildListener buildListener = ProfilerInitializer.init(project, projectOptions);

// 7、给 project 设置 android plugin version、插件类型、插件生成器、project 选项
ProcessProfileWriter.getProject(project.getPath())
.setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION)
.setAndroidPlugin(getAnalyticsPluginType())
.setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST)
.setOptions(AnalyticsUtil.toProto(projectOptions));

// 配置工程
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
project.getPath(),
null,
this::configureProject);

// 配置 Extension
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
project.getPath(),
null,
this::configureExtension);

// 创建 Tasks
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
project.getPath(),
null,
this::createTasks);
}

主要分为2大类

  1. 插件检查操作
  2. 插件初始化及配置操作

核心就在上面3个方法中

  • configureProject 配置项目
  • configureExtension 配置扩展
  • createTasks 创建Task

下面将一一介绍

配置项目

configureProject

plugin的准备工程完成之后,就会执行BasePlugin#configureProject,不过需要注意的是,此配置并不是对应Gradle生命周期配置,而是针对当前Project做一些配置工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
private void configureProject() {
// ... 执行大量的Service
// 依赖版本相关
Provider<ConstraintHandler.CachedStringBuildService> cachedStringBuildServiceProvider =
new ConstraintHandler.CachedStringBuildService.RegistrationAction(project)
.execute();
// maven缓存相关
Provider<MavenCoordinatesCacheBuildService> mavenCoordinatesCacheBuildService =
new MavenCoordinatesCacheBuildService.RegistrationAction(
project, cachedStringBuildServiceProvider)
.execute();
// 依赖库相关
new LibraryDependencyCacheBuildService.RegistrationAction(project).execute();
// aapt准备工作
new Aapt2WorkersBuildService.RegistrationAction(project, projectOptions).execute();
new Aapt2DaemonBuildService.RegistrationAction(project).execute();
new SyncIssueReporterImpl.GlobalSyncIssueService.RegistrationAction(
project, SyncOptions.getModelQueryMode(projectOptions))
.execute();
// SDK相关
Provider<SdkComponentsBuildService> sdkComponentsBuildService =
new SdkComponentsBuildService.RegistrationAction(
project,
projectOptions,
project.getProviders()
.provider(() -> extension.getCompileSdkVersion()),
project.getProviders()
.provider(() -> extension.getBuildToolsRevision()),
project.getProviders().provider(() -> extension.getNdkVersion()),
project.getProviders().provider(() -> extension.getNdkPath()))
.execute();
// Enforce minimum versions of certain plugins
GradlePluginUtils.enforceMinimumVersionsOfPlugins(project, issueReporter);
// Apply the Java plugin
project.getPlugins().apply(JavaBasePlugin.class);
dslServices =
new DslServicesImpl(
projectServices,
new DslVariableFactory(syncIssueReporter),
sdkComponentsBuildService);
// 消息打印服务注册
MessageReceiverImpl messageReceiver =
new MessageReceiverImpl(
SyncOptions.getErrorFormatMode(projectOptions),
projectServices.getLogger());
// ... 省略
createLintClasspathConfiguration(project);
}

主要是一些准备工作

配置Extension

configureExtension

创建工程会有如下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
android {
compileSdk 32

defaultConfig {
applicationId "com.qidian.test"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}

configureExtension 的目的就是为了将此类的脚本信息转化成代码可以识别的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private void configureExtension() {
// Gradle DSL的帮助类
DslServices dslServices = globalScope.getDslServices();
final NamedDomainObjectContainer<BaseVariantOutput> buildOutputs =
project.container(BaseVariantOutput.class);
// ... 代码省略
// ... variant 的工厂类以及管理等等
variantFactory = createVariantFactory(projectServices, globalScope);
variantInputModel =
new LegacyVariantInputManager(
dslServices,
variantFactory.getVariantType(),
new SourceSetManager(
project,
isPackagePublished(),
dslServices,
new DelayedActionsExecutor()));
// 创建扩展
extension =
createExtension(
dslServices, globalScope, variantInputModel, buildOutputs, extraModelInfo);
globalScope.setExtension(extension);
variantManager =
new VariantManager<>(
globalScope,
project,
projectServices.getProjectOptions(),
extension,
variantFactory,
variantInputModel,
projectServices,
threadRecorder);
registerModels(
registry,
globalScope,
variantInputModel,
extension,
extraModelInfo);
// create default Objects, signingConfig first as its used by the BuildTypes.
variantFactory.createDefaultComponents(variantInputModel);
// ...
}

看下上面的创建扩展方法,
BasePlugin#createExtension 是个抽象方法,最终交给了 AppPlugin#createExtension 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

protected AppExtension createExtension(
@NonNull DslServices dslServices,
@NonNull GlobalScope globalScope,
@NonNull
DslContainerProvider<DefaultConfig, BuildType, ProductFlavor, SigningConfig>
dslContainers,
@NonNull NamedDomainObjectContainer<BaseVariantOutput> buildOutputs,
@NonNull ExtraModelInfo extraModelInfo) {
return project.getExtensions()
.create(
"android",
getExtensionClass(),
dslServices,
globalScope,
buildOutputs,
dslContainers.getSourceSetManager(),
extraModelInfo,
new ApplicationExtensionImpl(dslServices, dslContainers));
}

它可以获取到上面提及的 build.gradle 下的 android {} 中的任何信息。

创建Task

createTasks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void createTasks() {
// 注册跟Variant不相关的任务
threadRecorder.record(
ExecutionType.TASK_MANAGER_CREATE_TASKS,
project.getPath(),
null,
() ->
TaskManager.createTasksBeforeEvaluate(
globalScope,
variantFactory.getVariantType(),
extension.getSourceSets()));
// 等到Gradle配置阶段完成后,注册跟Variant相关的任务
project.afterEvaluate(
CrashReporting.afterEvaluate(
p -> {
variantInputModel.getSourceSetManager().runBuildableArtifactsActions();
threadRecorder.record(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
project.getPath(),
null,
this::createAndroidTasks);
}));
}

这个方法里面主要有两个方法:

  1. TaskManager#createTasksBeforeEvaluate: 静态方法表示在 Project 配置前,会创建一批 Task。
  2. createAndroidTasks:注册了一个配置生命周期完成后的回调,等到 Project 配置完成后,Variant 已经确定完毕,又会创建一批 Task。

这些task大部分都是为apk打包服务,网上有个比较详细的图

APK 打包流程

从上面我们知道 AGP提供了核心框架,通过不同的Task去组成一个复杂且解耦的打包流程,我们可以通过以下方式看到Task

./gradlew app:assembleDebug –console=plain
或者 AS 右侧 Gradle-Tasks-build-assemble

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
./gradlew app:assembleDebug --console=plain

...

> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:generateDebugBuildConfig
> Task :app:javaPreCompileDebug
> Task :app:mainApkListPersistenceDebug
> Task :app:generateDebugResValues
> Task :app:createDebugCompatibleScreenManifests
> Task :app:extractDeepLinksDebug
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:generateDebugResources
> Task :app:processDebugManifest
> Task :app:mergeDebugResources
> Task :app:processDebugResources
> Task :app:compileDebugJavaWithJavac
> Task :app:compileDebugSources
> Task :app:mergeDebugShaders
> Task :app:compileDebugShaders
> Task :app:generateDebugAssets
> Task :app:mergeDebugAssets
> Task :app:processDebugJavaRes NO-SOURCE
> Task :app:checkDebugDuplicateClasses
> Task :app:dexBuilderDebug
> Task :app:mergeLibDexDebug
> Task :app:mergeDebugJavaResource
> Task :app:mergeDebugJniLibFolders
> Task :app:validateSigningDebug
> Task :app:mergeProjectDexDebug
> Task :app:mergeDebugNativeLibs
> Task :app:stripDebugDebugSymbols
> Task :app:desugarDebugFileDependencies
> Task :app:mergeExtDexDebug
> Task :app:packageDebug
> Task :app:assembleDebug

这些Task一起配合完成最终的打包,网上有几个图还不错

官网

Android Studio Project Site 还有个更加细节的

在前一个章节最后,我们可以看到,最后是TaskManager来创建具体的Task,其中,打包流程的大部分tasks都在这个目录中

com.android.build.gradle.internal.tasks

通过下面的表格 看下task对应的作用

Task 实现类 作用
preBuild AppPreBuildTask 预先创建的 task,用于做一些 application Variant 的检查
preDebugBuild 与 preBuild 区别是这个 task 是用于在 Debug 的环境下的一些 Vrariant 检查
generateDebugBuildConfig GenerateBuildConfig 生成与构建目标相关的 BuildConfig 类
javaPreCompileDebug JavaPreCompileTask 用于在 Java 编译之前执行必要的 action
mainApkListPersistenceDebug MainApkListPersistence 用于持久化 APK 数据
generateDebugResValues GenerateResValues 生成 Res 资源类型值
createDebugCompatibleScreenManifests CompatibleScreensManifest 生成具有给定屏幕密度与尺寸列表的 (兼容屏幕)节点清单
extractDeepLinksDebug ExtractDeepLinksTask 用于抽取一系列 DeepLink(深度链接技术,主要应用场景是通过Web页面直接调用Android原生app,并且把需要的参数通过Uri的形式,直接传递给app,节省用户的注册成本
compileDebugAidl AidlCompile 编译 AIDL 文件
compileDebugRenderscript RenderscriptCompile 编译 Renderscript 文件
generateDebugResources 在 TaskManager.createAnchorTasks 方法中通过 taskFactory.register(taskName)的方式注册一个 task 空 task,锚点
processDebugManifest ProcessApplicationManifest 处理 manifest 文件
mergeDebugResources MergeResources 使用 AAPT2 合并资源文件
processDebugResources ProcessAndroidResources 用于处理资源并生成 R.class 文件
compileDebugJavaWithJavac JavaCompileCreationAction(这里是一个 Action,从 gradle 源码中可以看到从 TaskFactory 中注册一个 Action 可以得到与之对应的 Task,因此,Task 即 Action,Action 即 Task) 用于执行 Java 源码的编译
compileDebugSources 在 TaskManager.createAnchorTasks 方法中通过 taskFactory.register(taskName)的方式注册一个 task 空 task,锚点使用
mergeDebugAssets MergeSourceSetFolders.MergeAppAssetCreationAction 合并 assets 文件
processDebugJavaRes ProcessJavaResConfigAction 处理 Java Res 资源
checkDebugDuplicateClasses CheckDuplicateClassesTask 用于检测工程外部依赖,确保不包含重复类
dexBuilderDebug DexArchiveBuilderTask 用于将 .class 文件转换成 dex archives,即 DexArchive,Dex 存档,可以通过 addFile 添加一个 DEX 文件
mergeLibDexDebug DexMergingTask.DexMergingAction.MERGE_LIBRARY_PROJECT 仅仅合并库工程中的 DEX 文件
mergeDebugJavaResource MergeJavaResourceTask 合并来自多个 moudle 的 Java 资源
mergeDebugJniLibFolders MergeSourceSetFolders.MergeJniLibFoldersCreationAction 以合适的优先级合并 JniLibs 源文件夹
validateSigningDebug ValidateSigningTask 用于检查当前 Variant 的签名配置中是否存在密钥库文件,如果当前密钥库默认是 debug keystore,即使它不存在也会进行相应的创建
mergeProjectDexDebug DexMergingTask.DexMergingAction.MERGE_PROJECT 仅仅合并工程的 DEX 文件
mergeDebugNativeLibs MergeNativeLibsTask 从多个 moudle 中合并 native 库
stripDebugDebugSymbols StripDebugSymbolsTask 从 Native 库中移除 Debug 符号
desugarDebugFileDependencies DexFileDependenciesTask 处理 Dex 文件的依赖关系
mergeExtDexDebug DexMergingTask.DexMergingAction.MERGE_EXTERNAL_LIBS 仅仅用于合并外部库的 DEX 文件
packageDebug PackageApplication 打包 APK
assembleDebug Assemble 空 task,锚点使用

这些Task各司其职形成一个有向无环图,完成了apk打包。这些Task主要分为3种类型

  1. 增量Task

继承于 NewIncrementalTask 这个增量 Task 基类,需要重写 doTaskAction 抽象方法实现增量功能

  1. 非增量Task

继承于 NonIncrementalTask 这个非增量 Task 基类,重写 doTaskAction 抽象方法实现全量更新功能

  1. Transform Task

自定义Transfrom在调用appExtension.registerTransform(new CustomTransform()) 注册方法时将其保存到当前的 Extension 类中的 transforms 列表中,当 LibraryTaskManager/TaskManager 调用 createPostCompilationTasks(负责为给定 Variant 创建编译后的 task)方法时,会取出相应 Extension 中的 tranforms 列表进行遍历,并通过 TransformManager.addTransform 方法将每一个 Transform 转换为与之对应的 TransformTask 实例,而该方法内部具体是通过 new TransformTask.CreationAction(…) 的形式进行创建

在4.0以下还有一些transformClassesWithDexBuilderForxxx,打包流程的Task校之4.0也有不同,在 3.0.1中主要Task如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
:app:preBuild UP-TO-DATE    → 空task,锚点
:app:preDebugBuild → 空task,锚点
:app:compileDebugAidl NO-SOURCE → 处理AIDL
:app:checkDebugManifest → 检查Manifest是否存在
:app:compileDebugRenderscript NO-SOURCE → 处理renderscript
:app:generateDebugBuildConfig → 生成 BuildConfig.java
:app:mainApkListPersistenceDebug → 生成 app-list.gson
:app:generateDebugResValues → 生成resvalue,generated.xml
:app:generateDebugResources → 空task,锚点
:app:mergeDebugResources → 合并资源文件
:app:createDebugCompatibleScreenManifests → manifest文件中生成compatible-screens,指定屏幕适配
:app:processDebugManifest → 合并manifest.xml文件
:app:processDebugResources → aapt打包资源
:app:compileDebugKotlin → 编译Kotlin文件
:app:prepareLintJar UP-TO-DATE → 拷贝 lint jar包到指定位置
:app:generateDebugSources → 空task,锚点
:app:javaPreCompileDebug → 生成 annotationProcessors.json 文件
:app:compileDebugJavaWithJavac → 编译 java文件
:app:compileDebugNdk → 编译ndk
:app:compileDebugSources → 空task,锚点
:app:mergeDebugShaders → 合并 shader文件
:app:compileDebugShaders → 编译 shaders
:app:generateDebugAssets → 空task,锚点
:app:mergeDebugAssets → 合并 assests文件
:app:validateSigningDebug → 验证签名
:app:signingConfigWriterDebug → 编写SigningConfig信息
:app:checkDebugDuplicateClasses → 检查重复class
:app:transformClassesWithDexBuilderForDebug → class打包成dex
:app:transformDexArchiveWithExternalLibsDexMergerForDebug → 打包第三方库的dex
:app:transformDexArchiveWithDexMergerForDebug → 打包最终的dex
:app:mergeDebugJniLibFolders → 合并jni lib 文件
:app:transformNativeLibsWithMergeJniLibsForDebug → 合并jnilibs
:app:transformNativeLibsWithStripDebugSymbolForDebug → 去掉native lib里的debug符号
:app:processDebugJavaRes NO-SOURCE → 处理java res
:app:transformResourcesWithMergeJavaResForDebug → 合并java res
:app:packageDebug → 打包apk
:app:assembleDebug → 空task,锚点
:app:extractProguardFiles → 生成混淆文件

# 还会打一个release包,task和上述基本一致,此处省略~

参考

  1. Android Gradle 插件版本说明
  2. 总听说AGP,它到底做了什么?
  3. Gradle 插件架构实现原理剖析 — 下
  4. Android Gradle Plugin 主要流程分析
  5. Android Gradle Plugin 主要 Task 分析
  6. 从AGP构建过程到APK打包过程