
前言
故事的開始是這樣的。
之前閱讀《Android開發(fā)高手課》的時候,里面啟動優(yōu)化一欄有講到 systrace + 函數(shù)插樁 是不錯的卡頓排查方式。
主要方式就是通過 Transform + Asm,相信是大家的老熟人了。
使用其中的 Demo 進行學(xué)習的時候,發(fā)現(xiàn)將 AGP(Android Gradle Plugin,Android Gradle 打包插件) 升級到 4.0.0 以后,Demo 就不管用了。
分析了一下 Demo,發(fā)現(xiàn)代碼中沒有使用直接注冊 Transform 的方式進行插樁,而是獲取 transformClassesWithDexBuilderForxxx 對應(yīng)的 Task,通過反射的方式將該 Task 中的 Transform 設(shè)置為當前實現(xiàn)的 Transform:

那為什么在 AGP 4.0.0 的時候,這種方式就不行了呢?
我們都知道,AS 在構(gòu)建代碼的過程中會將執(zhí)行的 Task 都打印到 Build 窗口中,通過觀察不同版本的 AGP 的構(gòu)建過程,發(fā)現(xiàn) 4.0.0 的構(gòu)建過程中沒有打印 transformClassesWithDexBuilderForxxx。
啊,這...

一個好端端的 Task 說沒了就沒了,好吧,AGP 源碼見!
這邊文章先和大家簡單分析一下 AGP 的作用,后續(xù)的文章再和大家分析 Transform 的源碼。
一、基礎(chǔ)準備
在分析源碼之前,我想你應(yīng)該對 Android 打包流程已經(jīng)有基礎(chǔ)的了解,至少了解了下圖的打包過程:

