Gradle Plugin 源码分析

本文基于的gradle版本如下:

plugin版本 :com.android.tools.build:gradle:3.5.4'
gradle 版本:5.6.4

我们知道Android gradle plugin是用来构建Android工程的gradle插件,在Android gradle 插件中,可以看到app工程和library工程所依赖的plugin是不一样的。

// app 工程
apply plugin: 'com.android.application'
// library 工程
apply plugin: 'com.android.library'

首先我们来看一个app的gradle文件格式。

1619683831(1).png
plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"

    defaultConfig {
        applicationId "com.example.flavorgradle"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    flavorDimensions "default"

    productFlavors {
        out1 {
            applicationId "com.example.out1"
            buildConfigField "String", "CHANNEL", '"channel_out1"'
            versionCode 1
            versionName "1.0"
            signingConfig signingConfigs.release
        }
        out2 {
            applicationId "com.example.out2"
            buildConfigField "String", "CHANNEL", '"channel_out2"'
            versionCode 1
            versionName "1.0"
            signingConfig signingConfigs.release
        }
        out3 {
            applicationId "com.example.out3"
            buildConfigField "String", "CHANNEL", '"channel_out2"'
            versionCode 1
            versionName "1.0"
            signingConfig signingConfigs.release
        }
    }
    
    signingConfigs {
        debug {
            //签名文件
            storeFile file(keystoreProperties["STORE_FILE"])
            storePassword keystoreProperties["STORE_PASSWORD"]
            keyAlias keystoreProperties["KEY_ALIAS"]
            //签名密码
            keyPassword keystoreProperties["KEY_PASSWORD"]
            v2SigningEnabled false
        }

        release {
            //签名文件
            storeFile file(keystoreProperties["STORE_FILE"])
            storePassword keystoreProperties["STORE_PASSWORD"]
            keyAlias keystoreProperties["KEY_ALIAS"]
            //签名密码
            keyPassword keystoreProperties["KEY_PASSWORD"]
            v2SigningEnabled false
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    /*
        这个需要跟上面productFlavors配合使用,目的是只是在项目为out3打包的时候引用,编译
     */
    out3Implementation 'com.github.vivitale:BaseCore:0.0.54'
}

我们都知道最上面引用的plugin id 对应gradle3.5.4的META-INF/gradle-plugins文件夹的com.android.build.gradle.properties文件。

1619690725(1).png
implementation-class=com.android.build.gradle.AppPlugin

对应具体的插件为AppPlugin。

然后android则对应AppExtension。其创建是在AbstractAppPlugin类中。

protected BaseExtension createExtension(
            @NonNull Project project,
            @NonNull ProjectOptions projectOptions,
            @NonNull GlobalScope globalScope,
            @NonNull NamedDomainObjectContainer buildTypeContainer,
            @NonNull NamedDomainObjectContainer productFlavorContainer,
            @NonNull NamedDomainObjectContainer signingConfigContainer,
            @NonNull NamedDomainObjectContainer buildOutputs,
            @NonNull SourceSetManager sourceSetManager,
            @NonNull ExtraModelInfo extraModelInfo) {
        return project.getExtensions()
                .create(
                        "android",
                        getExtensionClass(),
                        project,
                        projectOptions,
                        globalScope,
                        buildTypeContainer,
                        productFlavorContainer,
                        signingConfigContainer,
                        buildOutputs,
                        sourceSetManager,
                        extraModelInfo,
                        isBaseApplication);
    }

创建了一个名字为android的Extension,具体实现为AppExtension。

public AppExtension(
            @NonNull Project project,
            @NonNull ProjectOptions projectOptions,
            @NonNull GlobalScope globalScope,
            @NonNull NamedDomainObjectContainer buildTypes,
            @NonNull NamedDomainObjectContainer productFlavors,
            @NonNull NamedDomainObjectContainer signingConfigs,
            @NonNull NamedDomainObjectContainer buildOutputs,
            @NonNull SourceSetManager sourceSetManager,
            @NonNull ExtraModelInfo extraModelInfo,
            boolean isBaseModule) {
        super(
                project,
                projectOptions,
                globalScope,
                buildTypes,
                productFlavors,
                signingConfigs,
                buildOutputs,
                sourceSetManager,
                extraModelInfo,
                isBaseModule);
    }

其中signingConfigs对应build.gradle文件中的

signingConfigs {
        debug {
            //签名文件
            storeFile file(keystoreProperties["STORE_FILE"])
            storePassword keystoreProperties["STORE_PASSWORD"]
            keyAlias keystoreProperties["KEY_ALIAS"]
            //签名密码
            keyPassword keystoreProperties["KEY_PASSWORD"]
            v2SigningEnabled false
        }

        release {
            //签名文件
            storeFile file(keystoreProperties["STORE_FILE"])
            storePassword keystoreProperties["STORE_PASSWORD"]
            keyAlias keystoreProperties["KEY_ALIAS"]
            //签名密码
            keyPassword keystoreProperties["KEY_PASSWORD"]
            v2SigningEnabled false
        }
    }

这一整块代码。buildTypes则对应:

buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

productFlavors对应

productFlavors {
        out1 {
            applicationId "com.example.out1"
            buildConfigField "String", "CHANNEL", '"channel_out1"'
            versionCode 1
            versionName "1.0"
            signingConfig signingConfigs.release
        }
        out2 {
            applicationId "com.example.out2"
            buildConfigField "String", "CHANNEL", '"channel_out2"'
            versionCode 1
            versionName "1.0"
            signingConfig signingConfigs.release
        }
        out3 {
            applicationId "com.example.out3"
            buildConfigField "String", "CHANNEL", '"channel_out2"'
            versionCode 1
            versionName "1.0"
            signingConfig signingConfigs.release
        }
    }

下面我们来分析AppPlugin的构建流程。AppPlugin最终会走父类BasePlgin的apply方法。

public final void apply(@NonNull Project project) {
        CrashReporting.runAction(
                () -> {
                    basePluginApply(project);
                    pluginSpecificApply(project);
                });
    }
private void basePluginApply(@NonNull Project project) {
        this.project = project;
        this.projectOptions = new ProjectOptions(project);
        checkGradleVersion(project, getLogger(), projectOptions);//1
        DependencyResolutionChecks.registerDependencyCheck(project, projectOptions);//2

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

        checkPathForErrors();//4
        checkModulesForErrors();//5

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

        Workers.INSTANCE.initFromProject(
                projectOptions,
                ForkJoinPool.commonPool());

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

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

            threadRecorder.record(
                    ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
                    project.getPath(),
                    null,
                    this::configureProject);//8

            threadRecorder.record(
                    ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
                    project.getPath(),
                    null,
                    this::configureExtension);//9

            threadRecorder.record(
                    ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
                    project.getPath(),
                    null,
                    this::createTasks);//10
        } else {
            ......
        }
            
    }

注释1检查gradle版本。

注释2检查并确保在配置阶段不去解析依赖。

注释3应用一个 AndroidBasePlugin,目的是为了让其他插件作者区分当前应用的是一个 Android 插件。AndroidBasePlugin是一个空实现。

注释4是检查 project 路径是否有错误,发生错误则抛出 StopExecutionException 异常。

注释5检查子 moudle 的结构:目前版本会检查 2 个模块有没有相同的标识(组+名称),如果有则抛出 StopExecutionException 异常。(组件化在不同的 moudle 中需要给资源加 prefix 前缀)

注释6插件初始化,必须立即执行。此外,需要注意,Gradle Deamon进程 永远不会同时执行两个构建流程。

(Gradle会构建两个进程,一个是client进程,其作用是查找并与Deamon进程通信。当Deamon进程没有开启,Client进程则会创建一个Deamon进程。如果Deamon进程已经开启,则将参数给Deamon进程。而Deamon进程是不依赖AS独立存在,构建结束不会依赖。每一个Gradle版本都会对应一个Deamon进程。这么做的目的是加速编译构建时间。)

注释7初始化用于记录构建过程中配置信息的工厂实例 ProcessProfileWriterFactory。

现在重点来分析注释8,9,10 。

注释8:

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

        // Enforce minimum versions of certain plugins
        //强制使用不低于当前所支持的最小插件版本,否则会抛出异常。
        GradlePluginUtils.enforceMinimumVersionsOfPlugins(project, syncIssueHandler);

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

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

        //如果启动了 构建缓存 选项,则会创建 buildCache 实例以便后面能重用缓存。
        @Nullable
        FileCache buildCache = BuildCacheUtils.createBuildCacheIfEnabled(project, projectOptions);

        globalScope =
                new GlobalScope(
                        project,
                        creator,
                        new ProjectWrapper(project),
                        projectOptions,
                        dslScope,
                        sdkComponents,
                        registry,
                        buildCache,
                        extraModelInfo.getMessageReceiver());
        //给名字为assemble的添加描述。
        project.getTasks()
                .named("assemble")
                .configure(
                        task ->
                                task.setDescription(
                                        "Assembles all variants of all applications and secondary packages."));
        //对构建各个阶段的监听
        gradle.addBuildListener(
                new BuildListener() {
                    //构建开始
                    @Override
                    public void buildStarted(@NonNull Gradle gradle) {}
                    //settings 文件解析完成
                    @Override
                    public void settingsEvaluated(@NonNull Settings settings) {}
                    //project加载完成
                    @Override
                    public void projectsLoaded(@NonNull Gradle gradle) {}
                    //project解析完成
                    @Override
                    public void projectsEvaluated(@NonNull Gradle gradle) {}
                    //构建完成
                    @Override
                    public void buildFinished(@NonNull BuildResult buildResult) {
                        if (buildResult.getGradle().getParent() != null) {
                            return;
                        }
                        ModelBuilder.clearCaches();
                        Workers.INSTANCE.shutdown();
                        sdkComponents.unload();
                        SdkLocator.resetCache();
                        ConstraintHandler.clearCache();
                        threadRecorder.record(
                                ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
                                project.getPath(),
                                null,
                                () -> {
                                    if (!projectOptions.get(
                                            BooleanOption.KEEP_SERVICES_BETWEEN_BUILDS)) {
                                        WorkerActionServiceRegistry.INSTANCE
                                                .shutdownAllRegisteredServices(
                                                        ForkJoinPool.commonPool());
                                    }
                                    Main.clearInternTables();
                                });
                        DeprecationReporterImpl.Companion.clean();
                    }
                });

        createLintClasspathConfiguration(project);
    }

