apply plugin: 'xxx'到底做了啥

最近在学习自定义Gradle插件,怎么说呢,过程相对曲折,结果相对满意。在涉及到Gradle时也愿意去更多的了解一下,所以这篇文章是看Gradle源码做的记录整理,废话不多说,直入主题。

在application模块的build script中往往第一句就是

apply plugin: 'com.android.application'

在library模块中的build script中第一行是:

apply plugin: 'com.android.library'

我们再引用第三方的一些插件或是我们自定义的插件时,常常也是这一句:

apply plugin:'xxx'

com.android.application插件对应的是com.android.build.gradle.AppPlugin类(以下简称为AppPlugin类),com.android.library插件对应的是com.android.build.gradle.LibraryPlugin类(以下简称为LibraryPlugin类)。

看一下AppPlugin类和LibraryPlugin类的定义。

/** 
 * Gradle plugin class for 'application' projects.  
 */
class AppPlugin extends BasePlugin implements Plugin<Project> {
    @Inject
    public AppPlugin(Instantiator instantiator, ToolingModelBuilderRegistry registry) {
        super(instantiator, registry)
    }

    @Override
    protected Class<? extends BaseExtension> getExtensionClass() {
        return AppExtension.class
    }

    @Override
    protected TaskManager createTaskManager(
            @NonNull Project project,
            @NonNull AndroidBuilder androidBuilder,
            @NonNull DataBindingBuilder dataBindingBuilder,
            @NonNull AndroidConfig extension,
            @NonNull SdkHandler sdkHandler,
            @NonNull NdkHandler ndkHandler,
            @NonNull DependencyManager dependencyManager,
            @NonNull ToolingModelBuilderRegistry toolingRegistry) {
        return new ApplicationTaskManager(
                project,
                androidBuilder,
                dataBindingBuilder,
                extension,
                sdkHandler,
                ndkHandler,
                dependencyManager,
                toolingRegistry)
    }

    @Override
    void apply(Project project) {
        super.apply(project)
    }

    @Override
    protected VariantFactory createVariantFactory() {
        return new ApplicationVariantFactory(instantiator, androidBuilder, extension)
    }
}
/**
 * Gradle plugin class for 'library' projects.
 */
public class LibraryPlugin extends BasePlugin implements Plugin<Project> {

    /**
     * Default assemble task for the default-published artifact. this is needed for
     * the prepare task on the consuming project.
     */
    Task assembleDefault

    @Inject
    public LibraryPlugin(Instantiator instantiator, ToolingModelBuilderRegistry registry) {
        super(instantiator, registry)
    }

    @Override
    public Class<? extends BaseExtension> getExtensionClass() {
        return LibraryExtension.class
    }

    @Override
    protected VariantFactory createVariantFactory() {
        return new LibraryVariantFactory(
                instantiator,
                androidBuilder,
                (LibraryExtension) extension);
    }

    @Override
    protected boolean isLibrary() {
        return true;
    }

    @Override
    protected TaskManager createTaskManager(
            @NonNull Project project,
            @NonNull AndroidBuilder androidBuilder,
            @NonNull DataBindingBuilder dataBindingBuilder,
            @NonNull AndroidConfig extension,
            @NonNull SdkHandler sdkHandler,
            @NonNull NdkHandler ndkHandler,
            @NonNull DependencyManager dependencyManager,
            @NonNull ToolingModelBuilderRegistry toolingRegistry) {
        return new LibraryTaskManager(
                project,
                androidBuilder,
                dataBindingBuilder,
                extension,
                sdkHandler,
                ndkHandler,
                dependencyManager,
                toolingRegistry)
    }

    @Override
    void apply(Project project) {
        super.apply(project)

        assembleDefault = project.tasks.create("assembleDefault")
    }
}
Figure1 Plugin类关系图

AppPlugin和LibraryPlugin都继承自BasePlugin类,BasePlugin类是一个抽象类,所以AppPlugin和LibraryPlugin的类结构是相同的,参考图1。从上面的代码中可以看出,AppPlugin和LibraryPlugin也只是重写了BasePlugin中定义的四个方法(LibraryPlugin还重写了一个isLibrary方法),所以代码都比较简单。

下面开始逐个方法去解析。既然build script中的第一行都是apply plugin 'xxx',那就从apply方法开始。AppPlugin和LibraryPlugin的apply方法中的逻辑都比较简单,大概遵从以下的逻辑。

 @Override
    void apply(Project project) {
        super.apply(project)
        ...
    }