否則你有可能不了解下文中的專業(yè)術(shù)語。
二、AGP源碼的打開方式
看 AGP 代碼的時候,我一直糾結(jié)要不要下載 AGP 的源碼,后來聽同事大佬建議,直接使用了項目依賴的代碼進行分析。
主要的原因有兩點:
- AGP 的源碼太大了,有30g,并且版本已經(jīng)很舊了
- 使用項目依賴的 AGP 代碼很簡單
只要在項目中加入
implementation "com.android.tools.build:gradle:4.1.1"
即可查看。
三、代碼分析
順便說一下,AGP 的版本是 4.1.1。
第一步 尋找AppPlugin
在 AS 中,如果創(chuàng)建了一個項目,默認在主模塊下面添加:
apply plugin: 'com.android.application'
自定義過 Plugin 的小伙伴都知道,源碼中一定有一個 com.android.application.properties 文件與之相對應(yīng),這便是我們 Plugin 的入口了。
全局搜 com.android.application,打開 com.android.application.properties,內(nèi)容是:
implementation-class=com.android.build.gradle.AppPlugin
按「Command」按鈕點擊源碼,發(fā)現(xiàn) AppPlugin 里面又聲明了一個 Plugin,最終跳到了:
implementation-class=com.android.build.gradle.internal.plugins.AppPlugin
包名與之前的不一樣,這才是我們的最終入口。
各位同學(xué)有沒有這樣的疑惑,我給加上 apply plugin: com.android.application,那這段代碼什么時候調(diào)用呢?
不知道大家有沒有注意到,每次改動 build.gradle 文件的時候,AS 都會讓我們點擊 「Sync Now」按鈕,點擊完了,就會觸發(fā) 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);
});
}
這里我們只需要關(guān)注方法塊里面的兩個方法 basePluginApply 和 pluginSpecificApply。
進入重點方法 basePluginApply 方法,這個方法的前期做了很多的檢查工作,包括路徑、版本和 AGP 版本等等,之后又做了很多監(jiān)聽工作,看一下源碼:
private void basePluginApply(@NonNull Project project) {
// ... 代碼省略
// 依賴檢查
DependencyResolutionChecks.registerDependencyCheck(project, projectOptions);
// ... 省略路徑檢查、模塊檢查等、構(gòu)建參數(shù)監(jiān)聽器
// AGP版本檢查
AgpVersionChecker.enforceTheSamePluginVersions(project);
// 構(gòu)建流程Task執(zhí)行的監(jiān)聽器
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. 創(chuàng)建Task
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
project.getPath(),
null,
this::createTasks);
}
其中的重點方法我已經(jīng)標注出來了,分別是配置項目、配置擴展和創(chuàng)建Task。
第三步 配置Project
需要注意的是,此配置并不是對應(yīng) Gradle 生命周期的配置,而是針對當前 Project 做一些配置工作。
private void configureProject() {
// ... 執(zhí)行大量的Service
// 依賴版本相關(guān)
Provider<ConstraintHandler.CachedStringBuildService> cachedStringBuildServiceProvider =
new ConstraintHandler.CachedStringBuildService.RegistrationAction(project)
.execute();
// maven緩存相關(guān)
Provider<MavenCoordinatesCacheBuildService> mavenCoordinatesCacheBuildService =
new MavenCoordinatesCacheBuildService.RegistrationAction(
project, cachedStringBuildServiceProvider)
.execute();
// 依賴庫相關(guān)
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相關(guān)
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);
// 消息打印服務(wù)注冊
MessageReceiverImpl messageReceiver =
new MessageReceiverImpl(
SyncOptions.getErrorFormatMode(projectOptions),
projectServices.getLogger());
// ... 省略
createLintClasspathConfiguration(project);
}
我對上述代碼的理解是創(chuàng)建Task前的準備工作,并且,上面代碼中描述的 xxxAction 也很容易讓人迷惑,也并不是對應(yīng) Task 中的 Action。
第四步 確認擴展
確認擴展對應(yīng)的方法就是 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 的目的就是為了將此類的腳本信息轉(zhuǎn)化成代碼可以識別的信息:
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()));
// 創(chuàng)建擴展
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);
// ...
}
簡單看一下代碼即可,發(fā)現(xiàn)大部分的代碼都跟 variant 和擴展相關(guān)。
再關(guān)注一下生成的擴展,BasePlugin#createExtension 是個抽象方法,最終交給了 AppPlugin#createExtension 方法:
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));
}
乍看似乎還是不太熟悉,但是如果開發(fā)過插件,你一定知道 AppExtension,它可以獲取到上面提及的 build.gradle 下的 android {} 中的任何信息。
第五步 創(chuàng)建Task
這應(yīng)該是最重要的一步了,創(chuàng)建 Task 就在 BasePlugin#createTasks 方法:
private void createTasks() {
// 注冊跟Variant不相關(guān)的任務(wù)
threadRecorder.record(
ExecutionType.TASK_MANAGER_CREATE_TASKS,
project.getPath(),
null,
() ->
TaskManager.createTasksBeforeEvaluate(
globalScope,
variantFactory.getVariantType(),
extension.getSourceSets()));
// 等到Gradle配置階段完成后,注冊跟Variant相關(guān)的任務(wù)
project.afterEvaluate(
CrashReporting.afterEvaluate(
p -> {
variantInputModel.getSourceSetManager().runBuildableArtifactsActions();
threadRecorder.record(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
project.getPath(),
null,
this::createAndroidTasks);
}));
}
這個方法里面主要有兩個方法:
-
TaskManager#createTasksBeforeEvaluate: 靜態(tài)方法表示在 Project 配置前,會創(chuàng)建一批 Task。 -
createAndroidTasks:注冊了一個配置生命周期完成后的回調(diào),等到 Project 配置完成后,Variant 已經(jīng)確定完畢,又會創(chuàng)建一批 Task。
TaskManager#createTasksBeforeEvaluate 里面是一大段注冊 Task 的代碼,感興趣可以自己查看源碼。
第六步 配置完成后創(chuàng)建Task
等 Project 進入配置生命周期的回調(diào),進入方法 createAndroidTasks:
final void createAndroidTasks() {
if (extension.getCompileSdkVersion() == null) {
// ... compileSdkVersion 相關(guān)
}
// ...
// 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.");
}
// ...
// 設(shè)置一些配置
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);
// 注釋一 創(chuàng)建Variant
variantManager.createVariants();
List<ComponentInfo<VariantT, VariantPropertiesT>> variants =
variantManager.getMainComponents();
TaskManager<VariantT, VariantPropertiesT> taskManager =
createTaskManager(
variants,
variantManager.getTestComponents(),
!variantInputModel.getProductFlavors().isEmpty(),
globalScope,
extension,
threadRecorder);
// 注釋二 創(chuàng)建Task
taskManager.createTasks();
// ...
// 注釋三 創(chuàng)建 Task configure compose related tasks.
taskManager.createPostApiTasks();
// now publish all variant artifacts for non test variants since
// tests don't publish anything.
for (ComponentInfo<VariantT, VariantPropertiesT> component : variants) {
component.getProperties().publishBuildArtifacts();
}
// ...
variantManager.setHasCreatedTasks(true);
// notify our properties that configuration is over for us.
GradleProperty.Companion.endOfEvaluation();
}
首先,從注釋一中可以看出,所有的 Variant 在這一步已經(jīng)創(chuàng)建完成了。
接著,從注釋二和注釋三我們可以看出,createAndroidTasks 先后兩次使用 taskManager 創(chuàng)建 Task。
第七步 TaskManager第一次創(chuàng)建多個Task
第一次創(chuàng)建 Task 使用的 TaskManager#createTasks 方法,點進這個方法:
public void createTasks() {
// lint相關(guān)的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<VariantT, VariantPropertiesT> variant : variants) {
createTasksForVariant(variant, variants);
}
// Test相關(guān)的Task
for (ComponentInfo<
TestComponentImpl<? extends TestComponentPropertiesImpl>,
TestComponentPropertiesImpl>
testComponent : testComponents) {
createTasksForTest(testComponent);
}
// 信息記錄相關(guān)的Task
createReportTasks();
}
里面依然注冊了很多 Task,Lint、測試和信息記錄相關(guān)的 Task等。
其中最重要的還是獲取在上面創(chuàng)建好的的 Variant,遍歷執(zhí)行 createTasksForVariant 方法,我們看看它為每一個 Variant 注冊了哪些方法:
private void createTasksForVariant(
@NonNull ComponentInfo<VariantT, VariantPropertiesT> variant,
@NonNull List<ComponentInfo<VariantT, VariantPropertiesT>> variants) {
// ... 省略
createAssembleTask(variantProperties);
if (variantType.isBaseModule()) {
createBundleTask(variantProperties);
}
doCreateTasksForVariant(variant, variants);
}
大家對 createAssembleTask 這個方法肯定很熟悉,因為我們每次打包都是使用的 assembleDebug 或者 assembleRelease 這樣的命令,這個方法就是創(chuàng)建 Assemble 對應(yīng)的 Task。
doCreateTasksForVariant 方法就是創(chuàng)建跟 Variant 相關(guān) Task 的方法,不過在 TaskManager 中,它是一個抽象方法,交給了 ApplicationTaskManager 去實現(xiàn)。
那么它里面到底創(chuàng)建了哪些 Task 呢?往后面翻,后面的圖片會告訴你!
第八步 TaskManager第二次創(chuàng)建多個Task
第二次創(chuàng)建多個 Task 調(diào)用的是 TaskManager#createPostApiTasks 方法,主要跟 ViewBinding、DataBinding 和 Kotlin 編譯相關(guān)的 Task,感興趣的可以看一下。
這里就不一一和同學(xué)們分析了,直接看圖:

