Android Gradle Plugin 源碼分析(一)

本文是根據(jù)gradle3.1.2源碼進(jìn)行分析呀页。Android Gradle Plugin本質(zhì)上是一個(gè)gradle插件妈拌,肯定遵循自定義插件的結(jié)構(gòu),即繼承Plugin類的源碼蓬蝶,resources目錄結(jié)構(gòu)等尘分。為簡(jiǎn)便起見,以下都將Android Gradle Plugin簡(jiǎn)稱為AGP丸氛。

在分析源碼之前培愁,我們需要先下載AGP的源碼。我們?cè)?a target="_blank" rel="nofollow">此鏈接手動(dòng)下載AGP3.1.2的源碼缓窜。

Gradle 3.1.2源碼的大概設(shè)計(jì)

androidGradle.png
  • Extension:定義DSL類
  • Plugin:插件的入口
  • TaskManager:負(fù)責(zé)創(chuàng)建Task定续,本質(zhì)上調(diào)用TaskContainer#create
  • Tasks:具體的任務(wù)類
  • Processor:處理具體的任務(wù)類
  • 工具:真正的執(zhí)行者

分析AppPlugin

我們?cè)趧?chuàng)建一個(gè)Android新項(xiàng)目時(shí),項(xiàng)目模塊的build.gradle文件中的第一行往往都是apply plugin: 'com.android.application'這行代碼禾锤。這行代碼會(huì)調(diào)用com.android.application插件的apply方法私股。

我們打開AGP源碼的resources目錄下的com.android.application.properties文件。其內(nèi)容為implementation-class=com.android.build.gradle.AppPlugin

AGP插件的配置

因此时肿,我們從AppPlugin類的apply方法開始分析庇茫。

apply.png
public class AppPlugin extends BasePlugin<AppExtensionImpl> {
    ...
    @Override
    public void apply(@NonNull Project project) {
        super.apply(project);
    }
}

AppPlugin#apply方法很簡(jiǎn)單港粱,只是調(diào)用父類BasePlugin#apply的方法螃成。我們繼續(xù)查看BasePlugin#apply。

 @Override
    public void apply(@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);

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

        checkConfigureOnDemandGradleVersionCompat();
        checkPathForErrors();
        checkModulesForErrors();

        PluginInitializer.initialize(project);
        ProfilerInitializer.init(project, projectOptions);
        threadRecorder = ThreadRecorder.get();

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

        BuildableArtifactImpl.Companion.disableResolution();
        if (!projectOptions.get(BooleanOption.ENABLE_NEW_DSL_AND_API)) {
            TaskInputHelper.enableBypass();

            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 {
           // 代碼省略
        }
    }

上述代碼中查坪,依次執(zhí)行configureProject寸宏,configureExtension,createTasks方法偿曙。

下面我們將依次分析這三個(gè)方法氮凝。

