1.基础准备
在分析源码之前,我想你应该对 Android 打包流程已经有基础的了解,至少了解了下图的打包过程:
否则你有可能不了解下文中的专业术语。
2.AGP源码的打开方式
看 AGP 代码的时候,我一直纠结要不要下载 AGP 的源码,后来听同事大佬建议,直接使用了项目依赖的代码进行分析。
主要的原因有两点:
1. AGP 的源码太大了,有30g,并且版本已经很旧了。
2. 使用项目依赖的 AGP 代码很简单。
只要在项目中加入
implementation "com.android.tools.build:gradle:4.1.1"
即可查看。
3.代码分析
顺便说一缓存清理下,AGP 的版本是 4.1.1。
第一步 寻找AppPlugin
在 AS 中,gradle安装与配置如果创建了一个项目,默认在主模块下面添加:
apply plugin: 'com.android.application'
自定义过jvm是什么 Plugin 的小伙伴都知道,源码中一定有一个 com.缓存文件夹名称android.application.properties 文件与之相对应,这便是我们 Plugin 的入口了。
全局搜 com.android.application,打开 com.angradle依赖冲突强制指定droid.application.properties,内容是:
implementation-class=com.android.build.gradle.AppPlugin
按「Command」按钮点击源码,发现 AppPlugin 里面又声明android/harmonyos了一个 Plugin,最终跳到了:
implementation-class=com.android.build.gradle.internal.plugins.AppPlugin
包名与之前的不一样,这才是我们的最终入口。
各位同学有没有测试工程师这样的疑惑,我给加上 apply plugin: com.android.application,那这段代码什么时候调用gradle和maven呢?
不知道大家有没有注意到,每android的drawable类次android是什么系统改动 build.gradle 文件的时候,AS 都会让我们点击 「Sync Now」按钮,点击完了,就会触发 Gradle 中的配置过程,最终会运行 Plugin#apply 方法,大家可以自定义 Pgradle项目lugandroid手机in 的时候验证一下。
第二步 AppPlugin
AppPlugin 的父类是 AbstractAppPlugin,AbstractAppPlugin 的父类是 BasePlugin,插件的开始就在 BasePlugin#apply 方法里面:
@Override
public final void apply(@NonNull Project project) {
CrashReporting.runAction(
() -> {
basePluginApply(project);
pluginSpecificApply(project);
});
}
这里我们只需要关注方法gradle依赖冲突强制指定块缓存视频变成本地视频里面的两个方法 basePlugi测试英文nApply 和 pluginSpecificApply。
进入重点方法 basgradle项目ePluginApply 方法,这个方法的前期做了android下载安装很多的检查工缓存视频合并app作,包括路径、版本和 AGP 版本等等,之后又做JVM了很多监听工作,看一下源码:
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<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);
}
我对上述代码的理解是创建Task前测试仪的准备工作,jvm是什么并且,上面代码中描述的 xxxAction 也很容易让人迷惑,也并不是对应 Task 中的 Action。
第四步 确认扩展
确认扩展对应的方法就是 confi缓存视频合并gureExtensi测试英文on。
通常在 app 模块下的 build.gradle 文件中,常常会缓存视频合并app有诸如此类的配置:
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<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);
// ...
}
简单看一下代码即可,发现大部分的android是什么系统代码都跟 variant 和扩展相关。
再关注一下生成的扩展,BasePlugin#createExtejvm优化nsion 是个抽象测试抑郁症的20道题方法,最终交给了 AppPlugin#createExt测试手机是否被监控ension 方法:
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));
}
乍看似乎还是不太熟悉,但是如果开发过插件,你一定知道 AppExtension,它可以获取到android是什么手机牌子上面提及jvm性能调优的 build.gradle 下的 android {} 中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);
}));
}
这个方法里面主要有两个方法:
1. Tagradle项目skManager#createTasksBeforeEvaluate:静态方法表示在 Project 配置前,会创建一批 Taskjvm优化。
2. creaandroidstudio安装教程teAndroidTasks:注册了一个配置生命周期完成后的回调,等到 Project 配置完成后,Varigradle是什么ant 已经确定Android完毕,又会创建一批 Task。
TaskManager#createTasksBeforeEvaluate 里面是一大段注册 Task 的代码,感兴趣可以自己查看源码。
第六步 配置完成后创建Task
等 Project 进入配置生命周期的回调,进入方法 createAndroidTa测试抑郁症sks:
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<ComponentInfo<VariantT, VariantPropertiesT>> variants =
variantManager.getMainComponents();
TaskManager<VariantT, VariantPropertiesT> 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<VariantT, VariantPropertiesT> component : variants) {
component.getProperties().publishBuildArtifacts();
}
// ...
variantManager.setHasCreatedTasks(true);
// notify our properties that configuration is over for us.
GradleProperty.Companion.endOfEvaluation();
}
首先,从注释一中可以看出,所有的 Varia缓存文件夹名称nt 在这一步已经测试抑郁症的20道题创建完成了。
接着,从注释二测试和注释三我们可以看出,createAn测试你适合学心理学吗droidTasks 先后两次gradle是什么使用 taskManager 创建 Task。
**第七步 TaskManager第缓存视频变成本地视频一次创建多个Taskgradle和maven
**
第一次创建 Task 使用的 TaskManager#createTa测试英文sks 方法,点进这个方法:
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<VariantT, VariantPropertiesT> variant : variants) {
createTasksForVariant(variant, variants);
}
// Test相关的Task
for (ComponentInfo<
TestComponentImpl<? extends TestComponentPropertiesImpl>,
TestComponentPropertiesImpl>
testComponent : testComponents) {
createTasksForTest(testComponent);
}
// 信息记录相关的Task
createReportTasks();
}
里面依然注册了很多 Task,Lint、测试和信息记录相关的 Task等。
其中最重要的还是获取在上面创建好的的 Variant,遍历执行 createTasksForVariant 方jvm面试题法,我们看看它为每一个 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);
}
大家对 createAssemblgradle怎么读eTask 这个方法肯定很熟悉,因为我们每次打包都是使用的 assembleDebug 或者 assemblejvm内存Release 这样的命令,这个方法就是创建 Assemble 对应的 Task。
doCreateTasksForVariant 方法就是创建跟 Varjvm优化iant 相关 Task 的方法,gradle依赖冲突强制指定不过在 TaskManager 中,它是一个抽象方法,交给了 Appjvm优化licationTaskManager 去实现。
那么android什么意思它里面到底创建了测试英文哪些jvm调优 Task 呢?jvm性能调优往后面翻,后面的图片会告诉你!
第缓存视频在手机哪里找八步 Tagradle怎么读skManag测试抑郁症的20道题er第二次创建多个Task
第二次创建多个 Task 调用的是 TaskManager#jvm内存createPostApiTasks 方法,主缓存视频合并app要跟 ViewBindin缓存g、DataBinding 和 Kotlin 编译相关的 Task,感兴趣的可以看一下。
这里就不一一和同学们分析了,直接看图:
Task过程
简缓存清理单的解释一下:
蓝色的:Gradle 配置阶段前 createTasksBeforeEvaluate注册的 Task。
橙色:Gradle 配置阶段完成后gradle是什么创建的 Task。
红色:重要的 Task。
箭头:依赖关系(并不是所有)。
当然,我并没有把所有的 Task 都列出来,依赖关系也只把我看见的列出来(代码太多,并没有都阅读)。
如果我们将上面的图片和之前官方的打包流程图结合起来,发现很多都是可以对应起来的:
1. 前面有 AIDL、Source Code、Resource资源文件这类的处理 Task。
2. 中期有 Class 编译相关、代码测试手机是否被监控混淆相关的 Task。
3. 后期又有创建合并 Dex以及打包 Apk 相关的 Task。
而且,TAndroidask 之间都有依赖关系(图中并没有展现),比如我通过命令:
./gradlew assembleDebug
这gradle怎么读个命令会调用 assembleDebug 对应的 Task,在此之前,它会执行完前面依赖的 Task,比如资源处理、编译相关、打包生成我们想要的APK等等。
到这儿,这个源码就分析的差不多了,回到第二步,BasePlugin 在 apply 方法里面,还执行了 pluginSpecificApply 方法,不过这个方法是一个空方法。
3.总结
这篇文章的目的是希望大家对 AGP 有一个轮廓,AGP 主要做了什么?
可以发现,AGP 中注jvm是什么册的大部分 Task 都是为了打包服务的,每个小的 Task 都是android手机打包这个流水线的螺丝钉。
如果觉得本文不缓存是什么意思错,「点赞」是最好的肯定!