簡單的解釋一下:
- 藍色的:Gradle 配置階段前
createTasksBeforeEvaluate注冊的 Task - 橙色:Gradle 配置階段完成后創(chuàng)建的 Task
- 紅色:重要的 Task
- 箭頭:依賴關(guān)系(并不是所有)
當然,我并沒有把所有的 Task 都列出來,依賴關(guān)系也只把我看見的列出來(代碼太多,并沒有都閱讀)。
如果我們將上面的圖片和之前官方的打包流程圖結(jié)合起來,發(fā)現(xiàn)很多都是可以對應(yīng)起來的:
- 前面有 AIDL、Source Code、Resource資源文件這類的處理 Task
- 中期有 Class 編譯相關(guān)、代碼混淆相關(guān)的 Task
- 后期又有創(chuàng)建合并 Dex以及打包 Apk 相關(guān)的 Task
而且,Task 之間都有依賴關(guān)系(圖中并沒有展現(xiàn)),比如我通過命令:
./gradlew assembleDebug
這個命令會調(diào)用 assembleDebug 對應(yīng)的 Task,在此之前,它會執(zhí)行完前面依賴的 Task,比如資源處理、編譯相關(guān)、打包生成我們想要的APK等等。
到這兒,這個源碼就分析的差不多了,回到第二步,BasePlugin 在 apply 方法里面,還執(zhí)行了 pluginSpecificApply 方法,不過這個方法是一個空方法。
總結(jié)
這片文章的目的是希望大家對 AGP 有一個輪廓,AGP 主要做了什么?
可以發(fā)現(xiàn),AGP 中注冊的大部分 Task 都是為了打包服務(wù)的,每個小的 Task 都是打包這個流水線的螺絲釘。
下篇文章再和大家分析一下 Transform 的流程,下期見!
如果覺得本文不錯,「點贊」是最好的肯定!
參考文章:
《??補齊Android技能樹——從AGP構(gòu)建過程到APK打包過程》
《【Android 修煉手冊】Gradle 篇 -- Gradle 源碼分析》