根据这些回调,我们可以做一些事,比如在我们的settings.gradle文件中去测量每个阶段所用的时间。

long beginOfSetting = System.currentTimeMillis()
def beginOfConfig
def configHasBegin = false
def beginOfProjectConfig = new HashMap()
def beginOfProjectExcute
gradle.projectsLoaded {
    println '初始化阶段,耗时:' + (System.currentTimeMillis() -
            beginOfSetting) + 'ms'
}
gradle.beforeProject { project ->
    if (!configHasBegin) {
        configHasBegin = true
        beginOfConfig = System.currentTimeMillis()
    }
    beginOfProjectConfig.put(project, System.currentTimeMillis())
}
gradle.afterProject { project ->
    def begin = beginOfProjectConfig.get(project)
    println '配置阶段,' + project + '耗时:' +
            (System.currentTimeMillis() - begin) + 'ms'
}
gradle.taskGraph.whenReady {
    println '配置阶段,总共耗时:' + (System.currentTimeMillis() -
            beginOfConfig) + 'ms'
    beginOfProjectExcute = System.currentTimeMillis()
}
gradle.taskGraph.beforeTask { task ->
    task.doFirst {
        task.ext.beginOfTask = System.currentTimeMillis()
    }
    task.doLast {
        println '执行阶段,' + task + '耗时:' +
                (System.currentTimeMillis() - task.beginOfTask) + 'ms'
    }
}
gradle.buildFinished {
    println '执行阶段,耗时:' + (System.currentTimeMillis() -
            beginOfProjectExcute) + 'ms'
}

