前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Gradle源码分析

Android Gradle源码分析

作者头像
老马的编程之旅
发布2022-06-23 14:07:04
1.3K0
发布2022-06-23 14:07:04
举报
文章被收录于专栏:深入理解Android

一.如何调试Android Gradle源码

最简单的方式如下: 1.配置 gradle.properties 比较方便的做法是配置全局的 gradle.properties,这样对所有 Gradle 工具都适用,配置文件位于 ~/.gradle/gradle.properties,在 gradle.properties 文件中加上 org.gradle.jvmargs 属性:

代码语言:javascript
复制
org.gradle.jvmargs=-XX:MaxPermSize=4g -XX:+HeapDumpOnOutOfMemoryError -Xmx4g -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006

2.启动 Gradle Daemon 进程

代码语言:javascript
复制
$ ./gradlew --stop     # 先停掉 daemon 进程
$ ./gradlew --daemon   # 启动 daemon 进程

3.Attach daemon 进程

然后,选择 Gradle Daemon 进程,如下图所示:

4.新建一个空的module 删除所有其他文件,只留如下2个文件

gradle文件配置如下

代码语言:javascript
复制
apply plugin: 'groovy'

dependencies {
    implementation gradleApi()
    implementation localGroovy()
    implementation 'com.android.tools.build:gradle:3.5.0'
}

这样就引入了源码,想看对应版本的源码,改变相应的引用即可 保持和classpath声明的一致

代码语言:javascript
复制
 classpath 'com.android.tools.build:gradle:3.5.0'

5.放断点 在相应的代码行放上断点

6.运行构建,开始调试

在命令行中执行相应的 Task,例如:

代码语言:javascript
复制
$ ./gradlew assembleDebug

二.Gralde Plugin源码分析

平时我们使用plugin都是通过apply方法,例如:

代码语言:javascript
复制
apply plugin: 'com.android.application'

所以我们就从apply方法入手

1.AppPlugin#apply

从上面得知 ‘com.android.application’ 对应com.android.build.gradle.AppPlugin

AppPlugin继承自AbstractAppPlugin,AbstractAppPlugin继承自BasePlugin

2.BasePlugin#apply

代码语言:javascript
复制
  @Override
    public final void apply(@NonNull Project project) {
        CrashReporting.runAction(
                () -> {
                    basePluginApply(project);
                    pluginSpecificApply(project);
                });
    }

3.BasePlugin#basePluginApply

代码语言:javascript
复制
private void basePluginApply(@NonNull Project project) {
        // We run by default in headless mode, so the JVM doesn't steal focus.
        System.setProperty("java.awt.headless", "true");

        this.project = project;
        this.projectOptions = new ProjectOptions(project);
        checkGradleVersion(project, getLogger(), projectOptions);
        DependencyResolutionChecks.registerDependencyCheck(project, projectOptions);

        project.getPluginManager().apply(AndroidBasePlugin.class);

        checkPathForErrors();
        checkModulesForErrors();

        PluginInitializer.initialize(project);
        RecordingBuildListener buildListener = ProfilerInitializer.init(project, projectOptions);
        ProfileAgent.INSTANCE.register(project.getName(), buildListener);
        threadRecorder = ThreadRecorder.get();

        Workers.INSTANCE.initFromProject(
                projectOptions,
                // possibly, in the future, consider using a pool with a dedicated size
                // using the gradle parallelism settings.
                ForkJoinPool.commonPool());

        ProcessProfileWriter.getProject(project.getPath())
                .setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION)
                .setAndroidPlugin(getAnalyticsPluginType())
                .setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST)
                .setOptions(AnalyticsUtil.toProto(projectOptions));

        if (!projectOptions.get(BooleanOption.ENABLE_NEW_DSL_AND_API)) {

            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);
        } else {
            // Apply the Java plugin
            project.getPlugins().apply(JavaBasePlugin.class);

            // create the delegate
            ProjectWrapper projectWrapper = new ProjectWrapper(project);
            PluginDelegate<E> delegate =
                    new PluginDelegate<>(
                            project.getPath(),
                            project.getObjects(),
                            project.getExtensions(),
                            project.getConfigurations(),
                            projectWrapper,
                            projectWrapper,
                            project.getLogger(),
                            projectOptions,
                            getTypedDelegate());

            delegate.prepareForEvaluation();

            // after evaluate callbacks
            project.afterEvaluate(
                    CrashReporting.afterEvaluate(
                            p -> {
                                threadRecorder.record(
                                        ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
                                        p.getPath(),
                                        null,
                                        delegate::afterEvaluate);
                            }));
        }
    }

threadRecoirder.recode()是记录最后一个参数的路径和执行的时间点,前面做了一些必要性的信息检测之前,其实主要做了以下几件事情:

代码语言:javascript
复制
// 配置项目,设置构建回调
this::configureProject
// 配置Extension
this::configureExtension
// 创建任务
this::createTasks

4.configureProject