super.apply自然就是执行BasePlugin#apply,移步BasePlugin#apply如下,

  protected void apply(Project project) throws IOException {
        this.project = project;
        
        ...
        
        ThreadRecorder.get().record(...,
                new Recorder.Block<Void>() {
                    @Override
                    public Void call() throws Exception {
                        configureProject();
                        return null;
                    }
                }, ...);

        ThreadRecorder.get().record(...,
                new Recorder.Block<Void>() {
                    @Override
                    public Void call() throws Exception {
                        createExtension();
                        return null;
                    }
                }, ...);

        ThreadRecorder.get().record(...,
                new Recorder.Block<Void>() {
                    @Override
                    public Void call() throws Exception {
                        createTasks();
                        return null;
                    }
                }, ...);
    }

ThreadRecorder实现了Recorder接口,看一下Recorder接口的描述,

/**
 * A {@link ExecutionRecord} recorder for a block execution.
 *
 * A block is some code that produces a result and may throw exceptions.
 */
public interface Recorder {...}

简单地说,Recorder是一个block执行记录,而且注释中还给出了block的解释:block就是一个可能返回数值,可能抛出异常的代码块。
再看一下Recorder#Block类,这是个实现了Callable的抽象类,直接可以理解为一个线程即可,线程中的逻辑才是我们探究的重点。

在移除了一些次重要的代码后,BasePlugin#apply的主要逻辑开始显现出来,如果再将一些代码简化,apply方法逻辑就再直接不过了。

    protected void apply(Project project) throws IOException {
        configureProject();
        createExtension();
        createTasks();
    }

即,apply做的工作如下:

  • 配置project
  • 配置extensions
  • 创建tasks