下面来看注释9

private void configureExtension() {
        ObjectFactory objectFactory = project.getObjects();
        final NamedDomainObjectContainer buildTypeContainer =
                project.container(
                        BuildType.class,
                        new BuildTypeFactory(
                                objectFactory,
                                project,
                                extraModelInfo.getSyncIssueHandler(),
                                extraModelInfo.getDeprecationReporter()));
        final NamedDomainObjectContainer productFlavorContainer =
                project.container(
                        ProductFlavor.class,
                        new ProductFlavorFactory(
                                objectFactory,
                                project,
                                extraModelInfo.getDeprecationReporter(),
                                project.getLogger()));
        final NamedDomainObjectContainer signingConfigContainer =
                project.container(
                        SigningConfig.class,
                        new SigningConfigFactory(
                                objectFactory,
                                GradleKeystoreHelper.getDefaultDebugKeystoreLocation()));

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

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

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

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

        globalScope.setExtension(extension);

        variantFactory = createVariantFactory(globalScope, extension);

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

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

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

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

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

        productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor);

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

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

首先创建了 BuildType、ProductFlavor、SigningConfig、buildOutputs 四个类型的Container,接着传入到了createExtension方法中,该方法的具体实现是在AbstractAppPlugin。

对于Extension我们可以理解为java中的bean类。而BuildType、ProductFlavor、SigningConfig、buildOutputs属于这个bean类里面的成员变量。来看一个具体的SigningConfig。