代码语言:javascript
复制
 private void configureProject() {
        final Gradle gradle = project.getGradle();
        ObjectFactory objectFactory = project.getObjects();

        extraModelInfo = new ExtraModelInfo(project.getPath(), projectOptions, project.getLogger());

        final SyncIssueHandler syncIssueHandler = extraModelInfo.getSyncIssueHandler();

        SdkComponents sdkComponents =
                SdkComponents.Companion.createSdkComponents(
                        project,
                        projectOptions,
                        // We pass a supplier here because extension will only be set later.
                        this::getExtension,
                        getLogger(),
                        syncIssueHandler);

        dataBindingBuilder = new DataBindingBuilder();
        dataBindingBuilder.setPrintMachineReadableOutput(
                SyncOptions.getErrorFormatMode(projectOptions) == ErrorFormatMode.MACHINE_PARSABLE);

        if (projectOptions.hasRemovedOptions()) {
            syncIssueHandler.reportWarning(
                    Type.GENERIC, projectOptions.getRemovedOptionsErrorMessage());
        }

        if (projectOptions.hasDeprecatedOptions()) {
            extraModelInfo
                    .getDeprecationReporter()
                    .reportDeprecatedOptions(projectOptions.getDeprecatedOptions());
        }

        if (!projectOptions.getExperimentalOptions().isEmpty()) {
            projectOptions
                    .getExperimentalOptions()
                    .forEach(extraModelInfo.getDeprecationReporter()::reportExperimentalOption);
        }

        // Enforce minimum versions of certain plugins
        GradlePluginUtils.enforceMinimumVersionsOfPlugins(project, syncIssueHandler);

        // Apply the Java plugin
        project.getPlugins().apply(JavaBasePlugin.class);

        DslScopeImpl dslScope =
                new DslScopeImpl(
                        syncIssueHandler, extraModelInfo.getDeprecationReporter(), objectFactory);

        @Nullable
        FileCache buildCache = BuildCacheUtils.createBuildCacheIfEnabled(project, projectOptions);

        globalScope =
                new GlobalScope(
                        project,
                        creator,
                        new ProjectWrapper(project),
                        projectOptions,
                        dslScope,
                        sdkComponents,
                        registry,
                        buildCache,
                        extraModelInfo.getMessageReceiver());

        project.getTasks()
                .named("assemble")
                .configure(
                        task ->
                                task.setDescription(
                                        "Assembles all variants of all applications and secondary packages."));

        // call back on execution. This is called after the whole build is done (not
        // after the current project is done).
        // This is will be called for each (android) projects though, so this should support
        // being called 2+ times.
        gradle.addBuildListener(
                new BuildListener() {
                    @Override
                    public void buildStarted(@NonNull Gradle gradle) {}

                    @Override
                    public void settingsEvaluated(@NonNull Settings settings) {}

                    @Override
                    public void projectsLoaded(@NonNull Gradle gradle) {}

                    @Override
                    public void projectsEvaluated(@NonNull Gradle gradle) {}

                    @Override
                    public void buildFinished(@NonNull BuildResult buildResult) {
                        // Do not run buildFinished for included project in composite build.
                        if (buildResult.getGradle().getParent() != null) {
                            return;
                        }
                        ModelBuilder.clearCaches();
                        Workers.INSTANCE.shutdown();
                        sdkComponents.unload();
                        SdkLocator.resetCache();
                        threadRecorder.record(
                                ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
                                project.getPath(),
                                null,
                                () -> {
                                    if (!projectOptions.get(
                                            BooleanOption.KEEP_SERVICES_BETWEEN_BUILDS)) {
                                        WorkerActionServiceRegistry.INSTANCE
                                                .shutdownAllRegisteredServices(
                                                        ForkJoinPool.commonPool());
                                    }
                                    Main.clearInternTables();
                                });
                        DeprecationReporterImpl.Companion.clean();
                    }
                });

        createLintClasspathConfiguration(project);
    }

这里在添加了 BuildListener,在 buildFinished 的时候清楚了dex缓存 总结一下 configureProject 做的事情,主要是进行版本有效性的判断,并设置了构建流程的回调来处理依赖和dex的加载和缓存清理。

5.configureExtension 这个阶段就是配置 extension 的阶段,就是创建我们 android 块中的可配置的对象

代码语言:javascript
复制
ObjectFactory objectFactory = project.getObjects();
        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()));

        final NamedDomainObjectContainer<BaseVariantOutput> buildOutputs =
                project.container(BaseVariantOutput.class);

        project.getExtensions().add("buildOutputs", buildOutputs);

        sourceSetManager =
                new SourceSetManager(
                        project,
                        isPackagePublished(),
                        globalScope.getDslScope(),
                        new DelayedActionsExecutor());

        extension =
                createExtension(
                        project,
                        projectOptions,
                        globalScope,
                        buildTypeContainer,
                        productFlavorContainer,
                        signingConfigContainer,
                        buildOutputs,
                        sourceSetManager,
                        extraModelInfo);

        globalScope.setExtension(extension);

首先创建了 BuildType、ProductFlavor、SigningConfig 三个类型的Container,接着传入到了createExtension方法中,点入查看是个抽象的方法,各自的实现在子类中,这里也就是我们的AppPlugin 中

6.AbstractAppPlugin#createExtension

代码语言:javascript
复制
@NonNull
    @Override
    protected BaseExtension createExtension(
            @NonNull Project project,
            @NonNull ProjectOptions projectOptions,
            @NonNull GlobalScope globalScope,
            @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(),
                        project,
                        projectOptions,
                        globalScope,
                        buildTypeContainer,
                        productFlavorContainer,
                        signingConfigContainer,
                        buildOutputs,
                        sourceSetManager,
                        extraModelInfo,
                        isBaseApplication);
    }

这里也就是可以看到我们android块配置是如何来的了,对应的Extension也确实是AppExtension,继续查看 configureExtension 的源码

