乐趣区

关于android:Android安卓进阶技术分享之AGP工作原理

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 中,如果创立了一个我的项目,默认在主模块上面增加:

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<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 前的筹备工作,并且,下面代码中形容的 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<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);  
    // ...   
}  

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

再关注一下生成的扩大,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));  
}  

乍看仿佛还是不太熟悉,然而如果开发过插件,你肯定晓得 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);  
                    }));  
}  

这个办法外面次要有两个办法:

1. TaskManager#createTasksBeforeEvaluate:静态方法示意在 Project 配置前,会创立一批 Task。

2. 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<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();}  

首先,从正文一中能够看出,所有的 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<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 办法,咱们看看它为每一个 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 这样的命令,这个办法就是创立 Assemble 对应的 Task。

doCreateTasksForVariant 办法就是创立跟 Variant 相干 Task 的办法,不过在 TaskManager 中,它是一个形象办法,交给了 ApplicationTaskManager 去实现。

那么它外面到底创立了哪些 Task 呢?往后面翻,前面的图片会通知你!

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

第二次创立多个 Task 调用的是 TaskManager#createPostApiTasks 办法,次要跟 ViewBinding、DataBinding 和 Kotlin 编译相干的 Task,感兴趣的能够看一下。

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

Task 过程

简略的解释一下:

蓝色的 :Gradle 配置阶段前 createTasksBeforeEvaluate 注册的 Task。

橙色 :Gradle 配置阶段实现后创立的 Task。

红色 :重要的 Task。

箭头 :依赖关系(并不是所有)。

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

如果咱们将下面的图片和之前官网的打包流程图联合起来,发现很多都是能够对应起来的:

1. 后面有 AIDL、Source Code、Resource 资源文件这类的解决 Task。

2. 中期有 Class 编译相干、代码混同相干的 Task。

3. 前期又有创立合并 Dex 以及打包 Apk 相干的 Task。

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

./gradlew assembleDebug  

这个命令会调用 assembleDebug 对应的 Task,在此之前,它会执行完后面依赖的 Task,比方资源解决、编译相干、打包生成咱们想要的 APK 等等。

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


3. 总结

这篇文章的目标是心愿大家对 AGP 有一个轮廓,AGP 次要做了什么?

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

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

退出移动版