public SigningConfig initWith(com.android.builder.model.SigningConfig that) {
        setStoreFile(that.getStoreFile());
        setStorePassword(that.getStorePassword());
        setKeyAlias(that.getKeyAlias());
        setKeyPassword(that.getKeyPassword());
        setV1SigningEnabled(that.isV1SigningEnabled());
        setV2SigningEnabled(that.isV2SigningEnabled());
        setStoreType(that.getStoreType());
        return this;
    }

其具体的实现类对应SigningConfigImpl,

override fun initWith(that: SigningConfig) {
        if (checkSeal()) {
            storeFile = that.storeFile
            storePassword = that.storePassword
            keyAlias = that.keyAlias
            keyPassword = that.keyPassword
            v1SigningEnabled = that.v1SigningEnabled
            v2SigningEnabled = that.v2SigningEnabled
        }
    }

而这些对应于build.gradle的:

signingConfigs {
        debug {
            //签名文件
            storeFile file(keystoreProperties["STORE_FILE"])
            storePassword keystoreProperties["STORE_PASSWORD"]
            keyAlias keystoreProperties["KEY_ALIAS"]
            //签名密码
            keyPassword keystoreProperties["KEY_PASSWORD"]
            v2SigningEnabled false
        }

        release {
            //签名文件
            storeFile file(keystoreProperties["STORE_FILE"])
            storePassword keystoreProperties["STORE_PASSWORD"]
            keyAlias keystoreProperties["KEY_ALIAS"]
            //签名密码
            keyPassword keystoreProperties["KEY_PASSWORD"]
            v2SigningEnabled false
        }
    }

一般打包出来的apk需要签名才能安装在我们的手机上。但是我们的debug好像直接就可以安装,也不需要配置签名什么的。其实在源码中,当是debug包的时候,有一个默认的签名。

public static DefaultSigningConfig debugSigningConfig(File storeFile) {
        DefaultSigningConfig result = new DefaultSigningConfig(BuilderConstants.DEBUG);
        result.mStoreFile = storeFile;
        result.mStorePassword = DEFAULT_PASSWORD;
        result.mKeyAlias = DEFAULT_ALIAS;
        result.mKeyPassword = DEFAULT_PASSWORD;
        return result;
    }

这个storeFile是从外面传进来的,我们继续跟下去。

fun createDefaultDebugStore(defaultDebugKeystoreLocation: File, logger: Logger) {
    val signingConfig = DefaultSigningConfig.debugSigningConfig(defaultDebugKeystoreLocation)
    logger.info(
            "Creating default debug keystore at {}",
            defaultDebugKeystoreLocation.absolutePath)
    try {
        if (!KeystoreHelper.createDebugStore(
                signingConfig.storeType,
                signingConfig.storeFile!!,
                signingConfig.storePassword!!,
                signingConfig.keyPassword!!,
                signingConfig.keyAlias!!,
                LoggerWrapper(logger))) {
            throw IOException("Unable to create missing debug keystore.")
        }
    } catch (e: KeytoolException) {
        throw IOException(e)
    }
}

private fun createDefaultDebugKeystoreIfNeeded() {

        checkState(signingConfig.isSigningReady, "Debug signing config not ready.")
        
        checkState(FileUtils.parentDirExists(defaultDebugKeystoreLocation),
                "Parent directory of the default debug keystore '%s' does not exist",
                defaultDebugKeystoreLocation)
        
        SynchronizedFile
                .getInstanceWithMultiProcessLocking(defaultDebugKeystoreLocation)
                .createIfAbsent { createDefaultDebugStore(it, this.logger) }
    }

createDefaultDebugKeystoreIfNeeded中的defaultDebugKeystoreLocation这个赋值是在CreationAction内部类中,在构造方法中传入一个defaultDebugKeystoreLocation,然后在configure进行赋值。

