美文网首页
AGP源码浅析一

AGP源码浅析一

作者: 获取失败 | 来源:发表于2020-10-03 00:18 被阅读0次

    18年的时候有研究过AGP,当时主要是分析它的增量编译过程,本想写几篇技术博客来记录下的,后来由于工作实在太忙没写下去,最近在开发一款构建加速插件,又研究了下KGP AGP,刚好国庆有空就把它记录下来了

    插件入口

    Gradle的插件都是继承于Plugin接口的,在AGP里面分别为AppPluginLibraryPlugin,两者都是继承于BasePluginAppPlugin插件负责把代码打包成apk,而LibraryPlugin则是负责把项目代码打包成aar,这里我们只分析AppPlugin插件,源码是在下面几个类里

    com.android.build.gradle.AppPlugin
    com.android.build.gradle.AbstractAppPlugin
    com.android.build.gradle.BasePlugin
    

    他们的关系如下:


    初始化的控制逻辑都在BasePlugin类里面,BasePlugin大概是干了几件事情
    • 配置项目
    • 创建extension
    • 创建tasks等等
      源码在apply方法里,如下:
        @Override
        public void apply(@NonNull Project project) {
            //这里省略了部分代码...
            threadRecorder.record(
                        ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
                        project.getPath(),
                        null,
                        this::configureProject);
    
                threadRecorder.record(
                        ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
                        project.getPath(),
                        null,
                        this::configureExtension);
    
                threadRecorder.record(
                        ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
                        project.getPath(),
                        null,
                        this::createTasks);
        }
    

    配置项目

    configureProject方法比较简单,大概做了三个事情,创建AndroidBuilder,创建GlobalScope,监听Gradle的构建生命周期,做一些cache保存与清理工作。GlobalScopeAndroidBuilder是个上下文,保存了构建过程中所需要的各种数据,GlobalScope则是用来保存整个Plugin需要的一些数据结构,关键代码如下

    private void configureProject() {
            //这里省略部分代码...
            //创建SdkHandler
            sdkHandler = new SdkHandler(project, getLogger());
            //创建AndroidBuilder
            AndroidBuilder androidBuilder =
                    new AndroidBuilder(
                            project == project.getRootProject() ? project.getName() : project.getPath(),
                            creator,
                            new GradleProcessExecutor(project),
                            new GradleJavaProcessExecutor(project),
                            extraModelInfo.getSyncIssueHandler(),
                            extraModelInfo.getMessageReceiver(),
                            getLogger(),
                            isVerbose());
            //创建GlobalScope
            globalScope =
                    new GlobalScope(
                            project,
                            new ProjectWrapper(project),
                            projectOptions,
                            dslScope,
                            androidBuilder,
                            sdkHandler,
                            registry,
                            buildCache);
        //最后就是监听Gradle构建生命周期监听,代码有点长,这里就不贴出来了
    }
    

    创建extension

    在上一步创建完一些全局配置后,接着就开始创建Extension了,我们常常在build.gradle见到的android{} buildTypes{} productFlavor{} signingConfigs{}等等,就是在这里被创建出来的。configureExtension方法的主要任务有两个:

    • 创建extension
    • 创建SourceSetManager TaskManager以及VariantManager
    extension的创建

    首先创建几个容器,对应的是BuildType、ProductFlavor、SigningConfig关键代码如下:

    private void configureExtension() {
          final NamedDomainObjectContainer<BuildType> buildTypeContainer =
                    project.container(
                            BuildType.class,
                            new BuildTypeFactory(
                                    objectFactory,
                                    project,
                                    extraModelInfo.getSyncIssueHandler(),
                                    extraModelInfo.getDeprecationReporter()));
            final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer =
                    project.container(
                            ProductFlavor.class,
                            new ProductFlavorFactory(
                                    objectFactory,
                                    project,
                                    extraModelInfo.getDeprecationReporter(),
                                    project.getLogger()));
            final NamedDomainObjectContainer<SigningConfig> signingConfigContainer =
                    project.container(
                            SigningConfig.class,
                            new SigningConfigFactory(
                                    objectFactory,
                                    GradleKeystoreHelper.getDefaultDebugKeystoreLocation()));
    }
    

    容器被创建出来后,我们就可以对它进行配置了,譬如常见的

        buildTypes {
            debug {
                debuggable true
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'
                signingConfig signingConfigs.debug
                ext.enableCrashlytics = false
            }
        }
    

    我们可以在buildTypes里面配置的代码混淆、签名、资源压缩等等在BuildType类里面都能找得到。
    容器创建完后跟着就创建名字为android的extension,对应类型为AppExtension,代码是在com.android.build.gradle.AbstractAppPlugin里面,关键代码如下

    private void configureExtension() {
            //省略部分代码...
            extension = createExtension(/*省略参数列表*/);
    }
    
    @NonNull
    @Override
    protected BaseExtension createExtension(
             //省略部分代码....
            @NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer,
            @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer,
            @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer,
            @NonNull NamedDomainObjectContainer<BaseVariantOutput> buildOutputs,
            @NonNull SourceSetManager sourceSetManager,
            @NonNull ExtraModelInfo extraModelInfo) {
            return project.getExtensions()
                    .create( "android",getExtensionClass(), /*省略参数列表*/ );
    }
    

    创建管理器

    主要有SourceSetManager用来管理代码的,TaskManager用来管理任务的,以及VariantManager用来维护变构体的。代码如下:

    private void configureExtension() {
        //省略部分代码....
        //创建SourceSetManager
        sourceSetManager = createSourceSetManager();
        //创建TaskManager,类型为ApplicationTaskManager
        taskManager = createTaskManager(/*省略参数列表*/ );
        //创建VariantManager
        variantManager = new VariantManager(/*省略参数列表*/ );
    }
    

    管理器创建完了,接着会为signingConfigs buildTypes等创建一份默认配置,最后注册构建模块。

    构建Tasks的创建

    Tasks的创建在createTasks方法里面,createTasks会调用taskManager的相应方法去创建一些列的Tasks,譬如常见的assemble compile${variantName}JavaWithJavac merge${variantName}Resources 等等(注意常见compile${variantName}Kotlin等Kotlin相关Task并不是由AGP提供的,它们是由KGP提供的)。代码如下:

    private void createTasks() {
            threadRecorder.record(
            /*省略参数列表*/ 
                    () -> taskManager.createTasksBeforeEvaluate());
            project.afterEvaluate(
                    project -> {
                        threadRecorder.record(
                               /*省略参数列表*/ 
                                () -> createAndroidTasks());
                    });
        }
    

    这里分为两部分第一部分是createTasksBeforeEvaluate,一些check lint test等任务会在这里会被创建,第二部分是createAndroidTaskscreateAndroidTasks最终也是会通过调用taskManager的createAndroidTasks方法来创建任务,核心的构建任务就是在此被创建出来的,核心代码如下:

    public void createAndroidTasks() {
          //省略部分代码....
            for (final VariantScope variantScope : variantScopes) {
                recorder.record(
                       ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
                        project.getPath(),
                        variantScope.getFullVariantName(),
                        () -> createTasksForVariantData(variantScope));
            }
            taskManager.createSourceSetArtifactReportTask(globalScope);
            taskManager.createReportTasks(variantScopes);
        }
    

    可以看见createAndroidTasks会为每个变构体创建一套构建Tasks,createTasksForVariantData的核心代码大概如下:

    public void createTasksForVariantData(final VariantScope variantScope) {
          //省略部分代码....
        createAssembleTaskForVariantData(variantData);
          //省略部分代码....
        taskManager.createTasksForVariantScope(variantScope);
    }
    

    createAssembleTaskForVariantData主要是创建了assemble任务,并且通过dependsOn来设置一些依赖关系,这里我们只看createTasksForVariantScope方法做的事情,代码如下:

     public void createTasksForVariantScope(@NonNull final VariantScope variantScope) {
            BaseVariantData variantData = variantScope.getVariantData();
    
            createAnchorTasks(variantScope);
            createCheckManifestTask(variantScope);
    
    
            taskFactory.create(new MainApkListPersistence.ConfigAction(variantScope));
            createBuildArtifactReportTask(variantScope);
    
            // Add a task to process the manifest(s)
            createMergeApkManifestsTask(variantScope);
    
            // Add a task to create the res values
            createGenerateResValuesTask(variantScope);
    
            // Add a task to compile renderscript files.
            createRenderscriptTask(variantScope);
    
            // Add a task to merge the resource folders
            createMergeResourcesTask(
                    variantScope,
                    true,
                    Sets.immutableEnumSet(MergeResources.Flag.PROCESS_VECTOR_DRAWABLES));
    
            // Add tasks to compile shader
            createShaderTask(variantScope);
    
            // Add a task to merge the asset folders
            createMergeAssetsTask(variantScope);
    
            //省略部分代码...
            // Add a task to create the BuildConfig class
            createBuildConfigTask(variantScope);
    
            // Add a task to process the Android Resources and generate source files
            createApkProcessResTask(variantScope);
    
            // Add a task to process the java resources
            createProcessJavaResTask(variantScope);
    
            createAidlTask(variantScope);
    
            // Add NDK tasks
            createNdkTasks(variantScope);
            variantScope.setNdkBuildable(getNdkBuildable(variantData));
    
            // Add external native build tasks
            createExternalNativeBuildJsonGenerators(variantScope);
            createExternalNativeBuildTasks(variantScope);
    
            // Add a task to merge the jni libs folders
            createMergeJniLibFoldersTasks(variantScope);
    
            //省略部分代码...
            // Add a compile task
            createCompileTask(variantScope);
            createStripNativeLibraryTask(taskFactory, variantScope);
    
            //省略部分代码...
            createPackagingTask(variantScope, buildInfoWriterTask);
    
            // Create the lint tasks, if enabled
            createLintTasks(variantScope);
    
            taskFactory.create(new FeatureSplitTransitiveDepsWriterTask.ConfigAction(variantScope));
    
            createDynamicBundleTask(variantScope);
        }
    

    可以看见包括资源合并、资源编译、apk打包、jni合并等等的任务在此被创建出来。

    总结

    本文主要对从apply 入口函数开始,简析了AGP的初始化配置以及构建任务创建过程,AGP的源码十分的庞大,三言两语很难就能分析完,本文主要是为各位读者整理了下AGP的一些核心过程,篇幅问题很多代码都已被我精简省略,要了解更多细节读者们可自行翻译源码。

    相关文章

      网友评论

          本文标题:AGP源码浅析一

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