前言

上一篇我们知道com.android.application plugin 对应的类为com.android.build.gradle.AppPlugin

这个类的声明为: public class AppPlugin extends BasePlugin implements Plugin<Project>

看到最后implements Plugin<Project>,熟悉 gradle plugin 的人应该知道, apply plugin: 'com.android.application'其实就是调用AppPlugin类public void apply(@NonNull Project project)方法。

com.android.library plugin 对应的类为com.android.build.gradle.LibraryPlugin

这个类的声明为: public class LibraryPlugin extends BasePlugin implements Plugin<Project>

这个两个apply方法的具体内容只有一点点不同,两个都调用了super.apply(project)方法:

@Override
public void apply(@NonNull Project project) {
    super.apply(project);
    // 下面的代码只在Library plugin中存在
    // Default assemble task for the default-published artifact.
    // This is needed for the prepare task on the consuming project.
    project.getTasks().create("assembleDefault");
}

接下来我们一步步的跟进:

BasePlugin apply

可以看到,就是调用了 BasePlugin 的apply方法。我们来看一下 BasePlugin 的apply方法做了什么。 老规矩,分析中会去掉日志,记录,错误检查之类的代码。

// 去掉那些我认为不重要的代码后,整个apply方法的流程如下。
protected void apply(@NonNull Project project) {
    configureProject();
    createExtension();
    createTasks();
    // 读取 "android.additional.plugins"对应的插件名称
    // Apply additional plugins
    for (String plugin : AndroidGradleOptions.getAdditionalPlugins(project)) {
        project.apply(ImmutableMap.of("plugin", plugin));
    }
}

可以看到,其实整个apply方法分 4 步,最后一步读取插件没有什么好分析的,对于剩下三步来说本篇文章只分析前两步。

BasePlugin configureProject

我们一个过程一个过程研究。 先看configureProject()

String creator = "Android Gradle " Version.ANDROID_GRADLE_PLUGIN_VERSION;

protected void configureProject() {
    sdkHandler = new SdkHandler(project, getLogger());

    androidBuilder = new AndroidBuilder(
            project == project.getRootProject() ? project.getName() : project.getPath(), // project Id
            creator, // the createdBy String for the apk manifest(打包之后的MANIFEST.MF文件可以看到)
            new GradleProcessExecutor(project),  // An executor for external processes.
            new GradleJavaProcessExecutor(project), // An executor for external Java-based processes.
            extraModelInfo,
            getLogger(),
            isVerbose());

    project.getPlugins().apply(JavaBasePlugin.class);
    jacocoPlugin = project.getPlugins().apply(JacocoPlugin.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.
    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();
            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();
        }
    });
    project.getGradle().getTaskGraph().addTaskExecutionGraphListener(
            new TaskExecutionGraphListener() {
                @Override
                public void graphPopulated(TaskExecutionGraph taskGraph) {
                    for (Task task : taskGraph.getAllTasks()) {
                        if (task instanceof TransformTask) {
                            Transform transform = ((TransformTask) task).getTransform();
                            if (transform instanceof DexTransform) {
                                PreDexCache.getCache().load(
                                        new File(project.getRootProject().getBuildDir(),
                                        FD_INTERMEDIATES + "/dex-cache/cache.xml"));
                                break;
                            } else if (transform instanceof JackPreDexTransform) {
                                JackConversionCache.getCache().load(
                                        new File(project.getRootProject().getBuildDir(),
                                        FD_INTERMEDIATES + "/jack-cache/cache.xml"));
                                break;
                            }
                        }
                    }
                }
            });
}

这个方法主要做了如下几个操作:

  • 初始化 SdkHandler
  • 初始化 AndroidBuilder
  • 依赖 JavaBasePlugin,JacocoPlugin;这两个 Plugin 的 apply()方法我这里就不写了,大家有兴趣就像本文一样跟进去即可。
  • 给”assemble”任务加上说明
  • 当 Gradle Build 完成的时候做一些关闭和清理的操作
  • 在 Transform 任务真正执行之前,读取对应的 Cache。

SdkHandler 主要作用是找 local.properties 文件里 SdkLocation 和 NdkLocation SdkLocation 的查找顺序为: 1. local.properties 文件里 sdk.dir 的配置 2. local.properties 文件里 android.dir 的配置 3. 环境变量”ANDROID_HOME” 4. 环境变量”android.home”

NdkLocation 的查找顺序为: 1. local.properties 文件里 ndk.dir 的配置 2. 环境变量”ANDROID_NDK_HOME”

AndroidBuilder 对象主要的几个参数的含义从我在代码中添加的注释即可了解。 最后讲一下TaskExecutionGraphListener这个接口。 官方文档是这样说的:

A TaskExecutionGraphListener is notified when the TaskExecutionGraph has been populated. You can use this interface in your build file to perform some action based on the contents of the graph, before any tasks are actually executed.

大概翻译一下,当 Gradle 将所有 task 的关系图填充之后,该接口会被调用。 你可以在 build 文件中使用这个接口,在任意 task 真正执行之前,去完成一些基于 task 关系图内容的任务。 所以这里可以根据对应的 Task,判断 Task 的类型,做对应的操作。

BasePlugin createExtension

继续看apply方法中第二个过程createExtension()