override fun configure(task: ValidateSigningTask) {
            super.configure(task)

            task.signingConfig = variantScope.variantConfiguration.signingConfig ?: throw IllegalStateException(
                "No signing config configured for variant " + variantScope.fullVariantName)
            task.defaultDebugKeystoreLocation = defaultDebugKeystoreLocation
            task.dummyOutputDirectory = outputDirectory
            task.outputs.upToDateWhen { !task.forceRerun() }
        }

继续往下跟进。这个内部类是在一个task中,而我们的task是手TaskManager统一管理。所以可以在TaskManager找到这个内部类的实现。

taskFactory.register(
                new ValidateSigningTask.CreationAction(
                        variantScope, GradleKeystoreHelper.getDefaultDebugKeystoreLocation()));

fun getDefaultDebugKeystoreLocation(): File = try {
    File(KeystoreHelper.defaultDebugKeystoreLocation())
} catch (e: AndroidLocation.AndroidLocationException) {
    throw InvalidUserDataException("Failed to get default debug keystore location.", e)
}
public static String defaultDebugKeystoreLocation() throws AndroidLocationException {
        //this is guaranteed to either return a non null value (terminated with a platform
        // specific separator), or throw.
        String folder = AndroidLocation.getFolder();
        return folder + "debug.keystore";
    }

最后找到的是debug.keystore的一个路径。

这里只是分析了SigningConfig,其他的后面有时间再详细分析。

最后来分析注释10.

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

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

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

这里主要是分两块,一个是在 beforeEvaluate 创建任务;一个是在 afterEvaluate 创建任务。这里的区别是AndroidTask是依赖配置项的配置才能生成相应任务,所以是需要在 afterEvaluate 之后创建。

createTasksBeforeEvaluate 创建不依赖 flavor 的 task,TaskManager 的 createTasksBeforeEvaluate 方法给 Task 容器中注册了一系列的 Task,包括 uninstallAllTask、deviceCheckTask、connectedCheckTask、preBuild、extractProguardFiles、sourceSetsTask、assembleAndroidTest、compileLintTask 等等。

我们来看看对应的gradle task,如下图所示:

1619762164(1).png
Android 任务

androidDependencies-显示项目的Android依赖项
signingReport-显示基础和测试模块的签名信息
sourceSets-打印出此项目中定义的所有源集

Build 任务

assemble-组装所有变体的主要输出
assembleAndroidTest-组装所有测试应用程序
build-组装并测试该项目
buildDependents-组装并测试该项目以及依赖于该项目的所有项目
buildNeeded-组装和测试该项目及其依赖的所有项目
bundle-为所有变体组装捆绑包
clean-删除构建目录
cleanBuildCache-删除构建缓存目录
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources

构建安装任务

init-初始化一个新的Gradle构建
wrapper-生成Gradle包装器文件

清理任务

lintFix-在所有变体上运行lint并对源代码应用任何安全建议

帮助任务

buildEnvironment-显示在根项目“”中声明的所有buildscript依赖项
components-显示根项目“”生成的组件
dependencies-显示在根项目“”中声明的所有依赖项
dependencyInsight-显示对根项目“”中特定依赖关系的洞察。
help-显示帮助消息
model-显示根项目“”的配置模型
projects-显示根项目“”的子项目。

安装任务

installDebug-安装Debug构建
installDebugAndroidTest-为Debug版本安装android(在设备上)测试
uninstallAll-卸载所有应用程序。
uninstallDebug-卸载Debug构建
uninstallDebugAndroidTest-卸载Debug版本的android(在设备上)测试
uninstallRelease-卸载Release版本
 
验证任务

check-运行所有检查
connectedAndroidTest-安装并运行连接设备上所有风格的检测测试
connectedCheck-在当前连接的设备上运行所有设备检查
connectedDebugAndroidTest-在连接的设备上安装并运行测试以进行调试
deviceAndroidTest-使用所有设备提供程序安装和运行检测测试
deviceCheck-使用设备提供程序和测试服务器运行所有设备检查
lint-在所有变种上运行lint
test-对所有变体运行单元测试。
testDebugUnitTest-运行调试版本的单元测试
testReleaseUnitTest-运行发布版本的单元测试

重点关注 variantManager 的 createAndroidTasks 方法,