BasePlugin#configureProject

 private void configureProject() {
        final Gradle gradle = project.getGradle();

        extraModelInfo = new ExtraModelInfo(project.getPath(), projectOptions, project.getLogger());
     // 檢查Gradle版本,如果Gradle版本低于所要求的最低版本望忆,
     // 則拋出異常罩阵。gradle3.1.2要求gradle版本最低為4.4
        checkGradleVersion(project, getLogger(), projectOptions);

        sdkHandler = new SdkHandler(project, getLogger());
    // 省略代碼

        androidBuilder =
                new AndroidBuilder(
                        project == project.getRootProject() ? project.getName() : project.getPath(),
                        creator,
                        new GradleProcessExecutor(project),
                        new GradleJavaProcessExecutor(project),
                        extraModelInfo.getSyncIssueHandler(),
                        extraModelInfo.getMessageReceiver(),
                        getLogger(),
                        isVerbose());
        dataBindingBuilder = new DataBindingBuilder();
        dataBindingBuilder.setPrintMachineReadableOutput(
                SyncOptions.getErrorFormatMode(projectOptions) == ErrorFormatMode.MACHINE_PARSABLE);
        // 檢查是否有被移除的配置選項(xiàng)
        if (projectOptions.hasRemovedOptions()) {
            androidBuilder
                    .getIssueReporter()
                    .reportWarning(Type.GENERIC, projectOptions.getRemovedOptionsErrorMessage());
        }
        // 檢查是否使用被棄用的配置選項(xiàng)
        if (projectOptions.hasDeprecatedOptions()) {
            extraModelInfo
                    .getDeprecationReporter()
                    .reportDeprecatedOptions(projectOptions.getDeprecatedOptions());
        }

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

        project.getTasks()
                .getByName("assemble")
                .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) {
                        TaskInputHelper.enableBypass();
                        BuildableArtifactImpl.Companion.disableResolution();
                    }

                    @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;
                        }
                        sdkHandler.unload();
                        threadRecorder.record(
                                ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
                                project.getPath(),
                                null,
                                () -> {
                                    WorkerActionServiceRegistry.INSTANCE
                                            .shutdownAllRegisteredServices(
                                                    ForkJoinPool.commonPool());
                                    PreDexCache.getCache()
                                            .clear(
                                                    FileUtils.join(
                                                            project.getRootProject().getBuildDir(),
                                                            FD_INTERMEDIATES,
                                                            "dex-cache",
                                                            "cache.xml"),
                                                    getLogger());
                                    Main.clearInternTables();
                                });
                    }
                });

        gradle.getTaskGraph()
                .addTaskExecutionGraphListener(
                        taskGraph -> {
                            TaskInputHelper.disableBypass();
                            Aapt2DaemonManagerService.registerAaptService(
                                    Objects.requireNonNull(androidBuilder.getTargetInfo())
                                            .getBuildTools(),
                                    loggerWrapper,
                                    WorkerActionServiceRegistry.INSTANCE);

                            for (Task task : taskGraph.getAllTasks()) {
                                if (task instanceof TransformTask) {
                                    Transform transform = ((TransformTask) task).getTransform();
                                    if (transform instanceof DexTransform) {
                                        PreDexCache.getCache()
                                                .load(
                                                        FileUtils.join(
                                                                project.getRootProject()
                                                                        .getBuildDir(),
                                                                FD_INTERMEDIATES,
                                                                "dex-cache",
                                                                "cache.xml"));
                                        break;
                                    }
                                }
                            }
                        });

        createLintClasspathConfiguration(project);
    }

從上面代碼可以看出竿秆,該方法前面主要做一些gradle版本檢查,以及配置選項(xiàng)是否被棄用等等稿壁,諸如此類的工作幽钢。