代码语言:javascript
复制
 variantFactory = createVariantFactory(globalScope, extension);

        taskManager =
                createTaskManager(
                        globalScope,
                        project,
                        projectOptions,
                        dataBindingBuilder,
                        extension,
                        variantFactory,
                        registry,
                        threadRecorder);

        variantManager =
                new VariantManager(
                        globalScope,
                        project,
                        projectOptions,
                        extension,
                        variantFactory,
                        taskManager,
                        sourceSetManager,
                        threadRecorder);

        registerModels(registry, globalScope, variantManager, extension, extraModelInfo);

这一部分主要是创建一些管理类,其中 createTaskManager、createVariantFactory 都是抽象方法,对应的实现类

代码语言:javascript
复制
createTaskManager
AppPlugin -> ApplicationTaskManager
LibraryPlugin -> LibraryTaskManager

createVariantFactory
AppPlugin -> ApplicationVariantFactory
LibraryPlugin -> LibraryVariantFactory

这里简单介绍一下 TaskManager 就是创建具体任务的管理类,app 工程和库 library 工程所需的构建任务是不同的,后面我们会介绍 app 工程创建的构建任务;VariantFactory 就是我们常说的构建变体的工厂类,主要是生成Variant(构建变体)的对象。我们回到 createExtension 的源码中

代码语言:javascript
复制
 buildTypeContainer.whenObjectAdded(
                buildType -> {
                    if (!this.getClass().isAssignableFrom(DynamicFeaturePlugin.class)) {
                        SigningConfig signingConfig =
                                signingConfigContainer.findByName(BuilderConstants.DEBUG);
                        buildType.init(signingConfig);
                    } else {
                        // initialize it without the signingConfig for dynamic-features.
                        buildType.init();
                    }
                    variantManager.addBuildType(buildType);
                });

        productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor);

        // map whenObjectRemoved on the containers to throw an exception.
        signingConfigContainer.whenObjectRemoved(
                new UnsupportedAction("Removing signingConfigs is not supported."));
        buildTypeContainer.whenObjectRemoved(
                new UnsupportedAction("Removing build types is not supported."));
        productFlavorContainer.whenObjectRemoved(
                new UnsupportedAction("Removing product flavors is not supported."));

        // create default Objects, signingConfig first as its used by the BuildTypes.
        variantFactory.createDefaultComponents(
                buildTypeContainer, productFlavorContainer, signingConfigContainer);

这一部分做得事情,配置了 BuildTypeContainer、ProductFlavorContainer、SigningConfigContainer 这三个配置项的 whenObjectAdded 的回调,每个配置的添加都会加入到 variantManager 中;创建默认配置,下面是 ApplicationVariantFactory 的 createDefaultComponents 代码

7.ApplicationVariantFactory#createDefaultComponents

代码语言:javascript
复制
 @Override
    public void createDefaultComponents(
            @NonNull NamedDomainObjectContainer<BuildType> buildTypes,
            @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavors,
            @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigs) {
        // must create signing config first so that build type 'debug' can be initialized
        // with the debug signing config.
        signingConfigs.create(DEBUG);
        buildTypes.create(DEBUG);
        buildTypes.create(RELEASE);
    }

总结一下 configureExtension 方法的作用,主要是创建 Android 插件的扩展对象,对配置项 BuildType、ProductFlavor、SigningConfig 做了统一的创建和回调处理, 创建taskManager、variantFactory、variantManager。

8.BasePlugin#createTasks

代码语言:javascript
复制
private void createTasks() {
        threadRecorder.record(
                ExecutionType.TASK_MANAGER_CREATE_TASKS,
                project.getPath(),
                null,
                () -> taskManager.createTasksBeforeEvaluate());

        project.afterEvaluate(
                CrashReporting.afterEvaluate(
                        p -> {
                            sourceSetManager.runBuildableArtifactsActions();

                            threadRecorder.record(
                                    ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
                                    project.getPath(),
                                    null,
                                    this::createAndroidTasks);
                        }));
    }

这里主要是分两块,一个是在 beforeEvaluate 创建任务;一个是在 afterEvaluate 创建任务。这里的区别是 AndroidTask 是依赖配置项的配置才能生成相应任务,所以是需要在 afterEvaluate 之后创建,如果对项目评估回调不理解的话,可以查阅Project文档。beforeEvaluate 创建的任务跟我们编译没有太大关系,我们重点查看一下 afterEvaluate 创建的任务 createAndroidTasks

代码语言:javascript
复制
List<VariantScope> variantScopes = variantManager.createAndroidTasks();

        ApiObjectFactory apiObjectFactory =
                new ApiObjectFactory(
                        extension,
                        variantFactory,
                        project.getObjects());
        for (VariantScope variantScope : variantScopes) {
            BaseVariantData variantData = variantScope.getVariantData();
            apiObjectFactory.create(variantData);
        }

        // Make sure no SourceSets were added through the DSL without being properly configured
        // Only do it if we are not restricting to a single variant (with Instant
        // Run or we can find extra source set
        if (projectOptions.get(StringOption.IDE_RESTRICT_VARIANT_NAME) == null) {
            sourceSetManager.checkForUnconfiguredSourceSets();
        }

        // must run this after scopes are created so that we can configure kotlin
        // kapt tasks
        taskManager.addDataBindingDependenciesIfNecessary(
                extension.getDataBinding(), variantManager.getVariantScopes());


        // create the global lint task that depends on all the variants
        taskManager.configureGlobalLintTask(variantManager.getVariantScopes());

        int flavorDimensionCount = 0;
        if (extension.getFlavorDimensionList() != null) {
            flavorDimensionCount = extension.getFlavorDimensionList().size();
        }

        taskManager.createAnchorAssembleTasks(
                variantScopes,
                extension.getProductFlavors().size(),
                flavorDimensionCount,
                variantFactory.getVariantConfigurationTypes().size());

        // now publish all variant artifacts.
        for (VariantScope variantScope : variantManager.getVariantScopes()) {
            variantManager.publishBuildArtifacts(variantScope);
        }

        checkSplitConfiguration();
        variantManager.setHasCreatedTasks(true);

