总听说AGP,它到底做了什么?

365体育网在线手机版 admin 2025-06-29 13:51:32

目录

前言一、基础准备二、AGP源码的打开方式三、代码分析第一步 寻找AppPlugin第二步 AppPlugin第三步 配置Project第四步 确认扩展第五步 创建Task第六步 配置完成后创建Task第七步 TaskManager第一次创建多个Task第八步 TaskManager第二次创建多个Task

总结

前言

故事的开始是这样的。

之前阅读《Android开发高手课》的时候,里面启动优化一栏有讲到 systrace + 函数插桩 是不错的卡顿排查方式。

主要方式就是通过 Transform + Asm,相信是大家的老熟人了。

使用其中的 Demo 进行学习的时候,发现将 AGP(Android Gradle Plugin,Android Gradle 打包插件) 升级到 4.0.0 以后,Demo 就不管用了。

分析了一下 Demo,发现代码中没有使用直接注册 Transform 的方式进行插桩,而是获取 transformClassesWithDexBuilderForxxx 对应的 Task,通过反射的方式将该 Task 中的 Transform 设置为当前实现的 Transform:

那为什么在 AGP 4.0.0 的时候,这种方式就不行了呢?

我们都知道,AS 在构建代码的过程中会将执行的 Task 都打印到 Build 窗口中,通过观察不同版本的 AGP 的构建过程,发现 4.0.0 的构建过程中没有打印 transformClassesWithDexBuilderForxxx。

啊,这…

一个好端端的 Task 说没了就没了,好吧,AGP 源码见!

这边文章先和大家简单分析一下 AGP 的作用,后续的文章再和大家分析 Transform 的源码。

一、基础准备

在分析源码之前,我想你应该对 Android 打包流程已经有基础的了解,至少了解了下图的打包过程:

否则你有可能不了解下文中的专业术语。

二、AGP源码的打开方式

看 AGP 代码的时候,我一直纠结要不要下载 AGP 的源码,后来听同事大佬建议,直接使用了项目依赖的代码进行分析。

主要的原因有两点:

AGP 的源码太大了,有30g,并且版本已经很旧了使用项目依赖的 AGP 代码很简单

只要在项目中加入

implementation "com.android.tools.build:gradle:4.1.1"

即可查看。

三、代码分析

顺便说一下,AGP 的版本是 4.1.1。

第一步 寻找AppPlugin

在 AS 中,如果创建了一个项目,默认在主模块下面添加:

apply plugin: 'com.android.application'

自定义过 Plugin 的小伙伴都知道,源码中一定有一个 com.android.application.properties 文件与之相对应,这便是我们 Plugin 的入口了。

全局搜 com.android.application,打开 com.android.application.properties,内容是:

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

按「Command」按钮点击源码,发现 AppPlugin 里面又声明了一个 Plugin,最终跳到了:

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

包名与之前的不一样,这才是我们的最终入口。

各位同学有没有这样的疑惑,我给加上 apply plugin: com.android.application,那这段代码什么时候调用呢?

不知道大家有没有注意到,每次改动 build.gradle 文件的时候,AS 都会让我们点击 「Sync Now」按钮,点击完了,就会触发 Gradle 中的配置过程,最终会运行 Plugin#apply 方法,大家可以自定义 Plugin 的时候验证一下。

第二步 AppPlugin

AppPlugin 的父类是 AbstractAppPlugin,AbstractAppPlugin 的父类是 BasePlugin,插件的开始就在 BasePlugin#apply 方法里面:

@Override

public final void apply(@NonNull Project project) {

CrashReporting.runAction(

() -> {

basePluginApply(project);

pluginSpecificApply(project);

});

}

这里我们只需要关注方法块里面的两个方法 basePluginApply 和 pluginSpecificApply。

进入重点方法 basePluginApply 方法,这个方法的前期做了很多的检查工作,包括路径、版本和 AGP 版本等等,之后又做了很多监听工作,看一下源码:

private void basePluginApply(@NonNull Project project) {

// ... 代码省略

// 依赖检查

DependencyResolutionChecks.registerDependencyCheck(project, projectOptions);

// ... 省略路径检查、模块检查等、构建参数监听器

// AGP版本检查

AgpVersionChecker.enforceTheSamePluginVersions(project);

// 构建流程Task执行的监听器

RecordingBuildListener buildListener = ProfilerInitializer.init(project, projectOptions);

ProfileAgent.INSTANCE.register(project.getName(), buildListener);

threadRecorder = ThreadRecorder.get();

//... 代码省略

// 重点

// 1. 配置项目

threadRecorder.record(

ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,

project.getPath(),

null,

this::configureProject);

// 2. 配置扩展

threadRecorder.record(

ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,

project.getPath(),

null,

this::configureExtension);

// 3. 创建Task

threadRecorder.record(

ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,

project.getPath(),

null,

this::createTasks);

}

