美文网首页Android Other
Android安卓进阶技术分享之AGP工作原理

Android安卓进阶技术分享之AGP工作原理

作者: BlueSocks | 来源:发表于2022-04-14 15:19 被阅读0次

    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 都是打包这个流水线的螺丝钉。

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

    相关文章

      网友评论

        本文标题:Android安卓进阶技术分享之AGP工作原理

        本文链接:https://www.haomeiwen.com/subject/ftitertx.html