我们主要看下variantManager的createAndroidTasks的方法

9.VariantManager#createAndroidTasks

代码语言:javascript
复制
public List<VariantScope> createAndroidTasks() {
        variantFactory.validateModel(this);
        variantFactory.preVariantWork(project);

        if (variantScopes.isEmpty()) {
            populateVariantDataList();
        }

        // Create top level test tasks.
        taskManager.createTopLevelTestTasks(!productFlavors.isEmpty());

        for (final VariantScope variantScope : variantScopes) {
            createTasksForVariantData(variantScope);
        }

        taskManager.createSourceSetArtifactReportTask(globalScope);

        taskManager.createReportTasks(variantScopes);

        return variantScopes;
    }

首先判断 variantDataList 是否是空,如果是空的就会进入到 populateVariantDataList 方法中

10.VariantManager#populateVariantDataList

代码语言:javascript
复制
public void populateVariantDataList() {
        List<String> flavorDimensionList = extension.getFlavorDimensionList();

        if (productFlavors.isEmpty()) {
            configureDependencies();
            createVariantDataForProductFlavors(Collections.emptyList());
        } else {
            // ensure that there is always a dimension
            if (flavorDimensionList == null || flavorDimensionList.isEmpty()) {
                globalScope
                        .getErrorHandler()
                        .reportError(
                                EvalIssueReporter.Type.UNNAMED_FLAVOR_DIMENSION,
                                new EvalIssueException(
                                        "All flavors must now belong to a named flavor dimension. "
                                                + "Learn more at "
                                                + "https://d.android.com/r/tools/flavorDimensions-missing-error-message.html"));
            } else if (flavorDimensionList.size() == 1) {
                // if there's only one dimension, auto-assign the dimension to all the flavors.
                String dimensionName = flavorDimensionList.get(0);
                for (ProductFlavorData<CoreProductFlavor> flavorData : productFlavors.values()) {
                    CoreProductFlavor flavor = flavorData.getProductFlavor();
                    if (flavor.getDimension() == null && flavor instanceof DefaultProductFlavor) {
                        ((DefaultProductFlavor) flavor).setDimension(dimensionName);
                    }
                }
            }

            // can only call this after we ensure all flavors have a dimension.
            configureDependencies();

            // Create iterable to get GradleProductFlavor from ProductFlavorData.
            Iterable<CoreProductFlavor> flavorDsl =
                    Iterables.transform(
                            productFlavors.values(),
                            ProductFlavorData::getProductFlavor);

            // Get a list of all combinations of product flavors.
            List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList =
                    ProductFlavorCombo.createCombinations(
                            flavorDimensionList,
                            flavorDsl);

            for (ProductFlavorCombo<CoreProductFlavor>  flavorCombo : flavorComboList) {
                //noinspection unchecked
                createVariantDataForProductFlavors(
                        (List<ProductFlavor>) (List) flavorCombo.getFlavorList());
            }
        }

        configureVariantArtifactTransforms(variantScopes);
    }

从方法注释可以看到,这个方法主要的作用就是创建所有的 variants

创建构建变体(BuildVariant) 继续观察上面的代码,可以看到无论是否有配置productFlavor 子项,都会进入到 createVariantDataForProductFlavors 方法。如果有配置的话,通过获取配置的 flavorDimension 和 productFlavor 数组,调用 ProductFlavorCombo.createCombinations 组合出最后的产品风味数组 flavorComboList ,最后通过遍历调用 createVariantDataForProductFlavors 方法

11.VariantManager#createVariantDataForProductFlavors

代码语言:javascript
复制
/**
     * Creates VariantData for a specified list of product flavor.
     *
     * This will create VariantData for all build types of the given flavors.
     *
     * @param productFlavorList the flavor(s) to build.
     */
    private void createVariantDataForProductFlavors(
            @NonNull List<ProductFlavor> productFlavorList) {
        for (VariantType variantType : variantFactory.getVariantConfigurationTypes()) {
            createVariantDataForProductFlavorsAndVariantType(productFlavorList, variantType);
        }
    }

12.VariantManager#createVariantDataForProductFlavorsAndVariantType

代码语言:javascript
复制
......
if (!ignore) {
                BaseVariantData variantData =
                        createVariantDataForVariantType(
                                buildTypeData.getBuildType(), productFlavorList, variantType);
                addVariant(variantData);
				........
             
            }

看上述代码,通过 creatVariantData 方法,将 buildType 和 productFlavor 的作为参数传入,创建了 variantData,并且加入到了 variantScopes 集合中,这里我们就是将所有的构建变体VariantScope集合到了 variantScopes 中。

接着我们返回继续看 createAndroidTasks 方法

  1. VariantManager#createAndroidTasks