其中的重点方法我已经标注出来了,分别是配置项目、配置扩展和创建Task。

第三步 配置Project

需要注意的是,此配置并不是对应 Gradle 生命周期的配置,而是针对当前 Project 做一些配置工作。

private void configureProject() {

// ... 执行大量的Service

// 依赖版本相关

Provider cachedStringBuildServiceProvider =

new ConstraintHandler.CachedStringBuildService.RegistrationAction(project)

.execute();

// maven缓存相关

Provider 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 =

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);

}

我对上述代码的理解是创建Task前的准备工作,并且,上面代码中描述的 xxxAction 也很容易让人迷惑,也并不是对应 Task 中的 Action。

第四步 确认扩展

确认扩展对应的方法就是 configureExtension。

通常在 app 模块下的 build.gradle 文件中,常常会有诸如此类的配置:

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 的目的就是为了将此类的脚本信息转化成代码可以识别的信息:

private void configureExtension() {

// Gradle DSL的帮助类

DslServices dslServices = globalScope.getDslServices();

final NamedDomainObjectContainer 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);

// ...

}

简单看一下代码即可,发现大部分的代码都跟 variant 和扩展相关。

再关注一下生成的扩展,BasePlugin#createExtension 是个抽象方法,最终交给了 AppPlugin#createExtension 方法:

protected AppExtension createExtension(

@NonNull DslServices dslServices,

@NonNull GlobalScope globalScope,

@NonNull

DslContainerProvider

dslContainers,

@NonNull NamedDomainObjectContainer buildOutputs,

@NonNull ExtraModelInfo extraModelInfo) {

return project.getExtensions()

.create(

"android",

getExtensionClass(),

dslServices,

globalScope,

buildOutputs,

dslContainers.getSourceSetManager(),

extraModelInfo,

new ApplicationExtensionImpl(dslServices, dslContainers));

}

乍看似乎还是不太熟悉,但是如果开发过插件,你一定知道 AppExtension,它可以获取到上面提及的 build.gradle 下的 android {} 中的任何信息。

第五步 创建Task

这应该是最重要的一步了,创建 Task 就在 BasePlugin#createTasks 方法:

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);

}));

}

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

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

TaskManager#createTasksBeforeEvaluate 里面是一大段注册 Task 的代码,感兴趣可以自己查看源码。

第六步 配置完成后创建Task

等 Project 进入配置生命周期的回调,进入方法 createAndroidTasks:

final void createAndroidTasks() {

if (extension.getCompileSdkVersion() == null) {

// ... compileSdkVersion 相关

}

// ...

// get current plugins and look for the default Java plugin.

if (project.getPlugins().hasPlugin(JavaPlugin.class)) {

throw new BadPluginException(

"The 'java' plugin has been applied, but it is not compatible with the Android plugins.");

}

// ...

// 设置一些配置

ProcessProfileWriter.getProject(project.getPath())

.setCompileSdk(extension.getCompileSdkVersion())

.setBuildToolsVersion(extension.getBuildToolsRevision().toString())

.setSplits(AnalyticsUtil.toProto(extension.getSplits()));

String kotlinPluginVersion = getKotlinPluginVersion();

if (kotlinPluginVersion != null) {

ProcessProfileWriter.getProject(project.getPath())

.setKotlinPluginVersion(kotlinPluginVersion);

}

AnalyticsUtil.recordFirebasePerformancePluginVersion(project);

// 注释一 创建Variant

variantManager.createVariants();

List> variants =

variantManager.getMainComponents();

TaskManager taskManager =

createTaskManager(

variants,

variantManager.getTestComponents(),

!variantInputModel.getProductFlavors().isEmpty(),

globalScope,

extension,

threadRecorder);

// 注释二 创建Task

taskManager.createTasks();

// ...

// 注释三 创建 Task configure compose related tasks.

taskManager.createPostApiTasks();

// now publish all variant artifacts for non test variants since

// tests don't publish anything.

for (ComponentInfo component : variants) {

component.getProperties().publishBuildArtifacts();

}

// ...

variantManager.setHasCreatedTasks(true);

// notify our properties that configuration is over for us.

GradleProperty.Companion.endOfEvaluation();

}