public List createAndroidTasks() {
       
        ...
       
        // 1、创建工程级别的测试任务。
        taskManager.createTopLevelTestTasks(!productFlavors.isEmpty());

        // 2、遍历所有 variantScope,为其变体数据创建对应的 Tasks。
        for (final VariantScope variantScope : variantScopes) {
            createTasksForVariantData(variantScope);
        }

        // 3、创建报告相关的 Tasks。
        taskManager.createReportTasks(variantScopes);

        return variantScopes;
    }

可以看到,在 createAndroidTasks 方法中有 三项处理,如下所示:

创建工程级别的测试任务。

遍历所有的 variantScope,为其变体数据创建对应的 Tasks。

创建报告相关的 Tasks。

继续看看 createTasksForVariantData 方法是如何为每一个指定的 Variant 类型创建对应的 Tasks 的。

public void createTasksForVariantData(final VariantScope variantScope) {
        final BaseVariantData variantData = variantScope.getVariantData();
        final VariantType variantType = variantData.getType();
        final GradleVariantConfiguration variantConfig = variantScope.getVariantConfiguration();

        // 1、创建 Assemble Task。
        taskManager.createAssembleTask(variantData);
        
        // 2、如果 variantType 是 base moudle,则会创建相应的 bundle Task。需要注意的是,base moudle 是指包含功能的 moudle,而用于 test 的 moudle 则是不包含功能的。
        if (variantType.isBaseModule()) {
            taskManager.createBundleTask(variantData);
        }

        // 3、如果 variantType 是一个 test moudle(其作为一个 test 的组件),则会创建相应的 test variant。
        if (variantType.isTestComponent()) {
        
            // 1)、将 variant-specific, build type multi-flavor、defaultConfig 这些依赖添加到当前的 variantData 之中。
            ...
            
            // 2)、如果支持渲染脚本,则添加渲染脚本的依赖。
            if (testedVariantData.getVariantConfiguration().getRenderscriptSupportModeEnabled()) {
                project.getDependencies()
                        .add(
                                variantDep.getCompileClasspath().getName(),
                                project.files(
                                        globalScope
                                                .getSdkComponents()
                                                .getRenderScriptSupportJarProvider()));
            }
        
            // 3)、如果当前 Variant 会输出一个 APK,即当前是执行的一个 Android test(一般用来进行 UI 自动化测试),则会创建相应的 AndroidTestVariantTask。
            if (variantType.isApk()) { // ANDROID_TEST
                if (variantConfig.isLegacyMultiDexMode()) {
                    String multiDexInstrumentationDep =
                            globalScope.getProjectOptions().get(BooleanOption.USE_ANDROID_X)
                                    ? ANDROIDX_MULTIDEX_MULTIDEX_INSTRUMENTATION
                                    : COM_ANDROID_SUPPORT_MULTIDEX_INSTRUMENTATION;
                    project.getDependencies()
                            .add(
                                    variantDep.getCompileClasspath().getName(),
                                    multiDexInstrumentationDep);
                    project.getDependencies()
                            .add(
                                    variantDep.getRuntimeClasspath().getName(),
                                    multiDexInstrumentationDep);
                }

                taskManager.createAndroidTestVariantTasks(
                        (TestVariantData) variantData,
                        variantScopes
                                .stream()
                                .filter(TaskManager::isLintVariant)
                                .collect(Collectors.toList()));
            } else { // UNIT_TEST
                // 4)、否则说明该 Test moudle 是用于执行单元测试的,则会创建 UnitTestVariantTask。 taskManager.createUnitTestVariantTasks((TestVariantData) variantData);
            }

        } else {
            // 4、如果不是一个 Test moudle,则会调用 ApplicationTaskManager 的 createTasksForVariantScope 方法。
            taskManager.createTasksForVariantScope(
                    variantScope,
                    variantScopes
                            .stream()
                            .filter(TaskManager::isLintVariant)
                            .collect(Collectors.toList()));
        }
}

在 createTasksForVariantData 方法中为每一个指定的 Variant 类型创建了与之对应的 Tasks,该方法的处理逻辑如下所示:

1、创建 Assemble Task。

2、如果 variantType 是 base moudle,则会创建相应的 bundle Task。需要注意的是,base moudle 是指包含功能的 moudle,而用于 test 的 moudle 则是不包含功能的。

3、如果 variantType 是一个 test moudle(其作为一个 test 的组件),则会创建相应的 test variant。

1)、将 variant-specific, build type multi-flavor、defaultConfig 这些依赖添加到当前的 variantData 之中。