代码语言:javascript
复制
   /** Variant/Task creation entry point. */
    public List<VariantScope> createAndroidTasks() {
        variantFactory.validateModel(this);
        variantFactory.preVariantWork(project);

        if (variantScopes.isEmpty()) {
            populateVariantDataList();
        }

        // Create top level test tasks.
        taskManager.createTopLevelTestTasks(!productFlavors.isEmpty());

        for (final VariantScope variantScope : variantScopes) {
            createTasksForVariantData(variantScope);
        }

        taskManager.createSourceSetArtifactReportTask(globalScope);

        taskManager.createReportTasks(variantScopes);

        return variantScopes;
    }

继续看如下关键代码:

代码语言:javascript
复制
    for (final VariantScope variantScope : variantScopes) {
            createTasksForVariantData(variantScope);
        }

14.VariantManager#createTasksForVariantData

代码语言:javascript
复制
/** Create tasks for the specified variant. */
    public void createTasksForVariantData(final VariantScope variantScope) {
        final BaseVariantData variantData = variantScope.getVariantData();
        final VariantType variantType = variantData.getType();
        final GradleVariantConfiguration variantConfig = variantScope.getVariantConfiguration();

        taskManager.createAssembleTask(variantData);
        if (variantType.isBaseModule()) {
            taskManager.createBundleTask(variantData);
        }

        if (variantType.isTestComponent()) {
           ...........
        } else {
            taskManager.createTasksForVariantScope(
                    variantScope,
                    variantScopes
                            .stream()
                            .filter(TaskManager::isLintVariant)
                            .collect(Collectors.toList()));
        }
    }

首先会先根据 variantData 信息创建 assemble 任务,可以看下taskManager. createAssembleTask里的代码,然后这里最后是if else判断, if (variantType.isTestComponent())这里明显是测试会走,所以打包时候我们直接看else

代码语言:javascript
复制
taskManager.createTasksForVariantScope(
                    variantScope,
                    variantScopes
                            .stream()
                            .filter(TaskManager::isLintVariant)
                            .collect(Collectors.toList()));

15.TaskManager#createAssembleTask

代码语言:javascript
复制
 public void createAssembleTask(@NonNull final BaseVariantData variantData) {
        final VariantScope scope = variantData.getScope();
        taskFactory.register(
       			 //注册任务名字为 assembleXXX的任务
                getAssembleTaskName(scope, "assemble"),
                null /*preConfigAction*/,
                task -> {
                    task.setDescription(
                            "Assembles main output for variant "
                                    + scope.getVariantConfiguration().getFullName());
                },
                taskProvider -> scope.getTaskContainer().setAssembleTask(taskProvider));
    }

回到 createAndroidTasks 方法中

16.BasePlugin#createAndroidTasks

代码语言:javascript
复制
.......
 ApiObjectFactory apiObjectFactory =
                new ApiObjectFactory(
                        extension,
                        variantFactory,
                        project.getObjects());
        for (VariantScope variantScope : variantScopes) {
            BaseVariantData variantData = variantScope.getVariantData();
            apiObjectFactory.create(variantData);
        }
 
.......

最后就遍历 VariantScope 通过 ApiObjectFactory 创建 variantApi,添加到 extensions 中; 至此,我们就已经将配置的构建变种任务已经添加到我们的任务列表中,并形成了相关依赖。

代码语言:javascript
复制
public BaseVariantImpl create(BaseVariantData variantData) {
        if (variantData.getType().isTestComponent()) {
            // Testing variants are handled together with their "owners".
            createVariantOutput(variantData, null);
            return null;
        }

        BaseVariantImpl variantApi =
                variantFactory.createVariantApi(
                        objectFactory,
                        variantData,
                        readOnlyObjectProvider);
        if (variantApi == null) {
            return null;
        }
        ............
        createVariantOutput(variantData, variantApi);

        try {
            // Only add the variant API object to the domain object set once it's been fully
            // initialized.
            extension.addVariant(variantApi);
        } catch (Throwable t) {
            // Adding variant to the collection will trigger user-supplied callbacks
            throw new ExternalApiUsageException(t);
        }

        return variantApi;
    }

Application 的编译任务 17. ApplicationTaskManager#createTasksForVariantScope taskManager.createTasksForVariantData,发现 createTasksForVariantData 是抽象方法,这里的 taskManager 具体实现是 ApplicationTaskManager,查看 ApplicationTaskManager 的 createTasksForVariantData 方法