首先,从注释一中可以看出,所有的 Variant 在这一步已经创建完成了。

接着,从注释二和注释三我们可以看出,createAndroidTasks 先后两次使用 taskManager 创建 Task。

第七步 TaskManager第一次创建多个Task

第一次创建 Task 使用的 TaskManager#createTasks 方法,点进这个方法:

public void createTasks() {

// lint相关的Task

taskFactory.register(new PrepareLintJarForPublish.CreationAction(globalScope));

// create a lifecycle task to build the lintChecks dependencies

taskFactory.register(

COMPILE_LINT_CHECKS_TASK,

task -> task.dependsOn(globalScope.getLocalCustomLintChecks()));

// Create top level test tasks.

createTopLevelTestTasks();

// 重点,遍历VariantCreate tasks for all variants (main and tests)

for (ComponentInfo variant : variants) {

createTasksForVariant(variant, variants);

}

// Test相关的Task

for (ComponentInfo<

TestComponentImpl,

TestComponentPropertiesImpl>

testComponent : testComponents) {

createTasksForTest(testComponent);

}

// 信息记录相关的Task

createReportTasks();

}

里面依然注册了很多 Task,Lint、测试和信息记录相关的 Task等。

其中最重要的还是获取在上面创建好的的 Variant,遍历执行 createTasksForVariant 方法,我们看看它为每一个 Variant 注册了哪些方法:

private void createTasksForVariant(

@NonNull ComponentInfo variant,

@NonNull List> variants) {

// ... 省略

createAssembleTask(variantProperties);

if (variantType.isBaseModule()) {

createBundleTask(variantProperties);

}

doCreateTasksForVariant(variant, variants);

}

大家对 createAssembleTask 这个方法肯定很熟悉,因为我们每次打包都是使用的 assembleDebug 或者 assembleRelease 这样的命令,这个方法就是创建 Assemble 对应的 Task。

doCreateTasksForVariant 方法就是创建跟 Variant 相关 Task 的方法,不过在 TaskManager 中,它是一个抽象方法,交给了 ApplicationTaskManager 去实现。

那么它里面到底创建了哪些 Task 呢?往后面翻,后面的图片会告诉你!

第八步 TaskManager第二次创建多个Task

第二次创建多个 Task 调用的是 TaskManager#createPostApiTasks 方法,主要跟 ViewBinding、DataBinding 和 Kotlin 编译相关的 Task,感兴趣的可以看一下。

这里就不一一和同学们分析了,直接看图:

简单的解释一下:

蓝色的:Gradle 配置阶段前 createTasksBeforeEvaluate 注册的 Task橙色:Gradle 配置阶段完成后创建的 Task红色:重要的 Task箭头:依赖关系(并不是所有)

当然,我并没有把所有的 Task 都列出来,依赖关系也只把我看见的列出来(代码太多,并没有都阅读)。

如果我们将上面的图片和之前官方的打包流程图结合起来,发现很多都是可以对应起来的:

前面有 AIDL、Source Code、Resource资源文件这类的处理 Task中期有 Class 编译相关、代码混淆相关的 Task后期又有创建合并 Dex以及打包 Apk 相关的 Task

而且,Task 之间都有依赖关系(图中并没有展现),比如我通过命令:

./gradlew assembleDebug

这个命令会调用 assembleDebug 对应的 Task,在此之前,它会执行完前面依赖的 Task,比如资源处理、编译相关、打包生成我们想要的APK等等。

到这儿,这个源码就分析的差不多了,回到第二步,BasePlugin 在 apply 方法里面,还执行了 pluginSpecificApply 方法,不过这个方法是一个空方法。

总结

这片文章的目的是希望大家对 AGP 有一个轮廓,AGP 主要做了什么?

可以发现,AGP 中注册的大部分 Task 都是为了打包服务的,每个小的 Task 都是打包这个流水线的螺丝钉。

下篇文章再和大家分析一下 Transform 的流程,下期见!

如果觉得本文不错,「点赞」是最好的肯定!

参考文章:

《🍵补齐Android技能树——从AGP构建过程到APK打包过程》 《【Android 修炼手册】Gradle 篇 – Gradle 源码分析》