2)、如果支持渲染脚本,则添加渲染脚本的依赖。

3)、如果当前 Variant 会输出一个 APK,即当前是执行的一个 Android test(一般用来进行 UI 自动化测试),则会创建相应的 AndroidTestVariantTask。

4)、否则说明该 Test moudle 是用于执行单元测试的,则会创建 UnitTestVariantTask。

4、如果不是一个 Test moudle,则会调用 ApplicationTaskManager 的 createTasksForVariantScope 方法。

public void createTasksForVariantScope(
            @NonNull final VariantScope variantScope,
            @NonNull List variantScopesForLint) {
        createAnchorTasks(variantScope);
        createCheckManifestTask(variantScope);

        handleMicroApp(variantScope);

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

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

        taskFactory.register(new MainApkListPersistence.CreationAction(variantScope));
        createBuildArtifactReportTask(variantScope);

        // Add a task to process the manifest(s)
        createMergeApkManifestsTask(variantScope);

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

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

        // Add a task to merge the resource folders
        createMergeResourcesTask(
                variantScope,
                true,
                Sets.immutableEnumSet(MergeResources.Flag.PROCESS_VECTOR_DRAWABLES));

        // Add tasks to compile shader
        createShaderTask(variantScope);

        // Add a task to merge the asset folders
        createMergeAssetsTask(variantScope);

        // Add a task to create the BuildConfig class
        createBuildConfigTask(variantScope);

        // Add a task to process the Android Resources and generate source files
        createApkProcessResTask(variantScope);

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

        createAidlTask(variantScope);

        // Add external native build tasks
        createExternalNativeBuildJsonGenerators(variantScope);
        createExternalNativeBuildTasks(variantScope);

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

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

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

            if (extension.getDataBinding().isEnabled()) {
                // Create a task that will package the manifest ids(the R file packages) of all
                // features into a file. This file's path is passed into the Data Binding annotation
                // processor which uses it to known about all available features.
                //
                // 

see: {@link TaskManager#setDataBindingAnnotationProcessorParams(VariantScope)} taskFactory.register( new DataBindingExportFeatureApplicationIdsTask.CreationAction( variantScope)); } } else { // Non-base feature specific task. // Task will produce artifacts consumed by the base feature taskFactory.register( new FeatureSplitDeclarationWriterTask.CreationAction(variantScope)); if (extension.getDataBinding().isEnabled()) { // Create a task that will package necessary information about the feature into a // file which is passed into the Data Binding annotation processor. taskFactory.register( new DataBindingExportFeatureInfoTask.CreationAction(variantScope)); } taskFactory.register(new MergeConsumerProguardFilesTask.CreationAction(variantScope)); } // Add data binding tasks if enabled createDataBindingTasksIfNecessary(variantScope, MergeType.MERGE); // Add a compile task createCompileTask(variantScope); createStripNativeLibraryTask(taskFactory, variantScope); if (variantScope.getVariantData().getMultiOutputPolicy().equals(MultiOutputPolicy.SPLITS)) { if (extension.getBuildToolsRevision().getMajor() < 21) { throw new RuntimeException( "Pure splits can only be used with buildtools 21 and later"); } createSplitTasks(variantScope); } createPackagingTask(variantScope); maybeCreateLintVitalTask( (ApkVariantData) variantScope.getVariantData(), variantScopesForLint); // Create the lint tasks, if enabled createLintTasks(variantScope, variantScopesForLint); taskFactory.register(new FeatureSplitTransitiveDepsWriterTask.CreationAction(variantScope)); createDynamicBundleTask(variantScope); }

我们可以聊聊变体。

在build.gradle里面可以使用flavorDimensions属性创建“mode”变种维度和“api”变种维度。

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    
    minApi24 {
      dimension "api"
      minSdkVersion 24
      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}

Gradle 创建的 build 变体数量等于每个变种维度中的变种数量与您配置的 build 类型数量的乘积。当 Gradle 为每个 build 变体或对应的 APK 命名时,先显示属于较高优先级变种维度的产品变种,接着是较低优先级维度中的产品变种,再接着是 build 类型。以上面的构建配置为例,Gradle 使用以下命名方案创建了总共 12 个 build 变体:

build 变体:[minApi24, minApi23, minApi21][Demo, Full][Debug, Release]

对应的 APK:app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk

你可能感兴趣的:(Gradle Plugin 源码分析)