private void createExtension() {
    // 保存BuildType的NamedDomainObjectContainer
    final NamedDomainObjectContainer<BuildType> buildTypeContainer = project.container(
            BuildType.class,
            new BuildTypeFactory(instantiator, project, project.getLogger()));
    // 保存ProductFlavor的NamedDomainObjectContainer
    final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer = project.container(
            ProductFlavor.class,
            new ProductFlavorFactory(instantiator, project, project.getLogger(), extraModelInfo));
    // 保存SigningConfig的NamedDomainObjectContainer
    final NamedDomainObjectContainer<SigningConfig>  signingConfigContainer = project.container(
            SigningConfig.class,
            new SigningConfigFactory(instantiator));
    // 创建android这个extension
    extension = project.getExtensions().create("android", getExtensionClass(),
            project, instantiator, androidBuilder, sdkHandler,
            buildTypeContainer, productFlavorContainer, signingConfigContainer,
            extraModelInfo, isLibrary());

    // create the default mapping configuration.
    // 创建default-mapping和default-metadata两个configuration,并加入描述
    // 具体的作用暂时没有看出来,如果你知道,欢迎留言告诉我
    // 通过如下代码放在build.gradle,可以打印出当前所有的configuration
    /**
        configurations.names.forEach(new Consumer<String>() {
                @Override
                void accept(String s) {
                        println "configurations:" + s;
                }
        })
    */
    project.getConfigurations().create("default" + VariantDependencies.CONFIGURATION_MAPPING)
            .setDescription("Configuration for default mapping artifacts.");
    project.getConfigurations().create("default" + VariantDependencies.CONFIGURATION_METADATA)
            .setDescription("Metadata for the produced APKs.");
    // 创建DependencyManager, 负责管理配置的所有依赖
    dependencyManager = new DependencyManager(
            project,
            extraModelInfo,
            sdkHandler);
    // 负责管理ndk相关,这里略过不提
    ndkHandler = new NdkHandler(
            project.getRootDir(),
            null, /* compileSkdVersion, this will be set in afterEvaluate */
            "gcc",/* toolchainName */
            "" /*toolchainVersion*/);
    // 负责创建taskManager
    taskManager = createTaskManager(
            project,
            androidBuilder,
            dataBindingBuilder,
            extension,
            sdkHandler,
            ndkHandler,
            dependencyManager,
            registry);

    // 负责创建variant
    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);

    // Register a builder for the native tooling model
    NativeModelBuilder nativeModelBuilder = new NativeModelBuilder(variantManager);
    registry.register(nativeModelBuilder);

    // 下面三个whenObjectAdded方法从名字上就很好理解
    // 当你添加一个对应的对象的时候,回调此方法,也就是需要在variantManager里面添加对应的对象

    // 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) {
            // 默认debug签名
            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);
}

看到这么长的代码,本想去掉点,发现这里面去什么都不合适。 那么跟着我慢慢看一下。这里有几个地方需要解释:

  • NamedDomainObjectContainer是什么?

NamedDomainObjectContainer简单来说就是一个容器,里面的泛型保存了容器里面需要传的类型,类似一个 List

  • extension 的创建代表了什么?

extension 的创建代表了我们在 build.gradle 文件中,可以使用

android{

}

这样的闭包来给该扩展传消息。我们在{}内写的任何被允许的内容,在这里都被定义好了。从getExtensionClass方法获取具体的 Class, application: 使用com.android.build.gradle.AppExtension.class library: 使用com.android.build.gradle.LibraryExtension.class。 后面的值都是负责初始化这两个类的时候传入的值。

  • TaskManager 的作用?

首先这个依旧根据 application 和 library 做区分。 application: 创建ApplicationTaskManager library: 创建LibraryTaskManager 这两个类就是负责创建我们用来处理 Android 源码的 Gradle Task 的地方,比如 assemblyDebug, installDebug… 现在这里大概了解一下这个对象,后面再细细解读此对象。

  • VariantManager 的作用?

这就是管理Build Variant的地方,Build Variant的意义就是build typeproduct flavor交叉形成的,换句话说就是合并这两个东东的属性形成Build Variant的配置。 暂时也是单纯的提一下,后面再细细解读。

ModelBuilder, NativeModelBuilderprivate ToolingModelBuilderRegistry registry这三个对象我们都先放一下, 这个和 Android Plugin 本身无关,是和 gradle 的运行机制相关的东东。

好了,这里大概梳理一下此方法的逻辑,

  • 创建buildTypeContainer, productFlavorContainer, signingConfigContainer
  • 将 android 这个 extension 加入 build.gradle
  • 创建一些后面要使用的对象主要指ModelBuilderNativeModelBuilder,注册到 gradle 中。
  • 给上面提到的 Container 加一些回调
  • 通过variantFactory给 Container 创建默认的配置

看一下这个默认的配置,App 和 Library 的默认配置是相同的,都是如下代码。

VariantFactory createDefaultComponents

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

可以看出来我们的 SigningConfigs 里面默认有 debug 类型。 为什么不需要写 signingConfig 就有个默认的 debug 签名?就是这里配置的。 同理,为什么新建工程 buildTypes 有 debug 和 release?就是这里创建的。 这里就相当于我们在build.gradle文件写了如下内容:

android{
    signingConfigs {
        debug {}
    }

    buildTypes {
        debug {}
        release {}
    }
}

这个方法到这里也就暂时过完了。所以这一篇到这里就告一段落了。