configureProject做了什么
    
    protected void configureProject() {
        extraModelInfo = new ExtraModelInfo(project, isLibrary());
        
        //检测Gradle版本
        checkGradleVersion();
        //创建一个handler
        sdkHandler = new SdkHandler(project, getLogger());
        //创建AndroidBuilder
        androidBuilder = new AndroidBuilder(
                project == project.getRootProject() ? project.getName() : project.getPath(),
                creator,
                new GradleProcessExecutor(project),
                new GradleJavaProcessExecutor(project),
                extraModelInfo,
                getLogger(),
                isVerbose());
        dataBindingBuilder = new DataBindingBuilder();
        dataBindingBuilder.setPrintMachineReadableOutput(
                extraModelInfo.getErrorFormatMode() ==
                        ExtraModelInfo.ErrorFormatMode.MACHINE_PARSABLE);
                        
        //应用 JavaBasePlugin             
        project.getPlugins().apply(JavaBasePlugin.class);
        //应用 JacocoPlugin
        jacocoPlugin = project.getPlugins().apply(JacocoPlugin.class);
        //描述assemble task
        project.getTasks().getByName("assemble").setDescription(
                "Assembles all variants of all applications and secondary packages.");

        //设置BuildListener监听器
        // 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.
        project.getGradle().addBuildListener(new BuildListener() {
            private final LibraryCache libraryCache = LibraryCache.getCache();

            @Override
            public void buildStarted(Gradle gradle) { }

            @Override
            public void settingsEvaluated(Settings settings) { }

            @Override
            public void projectsLoaded(Gradle gradle) { }

            @Override
            public void projectsEvaluated(Gradle gradle) { }

            @Override
            public void buildFinished(BuildResult buildResult) {
                ExecutorSingleton.shutdown();
                sdkHandler.unload();
                ThreadRecorder.get().record(ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
                        new Recorder.Block() {
                            @Override
                            public Void call() throws Exception {
                                PreDexCache.getCache().clear(
                                        new File(project.getRootProject().getBuildDir(),
                                                FD_INTERMEDIATES + "/dex-cache/cache.xml"),
                                        getLogger());
                                JackConversionCache.getCache().clear(
                                        new File(project.getRootProject().getBuildDir(),
                                                FD_INTERMEDIATES + "/jack-cache/cache.xml"),
                                        getLogger());
                                libraryCache.unload();
                                Main.clearInternTables();
                                return null;
                            }
                        }, new Recorder.Property("project", project.getName()));

                try {
                    ProcessRecorderFactory.shutdown();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        
        //设置TaskExecutionGraphListener,监听任务图(task graph)配置完成
        project.getGradle().getTaskGraph().addTaskExecutionGraphListener(
                new TaskExecutionGraphListener() {
                    @Override
                    public void graphPopulated(TaskExecutionGraph taskGraph) {
                        for (Task task : taskGraph.getAllTasks()) {
                            if (task instanceof TransformTask) {
                                if (((TransformTask) task).getTransform() instanceof DexTransform) {
                                    PreDexCache.getCache().load(
                                            new File(project.getRootProject().getBuildDir(),
                                                    FD_INTERMEDIATES + "/dex-cache/cache.xml"));
                                    break;
                                }
                            } else if (task instanceof JillTask) {
                                JackConversionCache.getCache().load(
                                        new File(project.getRootProject().getBuildDir(),
                                                FD_INTERMEDIATES + "/jack-cache/cache.xml"));
                                break;
                            }
                        }
                    }
                });
    }

我在configureProject代码中做了一些必要的注释。且尚不管其中的元素发挥的作用。我们可以发现其中的逻辑还是很简单的:

  1. 检测了Gradle版本;
  2. 初始化了三个变量sdkHandler、androidBuilder、dataBindingBuilder;
  3. 应用了两个插件JavaBasePlugin、JacocoPlugin;
  4. 添加了两个对Gradle生命周期监听的监听器BuildListener、TaskExecutionGraphListener;

DONE!完了。

createExtension做了什么
    private void createExtension() {
        //创建buildTypeContainer
        final NamedDomainObjectContainer<BuildType> buildTypeContainer = project.container(
                BuildType.class,
                new BuildTypeFactory(instantiator, project, project.getLogger()));
        
        //创建productFlavorContainer      
        final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer = project.container(
                ProductFlavor.class,
                new ProductFlavorFactory(instantiator, project, project.getLogger(), extraModelInfo));
                
        //创建signingConfigContainer      
        final NamedDomainObjectContainer<SigningConfig>  signingConfigContainer = project.container(
                SigningConfig.class,
                new SigningConfigFactory(instantiator));

        //build script中的android块 
        extension = project.getExtensions().create("android", getExtensionClass(),
                project, instantiator, androidBuilder, sdkHandler,
                buildTypeContainer, productFlavorContainer, signingConfigContainer,
                extraModelInfo, isLibrary());

        //有疑问       
        // create the default mapping configuration.
        project.getConfigurations().create("default-mapping")
                .setDescription("Configuration for default mapping artifacts.");
        project.getConfigurations().create("default-metadata")
                .setDescription("Metadata for the produced APKs.");

        //创建依赖管理器
        DependencyManager dependencyManager = new DependencyManager(project, extraModelInfo);
        
        //创建与NDK有关系的ndkHandler
        ndkHandler = new NdkHandler(
                project.getRootDir(),
                null, /* compileSkdVersion, this will be set in afterEvaluate */
                "gcc",
                "" /*toolchainVersion*/);

        //创建任务管理器
        taskManager = createTaskManager(
                project,
                androidBuilder,
                dataBindingBuilder,
                extension,
                sdkHandler,
                ndkHandler,
                dependencyManager,
                registry);

        //创建variantFactory及variantManager
        variantFactory = createVariantFactory();
        variantManager = new VariantManager(
                project,
                androidBuilder,
                extension,
                variantFactory,
                taskManager,
                instantiator);

        // Register a builder for the custom tooling model
        ModelBuilder modelBuilder = new ModelBuilder(
                androidBuilder,
                variantManager,
                taskManager,
                extension,
                extraModelInfo,
                ndkHandler,
                new NativeLibraryFactoryImpl(ndkHandler),
                isLibrary(),
                AndroidProject.GENERATION_ORIGINAL);
        registry.register(modelBuilder);

        /* signingConfigContainer, buildTypeContainer, productFlavorContainer容器中添加元素时的回调 */
        // map the whenObjectAdded callbacks on the containers.
        signingConfigContainer.whenObjectAdded(new Action<SigningConfig>() {
            @Override
            public void execute(SigningConfig signingConfig) {
                variantManager.addSigningConfig(signingConfig);
            }
        });


        buildTypeContainer.whenObjectAdded(new Action<BuildType>() {
            @Override
            public void execute(BuildType buildType) {
            SigningConfig signingConfig = signingConfigContainer.findByName(BuilderConstants.DEBUG);
            buildType.init(signingConfig);
            variantManager.addBuildType(buildType);
            }
        });

        productFlavorContainer.whenObjectAdded(new Action<ProductFlavor>() {
            @Override
            public void execute(ProductFlavor productFlavor) {
                variantManager.addProductFlavor(productFlavor);
            }
        });

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

createExtension方法看着挺长,可是仔细再看,发现里面的元素不都是build script中经常见到的代码块么:buildType、productFlavor、signingConfig。其他的诸如taskManager与task有关,variantFactory、variantManager应该与构建变体有关。

其中涉及到一些类,做一下说明,

  • NamedDomainObjectContainer
    从代码中也能推测出这是一种容器。看一下源代码中的注释,可知NamedDomainObjectContainer是SortedSet的子类,所以,保持了Set容器的一些特点。

Note that a container is an implementation of {@link java.util.SortedSet}, which means that the container is guaranteed to only contain elements with unique names within this container. Furthermore, items are ordered by their name.

  • extension
    extension = project.getExtensions().create("android",...),这个自然就是build script中的 android{...}块。
android{
    defaultConfig{
        ...
    }
    ...
}

两个管理器类

  • DependencyManager
    解析依赖配置的管理器

  • TaskManager
    任务管理器,主要是在创建任务使用。

  • VariantFactory
    createVariantFactory方法返回类型,该方法是一个抽象方法,在AppPlugin和LibraryPlugin中分别有着具体的实现。

  • signingConfigContainer,buildTypeContainer,productFlavorContainer容器中添加元素时回调。可以看到回调中都调用variantManager.addXxx,也正印证signingConfig、buildType、productFlavor都可以成为构建变体的组成部分。

createTasks做了什么
    private void createTasks() {
        
        taskManager.createTasksBeforeEvaluate(new TaskContainerAdaptor(project.getTasks()));
                       
        project.afterEvaluate(new Action<Project>() {
            @Override
            public void execute(Project project) {
                createAndroidTasks(false); 
            }
        });
    }

顾名思义,createTasks方法就是用来创建任务。可以看到该方法中主要涉及beforeEvaluate、afterEvaluate两个阶段的方法调用。AndroidTask 是依赖配置项的配置才能生成相应任务,所以是需要在 afterEvaluate 之后创建。所以,重点查看 afterEvaluate 阶段的 createAndroidTasks方法。

VariantManager#createAndroidTasks

public void createAndroidTasks() {
        
        ...
        //variantDataList 构建变体数据集。variantDataList为空,则进行填充
        ...
        if (variantDataList.isEmpty()) {
              //variantDataList具体填充逻辑
              populateVariantDataList();              
        }

        // Create top level test tasks.    
        taskManager.createTopLevelTestTasks(tasks, !productFlavors.isEmpty());
        
        for (final BaseVariantData<? extends BaseVariantOutputData> variantData : variantDataList) {   
            ...
            createTasksForVariantData(tasks, variantData);     
            ...              
        }
        taskManager.createReportTasks(variantDataList);
    }

createAndroidTasks做了代码简化,只保留了主干。代码注释也很明了,就不再赘述。如果variantDataList为空,就以build script中的buildType, productFlavor等为原料去填充variantDataList。直接移步populateVariantDataList逻辑。

VariantManager#populateVariantDataList

/**
     * Create all variants. 创建所有的构建变体
     */
    public void populateVariantDataList() {
        //productFlavors类型为Map<String, ProductFlavorData<CoreProductFlavor>>
        if (productFlavors.isEmpty()) {
            createVariantDataForProductFlavors(Collections.<ProductFlavor>emptyList());
        }           
        else {
            ...
        }
    }

查看productFlavors中有无元素,若没有元素,则填充productFlavorsList。移步VariantManager#createVariantDataForProductFlavors

private void createVariantDataForProductFlavors(
            @NonNull List<ProductFlavor> productFlavorList) {

        BuildTypeData testBuildTypeData = null;
        ...

        BaseVariantData variantForAndroidTest = null;
        //获取过滤变体
        Action<com.android.build.gradle.api.VariantFilter> variantFilterAction =
                extension.getVariantFilter();

        //遍历buildType
        for (BuildTypeData buildTypeData : buildTypes.values()) {
            boolean ignore = false;
            
            //过滤变体
            if (variantFilterAction != null) {
                ...
                ignore = variantFilter.isIgnore();
            }

        
            //此时ignore == true,跳过if判断
            if (!ignore) {
                /* 一个buildType + productFlavorList 创建variantData,添加到variantDataList */
                BaseVariantData<?> variantData = createVariantData(
                        buildTypeData.getBuildType(),
                        productFlavorList);
                variantDataList.add(variantData);

                GradleVariantConfiguration variantConfig = variantData.getVariantConfiguration();
                ...
                
                //存在Gradle测试代码
                if (variantFactory.hasTestScope()) {
                    TestVariantData unitTestVariantData = createTestVariantData(
                            variantData,
                            UNIT_TEST);
                    variantDataList.add(unitTestVariantData);
                    ...
                }
            }
        }
            
        if (variantForAndroidTest != null) {
            TestVariantData androidTestVariantData = createTestVariantData(
                    variantForAndroidTest,
                    ANDROID_TEST);
            variantDataList.add(androidTestVariantData);
        }
    }

在createVariantDataForProductFlavors方法中,会遍历buildType,每一种buildType再与productFlavorList中的每一种productFlavor组合成为构建变体。这个过程在下面的createVariantData方法中实现。注意createVariantData返回BaseVariantData类型的对象,添加到variantDataList中。variantDataList是VariantManager的一个全局变量。

Gradle 会为配置的productFlavor与buildType的每个可能的组合创建构建变体。不过,某些特定的构建变体在项目环境中可能并不必要,也可能没有意义。所以,在模块级build.gradle文件中创建一个变体过滤器,以移除某些构建变体配置。所以,createVariantDataForProductFlavors方法中还对可能存在的过滤变体进行处理。以下是AndroidDeveloper文档中给出的一段示例代码,过滤掉组合“minApi21”和“demo”产品风格的所有构建变体配置。

variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }

VariantManager#createVariantData

     /**
     * 给定一个buildType,一个集合ProductFlavor集合。
     * 创建由该buildType和每一个ProductFlavor的构建变体
     * Create a VariantData for a specific combination of BuildType and ProductFlavor list.
     */
    public BaseVariantData<? extends BaseVariantOutputData> createVariantData(
            @NonNull com.android.builder.model.BuildType buildType,
            @NonNull List<? extends ProductFlavor> productFlavorList) {
        BuildTypeData buildTypeData = buildTypes.get(buildType.getName());

        GradleVariantConfiguration variantConfig = new GradleVariantConfiguration(
                defaultConfigData.getProductFlavor(),
                defaultConfigData.getSourceSet(),
                buildTypeData.getBuildType(),
                buildTypeData.getSourceSet(),
                variantFactory.getVariantConfigurationType(),
                signingOverride);

        ...

        // sourceSetContainer in case we are creating variant specific sourceSets.
        NamedDomainObjectContainer<AndroidSourceSet> sourceSetsContainer = extension
                .getSourceSets();

        // We must first add the flavors to the variant config, in order to get the proper
        // variant-specific and multi-flavor name as we add/create the variant providers later.
        for (ProductFlavor productFlavor : productFlavorList) {
            ProductFlavorData<CoreProductFlavor> data = productFlavors.get(
                    productFlavor.getName());

            String dimensionName = productFlavor.getDimension();
            if (dimensionName == null) {
                dimensionName = "";
            }

            //
            variantConfig.addProductFlavor(
                    data.getProductFlavor(),
                    data.getSourceSet(),
                    dimensionName);
        }

        createCompoundSourceSets(productFlavorList, variantConfig, sourceSetsContainer);
        ...
        
        // Done. Create the variant and get its internal storage object.
        /* core 
           createVariantData为VariantFactory接口中方法,具体实现在ApplicationVariantFactory,
           LibraryVariantFactory
    
        */
        BaseVariantData<?> variantData =
                variantFactory.createVariantData(variantConfig, taskManager);

        final VariantDependencies variantDep = VariantDependencies.compute(
                project, variantConfig.getFullName(),
                isVariantPublished(),
                variantData.getType(),
                null,
                variantProviders.toArray(new ConfigurationProvider[variantProviders.size()]));
        variantData.setVariantDependency(variantDep);

        ...

        return variantData;
    }

variantFactory.createVariantData是接口方法,在ApplicationVariantFactory、LibraryVariantFactory有相应的具体实现。分别看一下具体实现。

ApplicationVariantFactory#createVariantData

@Override
    @NonNull
    public BaseVariantData createVariantData(
            @NonNull GradleVariantConfiguration variantConfiguration,
            @NonNull TaskManager taskManager) {
        ApplicationVariantData variant =
                new ApplicationVariantData(extension, variantConfiguration, taskManager,
                        androidBuilder.getErrorReporter());

        variant.calculateFilters(extension.getSplits());

        Set<String> densities = variant.getFilters(OutputFile.FilterType.DENSITY);
        Set<String> abis = variant.getFilters(OutputFile.FilterType.ABI);

        if (!densities.isEmpty()) {
            variant.setCompatibleScreens(extension.getSplits().getDensity()
                    .getCompatibleScreens());
        }

        // create its outputs
        if (variant.getSplitHandlingPolicy() ==
                BaseVariantData.SplitHandlingPolicy.PRE_21_POLICY) {

            // Always dd an entry with no filter for universal and add it FIRST,
            // since code assume that the first variant output will be the universal one.
            List<String> orderedDensities = new ArrayList<String>();
            orderedDensities.add(NO_FILTER);
            orderedDensities.addAll(densities);

            List<String> orderedAbis = new ArrayList<String>();
            // if the abi list is empty or we must generate a universal apk, add a NO_FILTER
            if (abis.isEmpty() || (extension.getSplits().getAbi().isEnable() &&
                    extension.getSplits().getAbi().isUniversalApk())) {
                orderedAbis.add(NO_FILTER);
            }
            orderedAbis.addAll(abis);

            // create its outputs
            for (String density : orderedDensities) {
                for (String abi : orderedAbis) {
                    ImmutableList.Builder<FilterData> builder = ImmutableList.builder();
                    if (density != null) {
                        builder.add(FilterDataImpl.build(OutputFile.DENSITY, density));
                    }
                    if (abi != null) {
                        builder.add(FilterDataImpl.build(OutputFile.ABI, abi));
                    }
                    variant.createOutput(
                            OutputFile.OutputType.FULL_SPLIT,
                            builder.build());
                }
            }
        } else {
            variant.createOutput(OutputFile.OutputType.MAIN,
                    Collections.<FilterData>emptyList());
        }

        return variant;
    }

ApplicationVariantFactory#createVariantData方法中最显眼也是最熟悉的的两个Set<String>类型的对象:densities、abis。针对不同的 ABI(应用程序二进制接口)或(density)屏幕密度,可以构建多个 APK。通常做法是在android块中。

android{
  splits {
      // Configures multiple APKs based on screen density.
      density {
         ...
      }

      abi{
         ...
      }
   }
}

这样在创建variant过程中,会同时结合每一种配置的density、abi,这就是ApplicationVariantFactory#createVariantData方法的主要功能。

LibraryVariantFactory#createVariantData

  @Override
    @NonNull
    public BaseVariantData createVariantData(
            @NonNull GradleVariantConfiguration variantConfiguration,
            @NonNull TaskManager taskManager) {
        return new LibraryVariantData(extension, taskManager, variantConfiguration,
                androidBuilder.getErrorReporter());
    }

LibraryVariantFactory#createVariantData就更简单了,直接返回一个新建的LibraryVariantData对象。

以上是VariantManager#populateVariantDataList中if块,接着看else块中的逻辑

public void populateVariantDataList() {
        //productFlavors类型为Map<String, ProductFlavorData<CoreProductFlavor>>
        if (productFlavors.isEmpty()) {
          ...
        } 
        
        else {
            List<String> flavorDimensionList = extension.getFlavorDimensionList();

            // Create iterable to get GradleProductFlavor from ProductFlavorData.
            Iterable<CoreProductFlavor> flavorDsl =
                    Iterables.transform(
                            productFlavors.values(),
                            new Function<ProductFlavorData<CoreProductFlavor>, CoreProductFlavor>() {
                                @Override
                                public CoreProductFlavor apply(
                                        ProductFlavorData<CoreProductFlavor> data) {
                                    return data.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());
            }
        }
    }

如果productFlavors不为空,就获取所有产品口味组合的列表flavorComboList ,然后遍历flavorComboList ,继续调用VariantManager#createVariantDataForProductFlavors,后面逻辑就一样了。populateVariantDataList方法调用到此结束。接着看VariantManager#createAndroidTasks下面的逻辑,

public void createAndroidTasks() {
        ... 
        //variantDataList具体填充逻辑
        populateVariantDataList();
        ...
        //Create top level test tasks. 创建顶级测试任务
        taskManager.createTopLevelTestTasks(tasks, ...)
        ...
        createTasksForVariantData(tasks, variantData);
        ...                   
        taskManager.createReportTasks(variantDataList);
}

taskManager#createTopLevelTestTasks
根据注释知道,这个方法是创建顶级测试任务,这个方法略去。直接看VariantManager#createTasksForVariantData

/**
     * Create tasks for the specified variantData.
       为具体的构建变体创建相关的tasks
     */
    public void createTasksForVariantData(
            final TaskFactory tasks,
            final BaseVariantData<? extends BaseVariantOutputData> variantData) {

        // assemble task用于组合项目中的所有输出。添加assemble task对build type task依赖
        // Add dependency of assemble task on assemble build type task.
        tasks.named("assemble", new Action<Task>() {
            @Override
            public void execute(Task task) {
                BuildTypeData buildTypeData = buildTypes.get(
                                variantData.getVariantConfiguration().getBuildType().getName());
                task.dependsOn(buildTypeData.getAssembleTask());
            }
        });


        VariantType variantType = variantData.getType();

        createAssembleTaskForVariantData(tasks, variantData);
        //for test, 先忽略测试部分逻辑
        if (variantType.isForTesting()) {
            ...
        } else {
            taskManager.createTasksForVariantData(tasks, variantData);
        }
    }

assemble task用于组合项目中的所有输出。createTasksForVariantData方法中,首先添加assemble task对buildType assemble task依赖。之后调用

VariantManager#createAssembleTaskForVariantData。

/**
     * Create assemble task for VariantData.
     * 为VariantData创建assemble task
     *
     * 为buildTypeAssembleTask, productFlavorAssembleTask 添加依赖
     */
    private void createAssembleTaskForVariantData(
            TaskFactory tasks,
            final BaseVariantData<?> variantData) {
        
        //测试variantType     
        if (variantData.getType().isForTesting()) {
            variantData.assembleVariantTask = taskManager.createAssembleTask(tasks, variantData);
        } 
        //非测试variantType
        else {
            BuildTypeData buildTypeData =
                    buildTypes.get(variantData.getVariantConfiguration().getBuildType().getName());

            //productFlavors块没有配置       
            if (productFlavors.isEmpty()) {
                // Reuse assemble task for build type if there is no product flavor.
                variantData.assembleVariantTask = buildTypeData.getAssembleTask();
            } else {
                variantData.assembleVariantTask = taskManager.createAssembleTask(tasks, variantData);

                //设置builtType assembleTask 依赖 variantData assemble task
                // setup the task dependencies
                // build type
                buildTypeData.getAssembleTask().dependsOn(variantData.assembleVariantTask);

                //设置各productFlavor assemble task 依赖 variantData assemble task
                // each flavor
                GradleVariantConfiguration variantConfig = variantData.getVariantConfiguration();
                for (CoreProductFlavor flavor : variantConfig.getProductFlavors()) {
                    productFlavors.get(flavor.getName()).getAssembleTask()
                             .dependsOn(variantData.assembleVariantTask);
                }

                //variantConfig.getProductFlavors返回的集合中是否有遗漏,如有遗漏,需要创建相关task,
                //并设置依赖
                // assembleTask for this flavor(dimension), created on demand if needed.
                if (variantConfig.getProductFlavors().size() > 1) {
                    final String name = StringHelper.capitalize(variantConfig.getFlavorName());
                    final String variantAssembleTaskName = "assemble" + name;
                    if (!tasks.containsKey(variantAssembleTaskName)) {
                        tasks.create(variantAssembleTaskName, new Action<Task>() {
                            @Override
                            public void execute(Task task) {
                                task.setDescription(
                                        "Assembles all builds for flavor combination: " + name);
                                task.setGroup("Build");
                                task.dependsOn(variantData.assembleVariantTask);

                            }
                        });
                    }
                    tasks.named("assemble", new Action<Task>() {
                        @Override
                        public void execute(Task task) {
                            task.dependsOn(variantAssembleTaskName);
                        }
                    });
                }
            }
        }
    }

createAssembleTaskForVariantData逻辑也比较简单,为buildType、productFlavor的 assembleTask添加对variantData.assembleVariantTask的依赖。
继续看createTasksForVariantData中的逻辑。

taskManager#createTasksForVariantData

    //上个方法的名字叫createAssembleTask,其中内容是在做跟assemble task有关的操作。
    //这个方法叫createTasks,其中逻辑自然就是创建各种task了,从方法名就可以知道。
     @Override
    public void createTasksForVariantData(
            @NonNull final TaskFactory tasks,
            @NonNull final BaseVariantData<? extends BaseVariantOutputData> variantData) {
        assert variantData instanceof ApplicationVariantData;

        final VariantScope variantScope = variantData.getScope();

        createAnchorTasks(tasks, variantScope);
        
        //创建CheckManifestTask
        createCheckManifestTask(tasks, variantScope);
        ...

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

        // Add a task to process the manifest(s)
        ...
        createMergeAppManifestsTask(tasks, variantScope);
                      

        // Add a task to create the res values
        ...
        createGenerateResValuesTask(tasks, variantScope);
          

        // Add a task to compile renderscript files.
        ...
        createRenderscriptTask(tasks, variantScope);
                  
               

        // Add a task to merge the resource folders
        ...
        createMergeResourcesTask(tasks, variantScope);
              
        // Add a task to merge the asset folders
        createMergeAssetsTask(tasks, variantScope);
          
        ...
        // Add a task to create the BuildConfig class
        createBuildConfigTask(tasks, variantScope);
                       
        ...
        // Add a task to process the Android Resources and generate source files
        createApkProcessResTask(tasks, variantScope);

       
        createAidlTask(tasks, variantScope);
                      

        
        createShaderTask(tasks, variantScope);
                       

        // Add NDK tasks
        createNdkTasks(variantScope);
      
        variantScope.setNdkBuildable(getNdkBuildable(variantData));

        // Add a task to merge the jni libs folders
        createMergeJniLibFoldersTasks(tasks, variantScope);
                      
        // Add a compile task
        AndroidTask<? extends JavaCompile> javacTask =
                        createJavacTask(tasks, variantScope);
        ...
        if (variantData.getVariantConfiguration().getUseJack()) {
            createJackTask(tasks, variantScope);
        } 
              
        // Add data binding tasks if enabled
        if (extension.getDataBinding().isEnabled()) {
            createDataBindingTasks(tasks, variantScope);
        }

        if (variantData.getSplitHandlingPolicy().equals(
                BaseVariantData.SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY)) {
            
            createSplitTasks(tasks, variantScope);
                       
        }

       
        AndroidTask<InstantRunWrapperTask> fullBuildInfoGeneratorTask
                    = createInstantRunPackagingTasks(tasks, variantScope);
                    
        createPackagingTask(tasks, variantScope, true /*publishApk*/,
                    fullBuildInfoGeneratorTask);
                      
        // create the lint tasks.
        createLintTasks(tasks, variantScope);
                     
    }

至此,VariantManager#createAndroidTasks大体逻辑已经走完。BasePlugin#apply逻辑也已完成。

后记 (仍存有的疑问)

createExtension方法中创建两个配置块的default-mapping、default-metadata都未接触过,所以这里存在一些疑问。有知道的同学希望能不吝赐教。

 // create the default mapping configuration.
        project.getConfigurations().create("default-mapping")
                .setDescription("Configuration for default mapping artifacts.");
        project.getConfigurations().create("default-metadata")
                .setDescription("Metadata for the produced APKs.");

还有就是在源码中存在这一部分,这里提到一个Jack compiler,也是第一次听,专门去查了下,这里有一篇关于Jack编译器的博客,感兴趣的可以看看。

 if (variantConfig.getType() == LIBRARY && variantConfig.getUseJack()) {
            project.getLogger().warn(
                    "{}, {}: Jack compiler is not supported in library projects, falling back to javac.",
                    project.getPath(),
                    variantConfig.getFullName());
        }

Jack compiler
http://taobaofed.org/blog/2016/05/05/new-compiler-for-android/

本文只是简单的跟了一下流程,其中很多细节都忽略了,在以后的学习过程中逐渐加深理解吧,文章在作者对Gradle相关有新的认知后会继续做出更改,感谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容