apply plugin: 'xxx'到底做了啥

最近在學(xué)習(xí)自定義Gradle插件,怎么說(shuō)呢,過(guò)程相對(duì)曲折,結(jié)果相對(duì)滿意。在涉及到Gradle時(shí)也愿意去更多的了解一下,所以這篇文章是看Gradle源碼做的記錄整理,廢話不多說(shuō),直入主題。

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

apply plugin: 'com.android.application'

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

apply plugin: 'com.android.library'

我們?cè)僖玫谌降囊恍┎寮蚴俏覀冏远x的插件時(shí),常常也是這一句:

apply plugin:'xxx'

com.android.application插件對(duì)應(yīng)的是com.android.build.gradle.AppPlugin類(以下簡(jiǎn)稱為AppPlugin類),com.android.library插件對(duì)應(yīng)的是com.android.build.gradle.LibraryPlugin類(以下簡(jiǎn)稱為L(zhǎng)ibraryPlugin類)。

看一下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類關(guān)系圖

AppPlugin和LibraryPlugin都繼承自BasePlugin類,BasePlugin類是一個(gè)抽象類,所以AppPlugin和LibraryPlugin的類結(jié)構(gòu)是相同的,參考圖1。從上面的代碼中可以看出,AppPlugin和LibraryPlugin也只是重寫了BasePlugin中定義的四個(gè)方法(LibraryPlugin還重寫了一個(gè)isLibrary方法),所以代碼都比較簡(jiǎn)單。

下面開始逐個(gè)方法去解析。既然build script中的第一行都是apply plugin 'xxx',那就從apply方法開始。AppPlugin和LibraryPlugin的apply方法中的邏輯都比較簡(jiǎn)單,大概遵從以下的邏輯。

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

super.apply自然就是執(zhí)行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實(shí)現(xiàn)了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 {...}

簡(jiǎn)單地說(shuō),Recorder是一個(gè)block執(zhí)行記錄,而且注釋中還給出了block的解釋:block就是一個(gè)可能返回?cái)?shù)值,可能拋出異常的代碼塊。
再看一下Recorder#Block類,這是個(gè)實(shí)現(xiàn)了Callable的抽象類,直接可以理解為一個(gè)線程即可,線程中的邏輯才是我們探究的重點(diǎn)。

在移除了一些次重要的代碼后,BasePlugin#apply的主要邏輯開始顯現(xiàn)出來(lái),如果再將一些代碼簡(jiǎn)化,apply方法邏輯就再直接不過(guò)了。

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

即,apply做的工作如下:

  • 配置project
  • 配置extensions
  • 創(chuàng)建tasks
configureProject做了什么
    
    protected void configureProject() {
        extraModelInfo = new ExtraModelInfo(project, isLibrary());
        
        //檢測(cè)Gradle版本
        checkGradleVersion();
        //創(chuàng)建一個(gè)handler
        sdkHandler = new SdkHandler(project, getLogger());
        //創(chuàng)建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);
                        
        //應(yīng)用 JavaBasePlugin             
        project.getPlugins().apply(JavaBasePlugin.class);
        //應(yīng)用 JacocoPlugin
        jacocoPlugin = project.getPlugins().apply(JacocoPlugin.class);
        //描述assemble task
        project.getTasks().getByName("assemble").setDescription(
                "Assembles all variants of all applications and secondary packages.");

        //設(shè)置BuildListener監(jiān)聽(tīng)器
        // 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);
                }
            }
        });
        
        //設(shè)置TaskExecutionGraphListener,監(jiān)聽(tīng)任務(wù)圖(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代碼中做了一些必要的注釋。且尚不管其中的元素發(fā)揮的作用。我們可以發(fā)現(xiàn)其中的邏輯還是很簡(jiǎn)單的:

  1. 檢測(cè)了Gradle版本;
  2. 初始化了三個(gè)變量sdkHandler、androidBuilder、dataBindingBuilder;
  3. 應(yīng)用了兩個(gè)插件JavaBasePlugin、JacocoPlugin;
  4. 添加了兩個(gè)對(duì)Gradle生命周期監(jiān)聽(tīng)的監(jiān)聽(tīng)器BuildListener、TaskExecutionGraphListener;

DONE!完了。