BasePlugin#configureExtension

 private void configureExtension() {
        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 = createSourceSetManager();

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

        ndkHandler =
                new NdkHandler(
                        project.getRootDir(),
                        null, /* compileSkdVersion, this will be set in afterEvaluate */
                        "gcc",
                        "" /*toolchainVersion*/,
                        false /* useUnifiedHeaders */);


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

        GlobalScope globalScope =
                new GlobalScope(
                        project,
                        projectOptions,
                        androidBuilder,
                        extension,
                        sdkHandler,
                        ndkHandler,
                        registry,
                        buildCache);

        variantFactory = createVariantFactory(globalScope, androidBuilder, extension);

        taskManager =
                createTaskManager(
                        globalScope,
                        project,
                        projectOptions,
                        androidBuilder,
                        dataBindingBuilder,
                        extension,
                        sdkHandler,
                        ndkHandler,
                        registry,
                        threadRecorder);

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

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

        // map the whenObjectAdded callbacks on the containers.
        signingConfigContainer.whenObjectAdded(variantManager::addSigningConfig);

        buildTypeContainer.whenObjectAdded(
                buildType -> {
                    SigningConfig signingConfig =
                            signingConfigContainer.findByName(BuilderConstants.DEBUG);
                    buildType.init(signingConfig);
                    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);
    }

該方法主要是創(chuàng)建Extension,并且創(chuàng)建相應(yīng)的TaskManager和VariantManager傅是。AppPlugin對(duì)應(yīng)的Extension是AppExtension匪燕,對(duì)應(yīng)的TaskManager是ApplicationTaskManager。

然后依次添加signingConfig喧笔,buildType和productFlavor帽驯。主要通過調(diào)用Variant Manager的addSigningConfig,addBuildType以及addProductFlavor方法书闸。

BasePlugin#createTasks

private void createTasks() {
        threadRecorder.record(
                ExecutionType.TASK_MANAGER_CREATE_TASKS,
                project.getPath(),
                null,
                () -> taskManager.createTasksBeforeEvaluate());

        project.afterEvaluate(
                project ->
                        threadRecorder.record(
                                ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
                                project.getPath(),
                                null,
                                () -> createAndroidTasks(false)));
    }

BasePlugin#createAndroidTasks

@VisibleForTesting
    final void createAndroidTasks(boolean force) {
        // Make sure unit tests set the required fields.
        checkState(extension.getBuildToolsRevision() != null,
                "buildToolsVersion is not specified.");
        checkState(extension.getCompileSdkVersion() != null, "compileSdkVersion is not specified.");

        ndkHandler.setCompileSdkVersion(extension.getCompileSdkVersion());

        // 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.");
        }

        boolean targetSetupSuccess = ensureTargetSetup();
        sdkHandler.ensurePlatformToolsIsInstalledWarnOnFailure(
                extraModelInfo.getSyncIssueHandler());
        // Stop trying to configure the project if the SDK is not ready.
        // Sync issues will already have been collected at this point in sync.
        if (!targetSetupSuccess) {
            project.getLogger()
                    .warn("Aborting configuration as SDK is missing components in sync mode.");
            return;
        }

        // don't do anything if the project was not initialized.
        // Unless TEST_SDK_DIR is set in which case this is unit tests and we don't return.
        // This is because project don't get evaluated in the unit test setup.
        // See AppPluginDslTest
        if (!force
                && (!project.getState().getExecuted() || project.getState().getFailure() != null)
                && SdkHandler.sTestSdkFolder == null) {
            return;
        }

        if (hasCreatedTasks) {
            return;
        }
        hasCreatedTasks = true;

        extension.disableWrite();

        taskManager.configureCustomLintChecks();

        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);
        }

        // setup SDK repositories.
        sdkHandler.addLocalRepositories(project);

        threadRecorder.record(
                ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS,
                project.getPath(),
                null,
                () -> {
                    variantManager.createAndroidTasks();
                    ApiObjectFactory apiObjectFactory =
                            new ApiObjectFactory(
                                    androidBuilder,
                                    extension,
                                    variantFactory,
                                    project.getObjects());
                    for (VariantScope variantScope : variantManager.getVariantScopes()) {
                        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());

        // Create and read external native build JSON files depending on what's happening right
        // now.
        //
        // CREATE PHASE:
        // Creates JSONs by shelling out to external build system when:
        //   - Any one of AndroidProject.PROPERTY_INVOKED_FROM_IDE,
        //      AndroidProject.PROPERTY_BUILD_MODEL_ONLY_ADVANCED,
        //      AndroidProject.PROPERTY_BUILD_MODEL_ONLY,
        //      AndroidProject.PROPERTY_REFRESH_EXTERNAL_NATIVE_MODEL are set.
        //   - *and* AndroidProject.PROPERTY_REFRESH_EXTERNAL_NATIVE_MODEL is set
        //      or JSON files don't exist or are out-of-date.
        // Create phase may cause ProcessException (from cmake.exe for example)
        //
        // READ PHASE:
        // Reads and deserializes JSONs when:
        //   - Any one of AndroidProject.PROPERTY_INVOKED_FROM_IDE,
        //      AndroidProject.PROPERTY_BUILD_MODEL_ONLY_ADVANCED,
        //      AndroidProject.PROPERTY_BUILD_MODEL_ONLY,
        //      AndroidProject.PROPERTY_REFRESH_EXTERNAL_NATIVE_MODEL are set.
        // Read phase may produce IOException if the file can't be read for standard IO reasons.
        // Read phase may produce JsonSyntaxException in the case that the content of the file is
        // corrupt.
        boolean forceRegeneration =
                projectOptions.get(BooleanOption.IDE_REFRESH_EXTERNAL_NATIVE_MODEL);

        checkSplitConfiguration();
        if (ExternalNativeBuildTaskUtils.shouldRegenerateOutOfDateJsons(projectOptions)) {
            threadRecorder.record(
                    ExecutionType.VARIANT_MANAGER_EXTERNAL_NATIVE_CONFIG_VALUES,
                    project.getPath(),
                    null,
                    () -> {
                        for (VariantScope variantScope : variantManager.getVariantScopes()) {
                            ExternalNativeJsonGenerator generator =
                                    variantScope.getExternalNativeJsonGenerator();
                            if (generator != null) {
                                // This will generate any out-of-date or non-existent JSONs.
                                // When refreshExternalNativeModel() is true it will also
                                // force update all JSONs.
                                generator.build(forceRegeneration);
                            }
                        }
                    });
        }
        BuildableArtifactImpl.Companion.enableResolution();
    }


VariantManager#createAndroidTasks

public void createAndroidTasks() {
        variantFactory.validateModel(this);
        variantFactory.preVariantWork(project);

        if (variantScopes.isEmpty()) {
            recorder.record(
                    ExecutionType.VARIANT_MANAGER_CREATE_VARIANTS,
                    project.getPath(),
                    null /*variantName*/,
                    this::populateVariantDataList);
        }

        // Create top level test tasks.
        recorder.record(
                ExecutionType.VARIANT_MANAGER_CREATE_TESTS_TASKS,
                project.getPath(),
                null /*variantName*/,
                () -> taskManager.createTopLevelTestTasks(!productFlavors.isEmpty()));



        for (final VariantScope variantScope : variantScopes) {
            recorder.record(
                    ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
                    project.getPath(),
                    variantScope.getFullVariantName(),
                    () -> createTasksForVariantData(variantScope));
        }

        taskManager.createReportTasks(variantScopes);
    }

該方法是創(chuàng)建變體和任務(wù)的入口尼变。首先,判斷variantScopes變量是否為空浆劲。variantScopes變量是VariantScope的List享甸。而VariantScope是存放特定變體的數(shù)據(jù)。如果variantScopes為空梳侨,則會(huì)調(diào)用populateVariantDataList方法蛉威。populateVariantDataList方法用于創(chuàng)建所有的變體。現(xiàn)在我們查看一下populateVariantDataList方法如何創(chuàng)建變體的走哺。

VariantManager#populateVariantDataList

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()) {
                androidBuilder
                        .getIssueReporter()
                        .reportError(
                                EvalIssueReporter.Type.UNNAMED_FLAVOR_DIMENSION,
                                "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());
            }
        }
    }