代码语言:javascript
复制
@Override
    public void createTasksForVariantScope(
            @NonNull final VariantScope variantScope,
            @NonNull List<VariantScope> variantScopesForLint) {
        createAnchorTasks(variantScope);
        createCheckManifestTask(variantScope);

        handleMicroApp(variantScope);

        // Create all current streams (dependencies mostly at this point)
        createDependencyStreams(variantScope);

        // Add a task to publish the applicationId.
        createApplicationIdWriterTask(variantScope);

        taskFactory.register(new MainApkListPersistence.CreationAction(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 external native build tasks
        createExternalNativeBuildJsonGenerators(variantScope);
        createExternalNativeBuildTasks(variantScope);

        // Add a task to merge the jni libs folders
        createMergeJniLibFoldersTasks(variantScope);

        // Add feature related tasks if necessary
        if (variantScope.getType().isBaseModule()) {
            // Base feature specific tasks.
            taskFactory.register(new FeatureSetMetadataWriterTask.CreationAction(variantScope));

            createValidateSigningTask(variantScope);
            // Add a task to produce the signing config file.
            taskFactory.register(new SigningConfigWriterTask.CreationAction(variantScope));

            if (extension.getDataBinding().isEnabled()) {
                // Create a task that will package the manifest ids(the R file packages) of all
                // features into a file. This file's path is passed into the Data Binding annotation
                // processor which uses it to known about all available features.
                //
                // <p>see: {@link TaskManager#setDataBindingAnnotationProcessorParams(VariantScope)}
                taskFactory.register(
                        new DataBindingExportFeatureApplicationIdsTask.CreationAction(
                                variantScope));

            }
        } else {
            // Non-base feature specific task.
            // Task will produce artifacts consumed by the base feature
            taskFactory.register(
                    new FeatureSplitDeclarationWriterTask.CreationAction(variantScope));
            if (extension.getDataBinding().isEnabled()) {
                // Create a task that will package necessary information about the feature into a
                // file which is passed into the Data Binding annotation processor.
                taskFactory.register(
                        new DataBindingExportFeatureInfoTask.CreationAction(variantScope));
            }
            taskFactory.register(new MergeConsumerProguardFilesTask.CreationAction(variantScope));
        }

        // Add data binding tasks if enabled
        createDataBindingTasksIfNecessary(variantScope, MergeType.MERGE);

        // Add a compile task
        createCompileTask(variantScope);

        createStripNativeLibraryTask(taskFactory, variantScope);

        if (variantScope.getVariantData().getMultiOutputPolicy().equals(MultiOutputPolicy.SPLITS)) {
            if (extension.getBuildToolsRevision().getMajor() < 21) {
                throw new RuntimeException(
                        "Pure splits can only be used with buildtools 21 and later");
            }

            createSplitTasks(variantScope);
        }

        createPackagingTask(variantScope);

        maybeCreateLintVitalTask(
                (ApkVariantData) variantScope.getVariantData(), variantScopesForLint);

        // Create the lint tasks, if enabled
        createLintTasks(variantScope, variantScopesForLint);

        taskFactory.register(new FeatureSplitTransitiveDepsWriterTask.CreationAction(variantScope));

        createDynamicBundleTask(variantScope);
    }

这个主要就是生成 variantData 的一系列像 compileXXX、generateXXX、processXXX、mergeXXX的任务,这一系列 task 就是构建一个可运行的完整APK的所需的所有task。

Dex的编译过程 我们查看重点方法,createCompileTask 1.ApplicationTaskManager#createCompileTask

代码语言:javascript
复制
protected void createCompileTask(@NonNull VariantScope variantScope) {
        TaskProvider<? extends JavaCompile> javacTask = createJavacTask(variantScope);
        addJavacClassesStream(variantScope);
        setJavaCompilerTask(javacTask, variantScope);
        createPostCompilationTasks(variantScope);
    }

创建Javac任务,将java文件编译为class文件

2.TaskManager#createJavacTask

代码语言:javascript
复制
public TaskProvider<? extends JavaCompile> createJavacTask(@NonNull final VariantScope scope) {
        taskFactory.register(new JavaPreCompileTask.CreationAction(scope));

        boolean processAnnotationsTaskCreated = ProcessAnnotationsTask.taskShouldBeCreated(scope);
        if (processAnnotationsTaskCreated) {
            taskFactory.register(new ProcessAnnotationsTask.CreationAction(scope));
        }

        final TaskProvider<? extends JavaCompile> javacTask =
                taskFactory.register(
                        new AndroidJavaCompile.CreationAction(
                                scope, processAnnotationsTaskCreated));

        postJavacCreation(scope);

        return javacTask;
    }

在执行 createPostCompilationTasks 之前,先创建了 javac 任务,任务名称为 compileXXXJavaWithJavac ,该任务是将 java 源文件编译成 class 文件,

代码语言:javascript
复制
/** Makes the given task the one used by top-level "compile" task. */
    public static void setJavaCompilerTask(
            @NonNull TaskProvider<? extends JavaCompile> javaCompilerTask,
            @NonNull VariantScope scope) {
        TaskFactoryUtils.dependsOn(scope.getTaskContainer().getCompileTask(), javaCompilerTask);
    }

使compileXXXXSources依赖compileXXXXJavaWithJavac

紧接着我们来看一下 createPostCompilationTasks 的方法 3.TaskManager#createPostCompilationTasks

代码语言:javascript
复制
/**
     * Creates the post-compilation tasks for the given Variant.
     *
     * These tasks create the dex file from the .class files, plus optional intermediary steps like
     * proguard and jacoco
     */
    public void createPostCompilationTasks(
            @NonNull final VariantScope variantScope) {



        final BaseVariantData variantData = variantScope.getVariantData();
        final GradleVariantConfiguration config = variantData.getVariantConfiguration();

        TransformManager transformManager = variantScope.getTransformManager();
        //注册合并混淆文件的任务
        taskFactory.register(new MergeGeneratedProguardFilesCreationAction(variantScope));

        ........
        maybeCreateDesugarTask(
                variantScope, config.getMinSdkVersion(), transformManager, isTestCoverageEnabled);

        AndroidConfig extension = variantScope.getGlobalScope().getExtension();

        // Merge Java Resources.
        createMergeJavaResTask(variantScope);

        // ----- External Transforms -----
        // apply all the external transforms.
        List<Transform> customTransforms = extension.getTransforms();
        List<List<Object>> customTransformsDependencies = extension.getTransformsDependencies();

        for (int i = 0, count = customTransforms.size(); i < count; i++) {
            Transform transform = customTransforms.get(i);

            List<Object> deps = customTransformsDependencies.get(i);
            transformManager.addTransform(
                    taskFactory,
                    variantScope,
                    transform,
                    null,
                    task -> {
                        if (!deps.isEmpty()) {
                            task.dependsOn(deps);
                        }
                    },
                    taskProvider -> {
                        // if the task is a no-op then we make assemble task depend on it.
                        if (transform.getScopes().isEmpty()) {
                            TaskFactoryUtils.dependsOn(
                                    variantScope.getTaskContainer().getAssembleTask(),
                                    taskProvider);
                        }
                    });
        }

        // Add transform to create merged runtime classes if this is a feature, a dynamic-feature,
        // or a base module consuming feature jars. Merged runtime classes are needed if code
        // minification is enabled in a project with features or dynamic-features.
        if (variantData.getType().isFeatureSplit() || variantScope.consumesFeatureJars()) {
            createMergeClassesTransform(variantScope);
        }

        // ----- Android studio profiling transforms
        if (appliesCustomClassTransforms(variantScope, projectOptions)) {
            for (String jar : getAdvancedProfilingTransforms(projectOptions)) {
                if (jar != null) {
                    transformManager.addTransform(
                            taskFactory,
                            variantScope,
                            new CustomClassTransform(
                                    jar,
                                    packagesCustomClassDependencies(variantScope, projectOptions)));
                }
            }
        }

        // ----- Minify next -----
        //只有开启混淆这里才会shrinker不为null
        CodeShrinker shrinker = maybeCreateJavaCodeShrinkerTransform(variantScope);
        if (shrinker == CodeShrinker.R8) {
            maybeCreateResourcesShrinkerTransform(variantScope);
            maybeCreateDexSplitterTransform(variantScope);
            // TODO: create JavaResSplitterTransform and call it here (http://b/77546738)
            return;
        }

        // ----- Multi-Dex support
        DexingType dexingType = variantScope.getDexingType();

        // Upgrade from legacy multi-dex to native multi-dex if possible when using with a device
        if (dexingType == DexingType.LEGACY_MULTIDEX) {
            if (variantScope.getVariantConfiguration().isMultiDexEnabled()
                    && variantScope
                                    .getVariantConfiguration()
                                    .getMinSdkVersionWithTargetDeviceApi()
                                    .getFeatureLevel()
                            >= 21) {
                dexingType = DexingType.NATIVE_MULTIDEX;
            }
        }

        if (variantScope.getNeedsMainDexList()) {
            taskFactory.register(new D8MainDexListTask.CreationAction(variantScope, false));
        }

        if (variantScope.getNeedsMainDexListForBundle()) {
            taskFactory.register(new D8MainDexListTask.CreationAction(variantScope, true));
        }

        createDexTasks(variantScope, dexingType);

        maybeCreateResourcesShrinkerTransform(variantScope);

        // TODO: support DexSplitterTransform when IR enabled (http://b/77585545)
        maybeCreateDexSplitterTransform(variantScope);
        // TODO: create JavaResSplitterTransform and call it here (http://b/77546738)
    }

4.TaskManager#maybeCreateResourcesShrinkerTransform

代码语言:javascript
复制
/**
     * Checks if {@link ShrinkResourcesTransform} should be added to the build pipeline and either
     * adds it or registers a {@link SyncIssue} with the reason why it was skipped.
     */
    protected void maybeCreateResourcesShrinkerTransform(@NonNull VariantScope scope) {
        if (!scope.useResourceShrinker()) {
            return;
        }

        // if resources are shrink, insert a no-op transform per variant output
        // to transform the res package into a stripped res package
        File shrinkerOutput =
                FileUtils.join(
                        globalScope.getIntermediatesDir(),
                        "res_stripped",
                        scope.getVariantConfiguration().getDirName());

        ShrinkResourcesTransform shrinkResTransform =
                new ShrinkResourcesTransform(
                        scope.getVariantData(),
                        scope.getArtifacts()
                                .getFinalArtifactFiles(InternalArtifactType.PROCESSED_RES),
                        shrinkerOutput,
                        logger);

        Optional<TaskProvider<TransformTask>> shrinkTask =
                scope.getTransformManager()
                        .addTransform(
                                taskFactory,
                                scope,
                                shrinkResTransform,
                                taskName ->
                                        scope.getArtifacts()
                                                .appendArtifact(
                                                        InternalArtifactType.SHRUNK_PROCESSED_RES,
                                                        ImmutableList.of(shrinkerOutput),
                                                        taskName),
                                null,
                                null);

        if (!shrinkTask.isPresent()) {
            globalScope
                    .getErrorHandler()
                    .reportError(
                            Type.GENERIC,
                            new EvalIssueException(
                                    "Internal error, could not add the ShrinkResourcesTransform"));
        }

        // And for the bundle
        taskFactory.register(new ShrinkBundleResourcesTask.CreationAction(scope));
    }

这里代码执行之后会生成build/intermediates/res_stripped/release/resources-release-stripped.ap_

重点在于createDexTasks方法

代码语言:javascript
复制
/**
     * Creates tasks used for DEX generation. This will use an incremental pipeline that uses dex
     * archives in order to enable incremental dexing support.
     */
    private void createDexTasks(
            @NonNull VariantScope variantScope, @NonNull DexingType dexingType) {
        TransformManager transformManager = variantScope.getTransformManager();

        DefaultDexOptions dexOptions;
        if (variantScope.getVariantData().getType().isTestComponent()) {
            // Don't use custom dx flags when compiling the test FULL_APK. They can break the test FULL_APK,
            // like --minimal-main-dex.
            dexOptions = DefaultDexOptions.copyOf(extension.getDexOptions());
            dexOptions.setAdditionalParameters(ImmutableList.of());
        } else {
            dexOptions = extension.getDexOptions();
        }

        Java8LangSupport java8SLangSupport = variantScope.getJava8LangSupportType();
        boolean minified = variantScope.getCodeShrinker() != null;
        boolean supportsDesugaring =
                java8SLangSupport == Java8LangSupport.UNUSED
                        || (java8SLangSupport == Java8LangSupport.D8
                                && projectOptions.get(
                                        BooleanOption.ENABLE_DEXING_DESUGARING_ARTIFACT_TRANSFORM));
        boolean enableDexingArtifactTransform =
                globalScope.getProjectOptions().get(BooleanOption.ENABLE_DEXING_ARTIFACT_TRANSFORM)
                        && extension.getTransforms().isEmpty()
                        && !minified
                        && supportsDesugaring
                        && !appliesCustomClassTransforms(variantScope, projectOptions);
        FileCache userLevelCache = getUserDexCache(minified, dexOptions.getPreDexLibraries());
        DexArchiveBuilderTransform preDexTransform =
                new DexArchiveBuilderTransformBuilder()
                        .setAndroidJarClasspath(globalScope.getFilteredBootClasspath())
                        .setDexOptions(dexOptions)
                        .setMessageReceiver(variantScope.getGlobalScope().getMessageReceiver())
                        .setErrorFormatMode(
                                SyncOptions.getErrorFormatMode(
                                        variantScope.getGlobalScope().getProjectOptions()))
                        .setUserLevelCache(userLevelCache)
                        .setMinSdkVersion(
                                variantScope
                                        .getVariantConfiguration()
                                        .getMinSdkVersionWithTargetDeviceApi()
                                        .getFeatureLevel())
                        .setDexer(variantScope.getDexer())
                        .setUseGradleWorkers(
                                projectOptions.get(BooleanOption.ENABLE_GRADLE_WORKERS))
                        .setInBufferSize(projectOptions.get(IntegerOption.DEXING_READ_BUFFER_SIZE))
                        .setOutBufferSize(
                                projectOptions.get(IntegerOption.DEXING_WRITE_BUFFER_SIZE))
                        .setIsDebuggable(
                                variantScope
                                        .getVariantConfiguration()
                                        .getBuildType()
                                        .isDebuggable())
                        .setJava8LangSupportType(java8SLangSupport)
                        .setProjectVariant(getProjectVariantId(variantScope))
                        .setNumberOfBuckets(
                                projectOptions.get(IntegerOption.DEXING_NUMBER_OF_BUCKETS))
                        .setIncludeFeaturesInScope(variantScope.consumesFeatureJars())
                        .setEnableDexingArtifactTransform(enableDexingArtifactTransform)
                        .createDexArchiveBuilderTransform();
        transformManager.addTransform(taskFactory, variantScope, preDexTransform);

        if (projectOptions.get(BooleanOption.ENABLE_DUPLICATE_CLASSES_CHECK)) {
            taskFactory.register(new CheckDuplicateClassesTask.CreationAction(variantScope));
        }

        createDexMergingTasks(variantScope, dexingType, enableDexingArtifactTransform);
    }

5.TaskManager#maybeCreateDexSplitterTransform 这里是只有使用了Multidex 才会走到这里

代码语言:javascript
复制
private void maybeCreateDexSplitterTransform(@NonNull VariantScope variantScope) {
        if (!variantScope.consumesFeatureJars()) {
            return;
        }

        File dexSplitterOutput =
                FileUtils.join(
                        globalScope.getIntermediatesDir(),
                        "dex-splitter",
                        variantScope.getVariantConfiguration().getDirName());
        FileCollection featureJars =
                variantScope.getArtifactFileCollection(METADATA_VALUES, PROJECT, METADATA_CLASSES);
        BuildableArtifact baseJars =
                variantScope
                        .getArtifacts()
                        .getFinalArtifactFiles(
                                InternalArtifactType.MODULE_AND_RUNTIME_DEPS_CLASSES);
        BuildableArtifact mappingFileSrc =
                variantScope.getArtifacts().hasArtifact(InternalArtifactType.APK_MAPPING)
                        ? variantScope
                                .getArtifacts()
                                .getFinalArtifactFiles(InternalArtifactType.APK_MAPPING)
                        : null;
        BuildableArtifact mainDexList =
                variantScope
                        .getArtifacts()
                        .getFinalArtifactFilesIfPresent(
                                InternalArtifactType.MAIN_DEX_LIST_FOR_BUNDLE);

        DexSplitterTransform transform =
                new DexSplitterTransform(
                        dexSplitterOutput, featureJars, baseJars, mappingFileSrc, mainDexList);

        Optional<TaskProvider<TransformTask>> transformTask =
                variantScope
                        .getTransformManager()
                        .addTransform(
                                taskFactory,
                                variantScope,
                                transform,
                                taskName ->
                                        variantScope
                                                .getArtifacts()
                                                .appendArtifact(
                                                        InternalArtifactType.FEATURE_DEX,
                                                        ImmutableList.of(dexSplitterOutput),
                                                        taskName),
                                null,
                                null);

        if (transformTask.isPresent()) {
            publishFeatureDex(variantScope);
        } else {
            globalScope
                    .getErrorHandler()
                    .reportError(
                            Type.GENERIC,
                            new EvalIssueException(
                                    "Internal error, could not add the DexSplitterTransform"));
        }
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-06-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.如何调试Android Gradle源码
  • 二.Gralde Plugin源码分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档