createExtension做了什么
    private void createExtension() {
        //創(chuàng)建buildTypeContainer
        final NamedDomainObjectContainer<BuildType> buildTypeContainer = project.container(
                BuildType.class,
                new BuildTypeFactory(instantiator, project, project.getLogger()));
        
        //創(chuàng)建productFlavorContainer      
        final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer = project.container(
                ProductFlavor.class,
                new ProductFlavorFactory(instantiator, project, project.getLogger(), extraModelInfo));
                
        //創(chuàng)建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());

        //有疑問(wèn)       
        // 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.");

        //創(chuàng)建依賴管理器
        DependencyManager dependencyManager = new DependencyManager(project, extraModelInfo);
        
        //創(chuàng)建與NDK有關(guān)系的ndkHandler
        ndkHandler = new NdkHandler(
                project.getRootDir(),
                null, /* compileSkdVersion, this will be set in afterEvaluate */
                "gcc",
                "" /*toolchainVersion*/);

        //創(chuàng)建任務(wù)管理器
        taskManager = createTaskManager(
                project,
                androidBuilder,
                dataBindingBuilder,
                extension,
                sdkHandler,
                ndkHandler,
                dependencyManager,
                registry);

        //創(chuàng)建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容器中添加元素時(shí)的回調(diào) */
        // 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方法看著挺長(zhǎng),可是仔細(xì)再看,發(fā)現(xiàn)里面的元素不都是build script中經(jīng)常見(jiàn)到的代碼塊么:buildType、productFlavor、signingConfig。其他的諸如taskManager與task有關(guān),variantFactory、variantManager應(yīng)該與構(gòu)建變體有關(guān)。

其中涉及到一些類,做一下說(shuō)明,

  • NamedDomainObjectContainer
    從代碼中也能推測(cè)出這是一種容器。看一下源代碼中的注釋,可知NamedDomainObjectContainer是SortedSet的子類,所以,保持了Set容器的一些特點(diǎn)。

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",...),這個(gè)自然就是build script中的 android{...}塊。
android{
    defaultConfig{
        ...
    }
    ...
}

兩個(gè)管理器類

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

  • TaskManager
    任務(wù)管理器,主要是在創(chuàng)建任務(wù)使用。

  • VariantFactory
    createVariantFactory方法返回類型,該方法是一個(gè)抽象方法,在AppPlugin和LibraryPlugin中分別有著具體的實(shí)現(xiàn)。

  • signingConfigContainer,buildTypeContainer,productFlavorContainer容器中添加元素時(shí)回調(diào)??梢钥吹交卣{(diào)中都調(diào)用variantManager.addXxx,也正印證signingConfig、buildType、productFlavor都可以成為構(gòu)建變體的組成部分。

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

顧名思義,createTasks方法就是用來(lái)創(chuàng)建任務(wù)??梢钥吹皆摲椒ㄖ兄饕婕癰eforeEvaluate、afterEvaluate兩個(gè)階段的方法調(diào)用。AndroidTask 是依賴配置項(xiàng)的配置才能生成相應(yīng)任務(wù),所以是需要在 afterEvaluate 之后創(chuàng)建。所以,重點(diǎn)查看 afterEvaluate 階段的 createAndroidTasks方法。

VariantManager#createAndroidTasks

public void createAndroidTasks() {
        
        ...
        //variantDataList 構(gòu)建變體數(shù)據(jù)集。variantDataList為空,則進(jìn)行填充
        ...
        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做了代碼簡(jiǎn)化,只保留了主干。代碼注釋也很明了,就不再贅述。如果variantDataList為空,就以build script中的buildType, productFlavor等為原料去填充variantDataList。直接移步populateVariantDataList邏輯。

VariantManager#populateVariantDataList

/**
     * Create all variants. 創(chuàng)建所有的構(gòu)建變體
     */
    public void populateVariantDataList() {
        //productFlavors類型為Map<String, ProductFlavorData<CoreProductFlavor>>
        if (productFlavors.isEmpty()) {
            createVariantDataForProductFlavors(Collections.<ProductFlavor>emptyList());
        }           
        else {
            ...
        }
    }

查看productFlavors中有無(wú)元素,若沒(méi)有元素,則填充productFlavorsList。移步VariantManager#createVariantDataForProductFlavors

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

        BuildTypeData testBuildTypeData = null;
        ...

        BaseVariantData variantForAndroidTest = null;
        //獲取過(guò)濾變體
        Action<com.android.build.gradle.api.VariantFilter> variantFilterAction =
                extension.getVariantFilter();

        //遍歷buildType
        for (BuildTypeData buildTypeData : buildTypes.values()) {
            boolean ignore = false;
            
            //過(guò)濾變體
            if (variantFilterAction != null) {
                ...
                ignore = variantFilter.isIgnore();
            }

        
            //此時(shí)ignore == true,跳過(guò)if判斷
            if (!ignore) {
                /* 一個(gè)buildType + productFlavorList 創(chuàng)建variantData,添加到variantDataList */
                BaseVariantData<?> variantData = createVariantData(
                        buildTypeData.getBuildType(),
                        productFlavorList);
                variantDataList.add(variantData);

                GradleVariantConfiguration variantConfig = variantData.getVariantConfiguration();
                ...
                
                //存在Gradle測(cè)試代碼
                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方法中,會(huì)遍歷buildType,每一種buildType再與productFlavorList中的每一種productFlavor組合成為構(gòu)建變體。這個(gè)過(guò)程在下面的createVariantData方法中實(shí)現(xiàn)。注意createVariantData返回BaseVariantData類型的對(duì)象,添加到variantDataList中。variantDataList是VariantManager的一個(gè)全局變量。

Gradle 會(huì)為配置的productFlavor與buildType的每個(gè)可能的組合創(chuàng)建構(gòu)建變體。不過(guò),某些特定的構(gòu)建變體在項(xiàng)目環(huán)境中可能并不必要,也可能沒(méi)有意義。所以,在模塊級(jí)build.gradle文件中創(chuàng)建一個(gè)變體過(guò)濾器,以移除某些構(gòu)建變體配置。所以,createVariantDataForProductFlavors方法中還對(duì)可能存在的過(guò)濾變體進(jìn)行處理。以下是AndroidDeveloper文檔中給出的一段示例代碼,過(guò)濾掉組合“minApi21”和“demo”產(chǎn)品風(fēng)格的所有構(gòu)建變體配置。

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

     /**
     * 給定一個(gè)buildType,一個(gè)集合ProductFlavor集合。
     * 創(chuàng)建由該buildType和每一個(gè)ProductFlavor的構(gòu)建變體
     * 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接口中方法,具體實(shí)現(xiàn)在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有相應(yīng)的具體實(shí)現(xiàn)。分別看一下具體實(shí)現(xiàn)。

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方法中最顯眼也是最熟悉的的兩個(gè)Set<String>類型的對(duì)象:densities、abis。針對(duì)不同的 ABI(應(yīng)用程序二進(jìn)制接口)或(density)屏幕密度,可以構(gòu)建多個(gè) APK。通常做法是在android塊中。

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

      abi{
         ...
      }
   }
}

這樣在創(chuàng)建variant過(guò)程中,會(huì)同時(shí)結(jié)合每一種配置的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就更簡(jiǎn)單了,直接返回一個(gè)新建的LibraryVariantData對(duì)象。

以上是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不為空,就獲取所有產(chǎn)品口味組合的列表flavorComboList ,然后遍歷flavorComboList ,繼續(xù)調(diào)用VariantManager#createVariantDataForProductFlavors,后面邏輯就一樣了。populateVariantDataList方法調(diào)用到此結(jié)束。接著看VariantManager#createAndroidTasks下面的邏輯,

public void createAndroidTasks() {
        ... 
        //variantDataList具體填充邏輯
        populateVariantDataList();
        ...
        //Create top level test tasks. 創(chuàng)建頂級(jí)測(cè)試任務(wù)
        taskManager.createTopLevelTestTasks(tasks, ...)
        ...
        createTasksForVariantData(tasks, variantData);
        ...                   
        taskManager.createReportTasks(variantDataList);
}

taskManager#createTopLevelTestTasks
根據(jù)注釋知道,這個(gè)方法是創(chuàng)建頂級(jí)測(cè)試任務(wù),這個(gè)方法略去。直接看VariantManager#createTasksForVariantData

/**
     * Create tasks for the specified variantData.
       為具體的構(gòu)建變體創(chuàng)建相關(guān)的tasks
     */
    public void createTasksForVariantData(
            final TaskFactory tasks,
            final BaseVariantData<? extends BaseVariantOutputData> variantData) {

        // assemble task用于組合項(xiàng)目中的所有輸出。添加assemble task對(duì)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, 先忽略測(cè)試部分邏輯
        if (variantType.isForTesting()) {
            ...
        } else {
            taskManager.createTasksForVariantData(tasks, variantData);
        }
    }

assemble task用于組合項(xiàng)目中的所有輸出。createTasksForVariantData方法中,首先添加assemble task對(duì)buildType assemble task依賴。之后調(diào)用

VariantManager#createAssembleTaskForVariantData。

/**
     * Create assemble task for VariantData.
     * 為VariantData創(chuàng)建assemble task
     *
     * 為buildTypeAssembleTask, productFlavorAssembleTask 添加依賴
     */
    private void createAssembleTaskForVariantData(
            TaskFactory tasks,
            final BaseVariantData<?> variantData) {
        
        //測(cè)試variantType     
        if (variantData.getType().isForTesting()) {
            variantData.assembleVariantTask = taskManager.createAssembleTask(tasks, variantData);
        } 
        //非測(cè)試variantType
        else {
            BuildTypeData buildTypeData =
                    buildTypes.get(variantData.getVariantConfiguration().getBuildType().getName());

            //productFlavors塊沒(méi)有配置       
            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);

                //設(shè)置builtType assembleTask 依賴 variantData assemble task
                // setup the task dependencies
                // build type
                buildTypeData.getAssembleTask().dependsOn(variantData.assembleVariantTask);

                //設(shè)置各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返回的集合中是否有遺漏,如有遺漏,需要?jiǎng)?chuàng)建相關(guān)task,
                //并設(shè)置依賴
                // 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邏輯也比較簡(jiǎn)單,為buildType、productFlavor的 assembleTask添加對(duì)variantData.assembleVariantTask的依賴。
繼續(xù)看createTasksForVariantData中的邏輯。

taskManager#createTasksForVariantData

    //上個(gè)方法的名字叫createAssembleTask,其中內(nèi)容是在做跟assemble task有關(guān)的操作。
    //這個(gè)方法叫createTasks,其中邏輯自然就是創(chuàng)建各種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);
        
        //創(chuàng)建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大體邏輯已經(jīng)走完。BasePlugin#apply邏輯也已完成。

后記 (仍存有的疑問(wèn))

createExtension方法中創(chuàng)建兩個(gè)配置塊的default-mapping、default-metadata都未接觸過(guò),所以這里存在一些疑問(wèn)。有知道的同學(xué)希望能不吝賜教。

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

還有就是在源碼中存在這一部分,這里提到一個(gè)Jack compiler,也是第一次聽(tīng),專門去查了下,這里有一篇關(guān)于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/

本文只是簡(jiǎn)單的跟了一下流程,其中很多細(xì)節(jié)都忽略了,在以后的學(xué)習(xí)過(guò)程中逐漸加深理解吧,文章在作者對(duì)Gradle相關(guān)有新的認(rèn)知后會(huì)繼續(xù)做出更改,感謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Gradle 是一款構(gòu)建系統(tǒng)工具,它的 DSL 基于 Groovy 實(shí)現(xiàn)。Gradle 構(gòu)建的大部分功能都是通過(guò)插...
    任教主來(lái)也閱讀 3,250評(píng)論 3 6
  • 說(shuō)明 本文主要介紹和Gradle關(guān)系密切、相對(duì)不容易理解的配置,偏重概念介紹。部分內(nèi)容是Android特有的(例如...
    搬磚的小明閱讀 16,155評(píng)論 1 62
  • 所有Android插件的基本擴(kuò)展。 你不需要直接使用這個(gè),你可以選擇下面幾個(gè)合適的直接使用 AppExtensio...
    我該忘了我自己w_u閱讀 3,559評(píng)論 0 5
  • 在 Android Studio 構(gòu)建的項(xiàng)目中,基于 Gradle 進(jìn)行項(xiàng)目的構(gòu)建,同時(shí)使用 Android DS...
    Ant_way閱讀 7,586評(píng)論 0 16
  • 這一章主要針對(duì)項(xiàng)目中可以用到的一些實(shí)用功能來(lái)介紹Android Gradle,比如如何隱藏我們的證書文件,降低風(fēng)險(xiǎn)...
    acc8226閱讀 7,967評(píng)論 3 25

友情鏈接更多精彩內(nèi)容