首先蚯嫌,通過extension變量獲得變體的風(fēng)味維度(即flavor dimension),然后丙躏,判斷productFlavors是否為空择示,若為空,則調(diào)用configureDependencies和createVariantDataForProductFlavors方法晒旅。若不為空栅盲,則判斷flavorDimensionList是否為null,若為null废恋,則報(bào)告錯(cuò)誤谈秫。如果你之前升級(jí)過gradle3.0,那么對(duì)這個(gè)報(bào)錯(cuò)信息肯定很熟悉鱼鼓。它提示你拟烫,所有的flavors都必須有一個(gè)維度,即dimension迄本。dimension是Gradle3.0以上新加的特性硕淑。具體的內(nèi)容可以見升級(jí)Gradle3.x文章。

分析完populateVariantDataList方法后,我們繼續(xù)看VariantManager#createAndroidTasks 方法的執(zhí)行過程置媳。主要先后調(diào)用三個(gè)方法于樟,createTopLevelTestTasks,createTasksForVariantData以及createReportTasks方法拇囊。createTopLevelTestTasks主要是用來(lái)創(chuàng)建一些測(cè)試任務(wù)隔披,在這里就不具體分析了,有興趣的可以自行查看源碼寂拆。下面我們主要分析一下createTasksForVariantData方法奢米。

VariantManager#createTasksForVariantData

/** 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();

        final BuildTypeData buildTypeData = buildTypes.get(variantConfig.getBuildType().getName());
        if (buildTypeData.getAssembleTask() == null) {
            buildTypeData.setAssembleTask(taskManager.createAssembleTask(buildTypeData));
        }

        // Add dependency of assemble task on assemble build type task.
        taskManager
                .getTaskFactory()
                .configure(
                        "assemble",
                        task -> {
                            assert buildTypeData.getAssembleTask() != null;
                            task.dependsOn(buildTypeData.getAssembleTask().getName());
                        });

        createAssembleTaskForVariantData(variantData);
        if (variantType.isForTesting()) {
            // 省略代碼
        } else {
            taskManager.createTasksForVariantScope(variantScope);
        }
    }

VariantManager類主要用于創(chuàng)建和管理變體。這個(gè)方法主要作用是創(chuàng)建變體的task纠永。主要是將variantScope參數(shù)傳給TaskManager的createTasksForVariantScope方法鬓长。createTasksForVariantScope方法邏輯很簡(jiǎn)單,在非測(cè)試環(huán)境下尝江,直接調(diào)用TaskManager的createTasksForVariantScope方法涉波。上面我們說(shuō)過,AppPlugin的TaskManger實(shí)現(xiàn)類是ApplicationTaskManager炭序。我們將代碼定位到ApplicationTaskManager類的createTasksForVariantScope方法啤覆。

ApplicationTaskManager#createTasksForVariantScope

@Override
    public void createTasksForVariantScope(@NonNull final VariantScope variantScope) {
        BaseVariantData variantData = variantScope.getVariantData();
        assert variantData instanceof ApplicationVariantData;
        // 這個(gè)方法會(huì)創(chuàng)建preBuild任務(wù)
        createAnchorTasks(variantScope);
        createCheckManifestTask(variantScope);
        // 這個(gè)主要是針對(duì)可穿戴設(shè)備
        // Configure variantData to generate embedded wear application.
        handleMicroApp(variantScope);

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

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

        taskFactory.create(new MainApkListPersistence.ConfigAction(variantScope));
        taskFactory.create(new BuildArtifactReportTask.ConfigAction(variantScope));

        // Add a task to process the manifest(s)
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_MANIFEST_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createMergeApkManifestsTask(variantScope));

        // Add a task to create the res values
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_GENERATE_RES_VALUES_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createGenerateResValuesTask(variantScope));

        // Add a task to compile renderscript files.
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_CREATE_RENDERSCRIPT_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createRenderscriptTask(variantScope));

        // Add a task to merge the resource folders
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_RESOURCES_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                (Recorder.VoidBlock) () -> createMergeResourcesTask(variantScope, true));

        // Add tasks to compile shader
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_SHADER_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createShaderTask(variantScope));


        // Add a task to merge the asset folders
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_ASSETS_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> {
                    createMergeAssetsTask(variantScope);
                });

        // Add a task to create the BuildConfig class
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_BUILD_CONFIG_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createBuildConfigTask(variantScope));

        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_PROCESS_RES_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> {
                    // Add a task to process the Android Resources and generate source files
                    createApkProcessResTask(variantScope);

                    // Add a task to process the java resources
                    createProcessJavaResTask(variantScope);
                });

        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_AIDL_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createAidlTask(variantScope));

        // Add NDK tasks
        if (!isComponentModelPlugin()) {
            recorder.record(
                    ExecutionType.APP_TASK_MANAGER_CREATE_NDK_TASK,
                    project.getPath(),
                    variantScope.getFullVariantName(),
                    () -> createNdkTasks(variantScope));
        } else {
            if (variantData.compileTask != null) {
                variantData.compileTask.dependsOn(getNdkBuildable(variantData));
            } else {
                variantScope.getCompileTask().dependsOn(getNdkBuildable(variantData));
            }
        }
        variantScope.setNdkBuildable(getNdkBuildable(variantData));

        // Add external native build tasks

        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_EXTERNAL_NATIVE_BUILD_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> {
                    createExternalNativeBuildJsonGenerators(variantScope);
                    createExternalNativeBuildTasks(variantScope);
                });

        // Add a task to merge the jni libs folders
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_JNILIBS_FOLDERS_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createMergeJniLibFoldersTasks(variantScope));

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

        // Add a compile task
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_COMPILE_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> addCompileTask(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");
            }

            recorder.record(
                    ExecutionType.APP_TASK_MANAGER_CREATE_SPLIT_TASK,
                    project.getPath(),
                    variantScope.getFullVariantName(),
                    () -> createSplitTasks(variantScope));
        }

        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_PACKAGING_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> {
                    BuildInfoWriterTask buildInfoWriterTask =
                            createInstantRunPackagingTasks(variantScope);
                    createPackagingTask(variantScope, buildInfoWriterTask);
                });

        // create the lint tasks.
        recorder.record(
                ExecutionType.APP_TASK_MANAGER_CREATE_LINT_TASK,
                project.getPath(),
                variantScope.getFullVariantName(),
                () -> createLintTasks(variantScope));
    }

在上述代碼中看到,大部分的任務(wù)都是在createTasksForVariantScope方法里使用taskFactory創(chuàng)建的惭聂。taskFactory是TaskFactory接口的對(duì)象窗声。TaskFactory的實(shí)現(xiàn)類是TaskFactoryImp。

我們運(yùn)行一個(gè)Android工程的assembleRelease任務(wù)辜纲,就可以看到任務(wù)的執(zhí)行順序笨觅,如下所示:

:app:preBuild UP-TO-DATE
:app:preReleaseBuild
:app:compileReleaseAidl
:app:compileReleaseRenderscript
:app:checkReleaseManifest
:app:generateReleaseBuildConfig
:app:prepareLintJar UP-TO-DATE
:app:mainApkListPersistenceRelease
:app:generateReleaseResValues
:app:generateReleaseResources
:app:mergeReleaseResources
:app:createReleaseCompatibleScreenManifests
:app:processReleaseManifest
:app:splitsDiscoveryTaskRelease
:app:processReleaseResources
:app:generateReleaseSources
:app:javaPreCompileRelease
:app:compileReleaseJavaWithJavac
:app:compileReleaseNdk NO-SOURCE
:app:compileReleaseSources
:app:lintVitalRelease
:app:mergeReleaseShaders
:app:compileReleaseShaders
:app:generateReleaseAssets
:app:mergeReleaseAssets
:app:transformClassesWithDexBuilderForRelease
:app:transformDexArchiveWithExternalLibsDexMergerForRelease
:app:transformDexArchiveWithDexMergerForRelease
:app:mergeReleaseJniLibFolders
:app:transformNativeLibsWithMergeJniLibsForRelease
:app:transformNativeLibsWithStripDebugSymbolForRelease
:app:processReleaseJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForRelease
:app:packageRelease
:app:assembleRelease

總結(jié)

本篇文章主要分析了Android Gradle3.1.2插件的源碼大體設(shè)計(jì),以及如何通過apply plugin: 'com.android.application'創(chuàng)建了變體和任務(wù)的耕腾。

在下一篇文章见剩,會(huì)繼續(xù)分析具體Task的執(zhí)行過程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扫俺,一起剝皮案震驚了整個(gè)濱河市苍苞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狼纬,老刑警劉巖羹呵,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異畸颅,居然都是意外死亡担巩,警方通過查閱死者的電腦和手機(jī)方援,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門没炒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事送火∪埃” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵种吸,是天一觀的道長(zhǎng)弃衍。 經(jīng)常有香客問我,道長(zhǎng)坚俗,這世上最難降的妖魔是什么镜盯? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮猖败,結(jié)果婚禮上速缆,老公的妹妹穿的比我還像新娘。我一直安慰自己恩闻,他們只是感情好艺糜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著幢尚,像睡著了一般破停。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尉剩,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天真慢,我揣著相機(jī)與錄音,去河邊找鬼理茎。 笑死晤碘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的功蜓。 我是一名探鬼主播园爷,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼式撼!你這毒婦竟也來(lái)了童社?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤著隆,失蹤者是張志新(化名)和其女友劉穎扰楼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體美浦,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弦赖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浦辨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹬竖。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出币厕,到底是詐尸還是另有隱情列另,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布旦装,位于F島的核電站页衙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏阴绢。R本人自食惡果不足惜店乐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望呻袭。 院中可真熱鬧响巢,春花似錦、人聲如沸棒妨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)券腔。三九已至伏穆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纷纫,已是汗流浹背枕扫。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辱魁,地道東北人烟瞧。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像染簇,于是被迫代替她去往敵國(guó)和親参滴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 本文由玉剛說(shuō)寫作平臺(tái)提供寫作贊助锻弓,版權(quán)歸玉剛說(shuō)微信公眾號(hào)所有原作者:ShinyZeng版權(quán)聲明:未經(jīng)玉剛說(shuō)許可砾赔,不...
    渡過閱讀 10,896評(píng)論 3 30
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,524評(píng)論 25 707
  • 說(shuō)明 本文主要介紹和Gradle關(guān)系密切、相對(duì)不容易理解的配置青灼,偏重概念介紹暴心。部分內(nèi)容是Android特有的(例如...
    jzj1993閱讀 15,577評(píng)論 1 62
  • 學(xué)習(xí)android的同學(xué)都知道android工程從使用android studio開發(fā)以后就使用了[gradle作...
    qndroid閱讀 1,147評(píng)論 0 1
  • 那天专普,朋友約我出去喝咖啡,電話里傳遞出的脆弱和無(wú)助弹沽,讓我立刻意識(shí)到又一個(gè)悲情故事上演了檀夹。 果然筋粗,朋友含淚訴說(shuō),那個(gè)...
    佳人佳語(yǔ)閱讀 553評(píng)論 2 6