浅谈build.gradle.kts编译脚本

为什么要深入学习build.gradle

作为Android开发者,很有必要深入学习下build.gradle,不要仅限于配置层面,一定要深入到代码层面。build.gradle是整个Android项目最重要的配置文件之一,它告诉编译器很多与编译有关的信息。并且我一再强调要使用build.gradle.kts替代build.gradle,它将有助于我们深入到代码层面。

build.gradle都有哪些东西

build.gradle主要分为三大块,plugins、dependencies和android。前两个都是用来下载和使用依赖,plugins主要是应用其他第三方的gradle插件,而dependencies用来下载与业务功能相关的第三方库。所有与编译相关的配置信息,都在android作用域下,这个我放在最后讲。

plugins(PluginDependenciesSpecScope)

kts 复制代码
plugins {
    id("com.android.application")
    id("kotlin-android")
    id("kotlin-kapt")
    id("com.google.gms.google-services")
    id("com.google.firebase.crashlytics")
}

plugins作用域里面apply了一些第三方gradle插件,和本身编译脚本是一类程序,它本质上也属于编译层面的东西。

dependencies(DependencyHandlerScope)

kts 复制代码
dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.10")
    implementation("androidx.appcompat:appcompat:1.2.0")
    implementation("androidx.constraintlayout:constraintlayout:2.0.4")
}

dependencies作用域里面配置的则是与应用或应用库有关的依赖,它属于业务层面的东西。虽然第三方库不直接完全属于业务,但它却常常作为业务层面的基础架构层,也不排除是一个完整的业务模块。

android(BaseAppModuleExtension)

我们看一眼BaseAppModuleExtension的源码,里面主要可以配置哪些东西。本文基于Gradle8.1.1,不能说最新,但也很新了。

kotlin 复制代码
package com.android.build.gradle.internal.dsl

import com.android.build.api.dsl.ApplicationAndroidResources
import com.android.build.api.dsl.ComposeOptions
import com.android.build.gradle.AppExtension
import com.android.build.gradle.api.AndroidSourceSet
import com.android.build.gradle.api.BaseVariantOutput
import com.android.build.gradle.internal.ExtraModelInfo
import com.android.build.gradle.internal.dependency.SourceSetManager
import com.android.build.gradle.internal.services.DslServices
import com.android.build.gradle.internal.tasks.factory.BootClasspathConfig
import com.android.builder.core.LibraryRequest
import com.android.repository.Revision
import org.gradle.api.NamedDomainObjectContainer

/** The `android` extension for base feature module (application plugin).  */
open class BaseAppModuleExtension(
    dslServices: DslServices,
    bootClasspathConfig: BootClasspathConfig,
    buildOutputs: NamedDomainObjectContainer<BaseVariantOutput>,
    sourceSetManager: SourceSetManager,
    extraModelInfo: ExtraModelInfo,
    private val publicExtensionImpl: ApplicationExtensionImpl
) : AppExtension(
    dslServices,
    bootClasspathConfig,
    buildOutputs,
    sourceSetManager,
    extraModelInfo,
    true
), InternalApplicationExtension by publicExtensionImpl {

    // Overrides to make the parameterized types match, due to BaseExtension being part of
    // the previous public API and not wanting to paramerterize that.
    override val buildTypes: NamedDomainObjectContainer<BuildType>
        get() = publicExtensionImpl.buildTypes as NamedDomainObjectContainer<BuildType>
    override val defaultConfig: DefaultConfig
        get() = publicExtensionImpl.defaultConfig as DefaultConfig
    override val productFlavors: NamedDomainObjectContainer<ProductFlavor>
        get() = publicExtensionImpl.productFlavors as NamedDomainObjectContainer<ProductFlavor>
    override val sourceSets: NamedDomainObjectContainer<AndroidSourceSet>
        get() = publicExtensionImpl.sourceSets

    override val composeOptions: ComposeOptions = publicExtensionImpl.composeOptions

    override val bundle: BundleOptions = publicExtensionImpl.bundle as BundleOptions

    override val flavorDimensionList: MutableList<String>
        get() = flavorDimensions

    override val buildToolsRevision: Revision
        get() = Revision.parseRevision(buildToolsVersion, Revision.Precision.MICRO)

    override val libraryRequests: MutableCollection<LibraryRequest>
        get() = publicExtensionImpl.libraryRequests

    override val androidResources: ApplicationAndroidResources
        get() = publicExtensionImpl.androidResources
}

很明显主要配置的有buildTypes、defaultConfig、productFlavors、sourceSets。其实你看到的这些还不全,你要看全的应该深入到它的基类。我们一直倒查它祖宗18代,依次是AppExtension、AbstractAppExtension、TestedExtension、BaseExtension。没错,BaseExtension正是我们想要找的。我们看一下BaseExtension的源码。

kotlin 复制代码
package com.android.build.gradle

import com.android.annotations.NonNull
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.BuildFeatures
import com.android.build.api.dsl.ComposeOptions
import com.android.build.api.dsl.DynamicFeatureExtension
import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.dsl.TestExtension
import com.android.build.api.transform.Transform
import com.android.build.api.variant.VariantFilter
import com.android.build.gradle.api.AndroidSourceSet
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.BaseVariantOutput
import com.android.build.gradle.api.ViewBindingOptions
import com.android.build.gradle.internal.CompileOptions
import com.android.build.gradle.internal.ExtraModelInfo
import com.android.build.gradle.internal.SourceSetSourceProviderWrapper
import com.android.build.gradle.internal.coverage.JacocoOptions
import com.android.build.gradle.internal.dependency.SourceSetManager
import com.android.build.gradle.internal.dsl.AaptOptions
import com.android.build.gradle.internal.dsl.AdbOptions
import com.android.build.gradle.internal.dsl.BuildType
import com.android.build.gradle.internal.dsl.DataBindingOptions
import com.android.build.gradle.internal.dsl.DefaultConfig
import com.android.build.gradle.internal.dsl.DexOptions
import com.android.build.gradle.internal.dsl.ExternalNativeBuild
import com.android.build.gradle.internal.dsl.LintOptions
import com.android.build.gradle.internal.dsl.Lockable
import com.android.build.gradle.internal.dsl.PackagingOptions
import com.android.build.gradle.internal.dsl.ProductFlavor
import com.android.build.gradle.internal.dsl.SigningConfig
import com.android.build.gradle.internal.dsl.Splits
import com.android.build.gradle.internal.dsl.TestOptions
import com.android.build.gradle.internal.dsl.ViewBindingOptionsImpl
import com.android.build.gradle.internal.errors.DeprecationReporter
import com.android.build.gradle.internal.services.DslServices
import com.android.build.gradle.internal.tasks.factory.BootClasspathConfig
import com.android.builder.core.LibraryRequest
import com.android.builder.errors.IssueReporter
import com.android.builder.model.SourceProvider
import com.android.builder.testing.api.DeviceProvider
import com.android.builder.testing.api.TestServer
import com.android.repository.Revision
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.Incubating
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.artifacts.Configuration
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.tasks.SourceSet
import java.io.File

/**
 * Base extension for all Android plugins.
 *
 * You don't use this extension directly. Instead, use one of the following:
 *
 * * [ApplicationExtension]: `android` extension for the `com.android.application` plugin
 *         used to create an Android app.
 * * [LibraryExtension]: `android` extension for the `com.android.library` plugin used to
 *         [create an Android library](https://developer.android.com/studio/projects/android-library.html)
 * * [TestExtension]: `android` extension for the `com.android.test` plugin used to create
 *         a separate android test project.
 * * [DynamicFeatureExtension]: `android` extension for the `com.android.feature` plugin
 *         used to create dynamic features.
 *
 * The following applies the Android plugin to an app project `build.gradle` file:
 *
 * ```
 * // Applies the application plugin and makes the 'android' block available to specify
 * // Android-specific build options.
 * apply plugin: 'com.android.application'
 * ```
 *
 * To learn more about creating and organizing Android projects, read
 * [Projects Overview](https://developer.android.com/studio/projects/index.html)
 */
// All the public methods are meant to be exposed in the DSL. We can't use lambdas in this class
// (yet), because the DSL reference generator doesn't understand them.
abstract class BaseExtension protected constructor(
    protected val dslServices: DslServices,
    protected val bootClasspathConfig: BootClasspathConfig,
    /** All build outputs for all variants, can be used by users to customize a build output. */
    override val buildOutputs: NamedDomainObjectContainer<BaseVariantOutput>,
    private val sourceSetManager: SourceSetManager,
    private val extraModelInfo: ExtraModelInfo,
    private val isBaseModule: Boolean
) : AndroidConfig, Lockable {

    private val _dexOptions = dslServices.newInstance(DexOptions::class.java)

    @Deprecated("Using dexOptions is obsolete.")
    override val dexOptions: DexOptions
        get() {
            dslServices.deprecationReporter.reportObsoleteUsage(
                "dexOptions",
                DeprecationReporter.DeprecationTarget.DEX_OPTIONS
            )
            return _dexOptions
        }

    private val deviceProviderList: MutableList<DeviceProvider> = Lists.newArrayList()
    private val testServerList: MutableList<TestServer> = Lists.newArrayList()

    @get:Incubating
    abstract val composeOptions: ComposeOptions

    abstract override val dataBinding: DataBindingOptions
    abstract val viewBinding: ViewBindingOptionsImpl

    override var defaultPublishConfig: String = "release"
        set(_) {
            dslServices.deprecationReporter.reportObsoleteUsage(
                    "defaultPublishConfig",
                    DeprecationReporter.DeprecationTarget.DEFAULT_PUBLISH_CONFIG
            )
        }

    override var variantFilter: Action<VariantFilter>? = null

    protected val logger: Logger = Logging.getLogger(this::class.java)

    private var isWritable = true

    /**
     * Disallow further modification on the extension.
     */
    fun disableWrite() {
        isWritable = false
        lock()
    }

    protected fun checkWritability() {
        if (!isWritable) {
            throw GradleException(
                "Android tasks have already been created.\n" +
                        "This happens when calling android.applicationVariants,\n" +
                        "android.libraryVariants or android.testVariants.\n" +
                        "Once these methods are called, it is not possible to\n" +
                        "continue configuring the model."
            )
        }
    }

    /** For groovy only (so `compileSdkVersion=2` works) */
    fun setCompileSdkVersion(apiLevel: Int) {
        compileSdkVersion(apiLevel)
    }

    open fun buildToolsVersion(version: String) {
        buildToolsVersion = version
    }

    open fun flavorDimensions(vararg dimensions: String) {
        checkWritability()
        flavorDimensionList.clear()
        flavorDimensionList.addAll(dimensions)
    }

    abstract fun sourceSets(action: Action<NamedDomainObjectContainer<AndroidSourceSet>>)

    abstract fun aaptOptions(action: Action<AaptOptions>)

    /**
     * Specifies options for the DEX tool, such as enabling library pre-dexing.
     *
     * For more information about the properties you can configure in this block, see [DexOptions].
     */
    @Deprecated("Setting dexOptions is obsolete.")
    fun dexOptions(action: Action<DexOptions>) {
        checkWritability()
        action.execute(dexOptions)
    }

    abstract fun lintOptions(action: Action<LintOptions>)

    abstract fun externalNativeBuild(action: Action<ExternalNativeBuild>)

    /**
     * Specifies options for how the Android plugin should run local and instrumented tests.
     *
     * For more information about the properties you can configure in this block, see [TestOptions].
     */
    abstract fun testOptions(action: Action<TestOptions>)

    abstract fun compileOptions(action: Action<CompileOptions>)

    abstract fun packagingOptions(action: Action<PackagingOptions>)

    abstract fun jacoco(action: Action<JacocoOptions>)

    /**
     * Specifies options for the
     * [Android Debug Bridge (ADB)](https://developer.android.com/studio/command-line/adb.html),
     * such as APK installation options.
     *
     * For more information about the properties you can configure in this block, see [AdbOptions].
     */
    abstract fun adbOptions(action: Action<AdbOptions>)

    abstract fun splits(action: Action<Splits>)

    /**
     * Specifies options for the
     * [Data Binding Library](https://developer.android.com/topic/libraries/data-binding/index.html).
     *
     * For more information about the properties you can configure in this block, see [DataBindingOptions]
     */
    abstract fun dataBinding(action: Action<DataBindingOptions>)

    /**
     * Specifies options for the View Binding lLibrary.
     *
     * For more information about the properties you can configure in this block, see [ViewBindingOptions].
     */
    abstract fun viewBinding(action: Action<ViewBindingOptionsImpl>)

    fun deviceProvider(deviceProvider: DeviceProvider) {
        checkWritability()
        deviceProviderList.add(deviceProvider)
    }

    override val deviceProviders: List<DeviceProvider>
        get() = deviceProviderList

    fun testServer(testServer: TestServer) {
        checkWritability()
        testServerList.add(testServer)
    }

    override val testServers: List<TestServer>
        get() = testServerList

    /**
     * The [Transform] API is planned to be removed in Android Gradle plugin 8.0.
     *
     * There is no single replacement. For more information about how to migrate, see
     * [https://developer.android.com/studio/releases/gradle-plugin-roadmap]
     */
    @Deprecated(
        "The transform API support has been removed in Android Gradle plugin 8.0."
    )
    fun registerTransform(transform: Transform, vararg dependencies: Any) {
        dslServices.deprecationReporter.reportRemovedApi(
            oldApiElement = "android.registerTransform",
            url = "https://developer.android.com/studio/releases/gradle-plugin-api-updates#transform-api",
            deprecationTarget = DeprecationReporter.DeprecationTarget.TRANSFORM_API
        )
    }

    override val transforms: List<Transform>
        get() = ImmutableList.of()

    override val transformsDependencies: List<List<Any>>
        get() = ImmutableList.of()

    open fun defaultPublishConfig(value: String) {
        defaultPublishConfig = value
    }

    fun setPublishNonDefault(publishNonDefault: Boolean) {
        logger.warn("publishNonDefault is deprecated and has no effect anymore. All variants are now published.")
    }

    @Deprecated("Use AndroidComponentsExtension.beforeVariants API to disable specific variants")
    open fun variantFilter(variantFilter: Action<VariantFilter>) {
        this.variantFilter = variantFilter
    }

    open fun resourcePrefix(prefix: String) {
        resourcePrefix = prefix
    }

    abstract fun addVariant(variant: BaseVariant)

    fun registerArtifactType(name: String, isTest: Boolean, artifactType: Int) {
        extraModelInfo.registerArtifactType(name, isTest, artifactType)
    }

    fun registerBuildTypeSourceProvider(
        name: String,
        buildType: BuildType,
        sourceProvider: SourceProvider
    ) {
        extraModelInfo.registerBuildTypeSourceProvider(name, buildType, sourceProvider)
    }

    fun registerProductFlavorSourceProvider(
        name: String,
        productFlavor: ProductFlavor,
        sourceProvider: SourceProvider
    ) {
        extraModelInfo.registerProductFlavorSourceProvider(name, productFlavor, sourceProvider)
    }

    fun registerJavaArtifact(
        name: String,
        variant: BaseVariant,
        assembleTaskName: String,
        javaCompileTaskName: String,
        generatedSourceFolders: MutableCollection<File>,
        ideSetupTaskNames: Iterable<String>,
        configuration: Configuration,
        classesFolder: File,
        javaResourceFolder: File,
        sourceProvider: SourceProvider
    ) {
        extraModelInfo.registerJavaArtifact(
            name, variant, assembleTaskName,
            javaCompileTaskName, generatedSourceFolders, ideSetupTaskNames,
            configuration, classesFolder, javaResourceFolder, sourceProvider
        )
    }

    fun registerMultiFlavorSourceProvider(
        name: String,
        flavorName: String,
        sourceProvider: SourceProvider
    ) {
        extraModelInfo.registerMultiFlavorSourceProvider(name, flavorName, sourceProvider)
    }

    @NonNull
    fun wrapJavaSourceSet(sourceSet: SourceSet): SourceProvider {
        return SourceSetSourceProviderWrapper(sourceSet)
    }

    /**
     * The path to the Android SDK that Gradle uses for this project.
     *
     * To learn more about downloading and installing the Android SDK, read
     * [Update Your Tools with the SDK Manager](https://developer.android.com/studio/intro/update.html#sdk-manager)
     */
    val sdkDirectory: File
        get() {
            return dslServices.sdkComponents.flatMap { it.sdkDirectoryProvider }.get().asFile
        }

    /**
     * The path to the [Android NDK](https://developer.android.com/ndk/index.html) that Gradle uses for this project.
     *
     * You can install the Android NDK by either
     * [using the SDK manager](https://developer.android.com/studio/intro/update.html#sdk-manager)
     * or downloading
     * [the standalone NDK package](https://developer.android.com/ndk/downloads/index.html).
     */
    val ndkDirectory: File
        get() {
        // do not call this method from within the plugin code as it forces part of SDK initialization.
            return dslServices.sdkComponents.map {
                it.versionedNdkHandler(
                    compileSdkVersion
                        ?: throw kotlin.IllegalStateException("compileSdkVersion not set in the android configuration"),
                    ndkVersion,
                    ndkPath
                ).ndkPlatform.getOrThrow().ndkDirectory
            }.get()
    }

    // do not call this method from within the plugin code as it forces SDK initialization.
    // once this method is removed, remember to protect the bootClasspathConfig.bootClasspath against
    // unsafe read.
    override val bootClasspath: List<File>
        get() = try {
            bootClasspathConfig.bootClasspath.get().map { it.asFile }
        } catch (e: IllegalStateException) {
            listOf()
        }

    /**
     * The path to the
     * [Android Debug Bridge (ADB)](https://developer.android.com/studio/command-line/adb.html)
     * executable from the Android SDK.
     */
    @Suppress("DEPRECATION")
    val adbExecutable: File
        get() {
            return dslServices.versionedSdkLoaderService.versionedSdkLoader.flatMap {
                it.adbExecutableProvider }.get().asFile
        }

    /** This property is deprecated. Instead, use [adbExecutable]. */
    @Deprecated("This property is deprecated", ReplaceWith("adbExecutable"))
    val adbExe: File
        get() {
            return adbExecutable
        }

    open fun getDefaultProguardFile(name: String): File {
        if (!ProguardFiles.KNOWN_FILE_NAMES.contains(name)) {
            dslServices
                .issueReporter
                .reportError(
                    IssueReporter.Type.GENERIC, ProguardFiles.UNKNOWN_FILENAME_MESSAGE
                )
        }
        return ProguardFiles.getDefaultProguardFile(name, dslServices.buildDirectory)
    }

    // ---------------
    // TEMP for compatibility

    /** {@inheritDoc} */
    override var generatePureSplits: Boolean
        get() = false
        set(_) = logger.warn(
            "generatePureSplits is deprecated and has no effect anymore. Use bundletool to generate configuration splits."
        )

    @get:Suppress("WrongTerminology")
    @Deprecated("Use aidlPackagedList instead", ReplaceWith("aidlPackagedList"))
    override val aidlPackageWhiteList: MutableCollection<String>?
        get() = aidlPackagedList

    override val aidlPackagedList: MutableCollection<String>?
        get() = throw GradleException("aidlPackagedList is not supported.")

    // For compatibility with FeatureExtension.
    override val baseFeature: Boolean
        get() = isBaseModule

    @Incubating
    abstract fun composeOptions(action: Action<ComposeOptions>)

    abstract fun compileSdkVersion(version: String)

    abstract fun compileSdkVersion(apiLevel: Int)

    // Kept for binary and source compatibility until the old DSL interfaces can go away.
    abstract override val flavorDimensionList: MutableList<String>

    abstract override var resourcePrefix: String?

    abstract override var ndkVersion: String?

    abstract var ndkPath: String?

    abstract override var buildToolsVersion: String

    abstract override val buildToolsRevision: Revision

    abstract override val libraryRequests: MutableCollection<LibraryRequest>

    abstract fun useLibrary(name: String)
    abstract fun useLibrary(name: String, required: Boolean)

    abstract override val aaptOptions: AaptOptions

    abstract override val adbOptions: AdbOptions

    abstract override val buildTypes: NamedDomainObjectContainer<BuildType>
    abstract fun buildTypes(action: Action<in NamedDomainObjectContainer<BuildType>>)

    abstract override val compileOptions: CompileOptions

    abstract override var compileSdkVersion: String?

    abstract override val defaultConfig: DefaultConfig
    abstract fun defaultConfig(action: Action<DefaultConfig>)

    abstract override val externalNativeBuild: ExternalNativeBuild

    abstract override val jacoco: JacocoOptions

    abstract override val lintOptions: LintOptions

    abstract override val packagingOptions: PackagingOptions

    abstract override val productFlavors: NamedDomainObjectContainer<ProductFlavor>
    abstract fun productFlavors(action: Action<NamedDomainObjectContainer<ProductFlavor>>)

    abstract override val signingConfigs: NamedDomainObjectContainer<SigningConfig>
    abstract fun signingConfigs(action: Action<NamedDomainObjectContainer<SigningConfig>>)

    abstract override val sourceSets: NamedDomainObjectContainer<AndroidSourceSet>

    abstract override val splits: Splits

    abstract override val testOptions: TestOptions

    // these are indirectly implemented by extensions when they implement the new public
    // extension interfaces via delegates.
    abstract val buildFeatures: BuildFeatures
    abstract var namespace: String?
}

发现它的属性都是我们要学习的,但重点是以下这些。

namespace

指定命名空间,高版本gradle强制使用,它取代了applicationId。

buildToolsVersion

指定构建工具版本号。

ndkVersion

指定NDK版本。

ndkPath

指定NDK路径。

resourcePrefix

校验资源前缀。主要校验xml资源,无法校验图片资源。它的方法大部分也都是我们要学习的,后面我会讲解。

defaultConfig(ApplicationDefaultConfig)

defaultConfig它是所有flavor变体的默认配置。它的顶级接口是ProductFlavor。

kotlin 复制代码
package com.android.builder.model

/**
 * a Product Flavor. This is only the configuration of the flavor.
 *
 * This is an interface for the gradle tooling api, and should only be used from Android Studio.
 * It is not part of the DSL & API interfaces of the Android Gradle Plugin.
 *
 * It does not include the sources or the dependencies. Those are available on the container
 * or in the artifact info.
 *
 * @see ProductFlavorContainer
 *
 * @see BaseArtifact.getDependencies
 */
interface ProductFlavor : BaseConfig, DimensionAware {
    /** The name of the flavor. */
    override fun getName(): String

    /**
     * The name of the product flavor. This is only the value set on this product flavor.
     * To get the final application id name, use [AndroidArtifact.getApplicationId].
     */
    val applicationId: String?

    /**
     * The version code associated with this flavor or null if none have been set.
     * This is only the value set on this product flavor, not necessarily the actual
     * version code used.
     */
    val versionCode: Int?

    /** The version name. This is only the value set on this product flavor.
     * To get the final value, use [Variant.getMergedFlavor] with
     * [.getVersionNameSuffix] and [BuildType.getVersionNameSuffix].
     */
    val versionName: String?

    /** The minSdkVersion, or null if not specified. This is only the value set on this product flavor. */
    val minSdkVersion: ApiVersion?

    /** The targetSdkVersion, or null if not specified. This is only the value set on this product flavor. */
    val targetSdkVersion: ApiVersion?

    /** The maxSdkVersion, or null if not specified. This is only the value set on this produce flavor. */
    val maxSdkVersion: Int?

    /**
     * The renderscript target api, or null if not specified. This is only the value set on this product flavor.
     * TODO: make final renderscript target api available through the model
     */
    val renderscriptTargetApi: Int?

    /**
     * Whether the renderscript code should be compiled in support mode to
     * make it compatible with older versions of Android.
     *
     * True if support mode is enabled, false if not, and null if not specified.
     */
    val renderscriptSupportModeEnabled: Boolean?

    /**
     * Whether the renderscript BLAS support lib should be used to
     * make it compatible with older versions of Android.
     *
     * True if BLAS support lib is enabled, false if not, and null if not specified.
     */
    val renderscriptSupportModeBlasEnabled: Boolean?

    /**
     * Whether the renderscript code should be compiled to generate C/C++ bindings.
     * True for C/C++ generation, false for Java, null if not specified.
     */
    val renderscriptNdkModeEnabled: Boolean?

    /**
     * The test application id. This is only the value set on this product flavor.
     * To get the final value, use [Variant.getExtraAndroidArtifacts] with
     * [AndroidProject.ARTIFACT_ANDROID_TEST] and then
     * [AndroidArtifact.getApplicationId]
     */
    val testApplicationId: String?

    /**
     * The test instrumentation runner. This is only the value set on this product flavor.
     * TODO: make test instrumentation runner available through the model.
     */
    val testInstrumentationRunner: String?

    /** The arguments for the test instrumentation runner.*/
    val testInstrumentationRunnerArguments: Map<String, String>

    /** The handlingProfile value. This is only the value set on this product flavor. */
    val testHandleProfiling: Boolean?

    /** The functionalTest value. This is only the value set on this product flavor. */
    val testFunctionalTest: Boolean?

    /**
     * The resource configuration for this variant.
     *
     * This is the list of -c parameters for aapt.
     */
    val resourceConfigurations: Collection<String>

    val vectorDrawables: VectorDrawablesOptions
    /**
     *  Whether to enable unbundling mode for embedded wear app.
     *
     * If true, this enables the app to transition from an embedded wear app to one
     * distributed by the play store directly.
     */
    val wearAppUnbundled: Boolean?
}

ProductFlavor重点关注applicationId、versionCode、versionName、minSdkVersion、targetSdkVersion、maxSdkVersion这几个属性,原先都来自于清单文件AndroidManifest.xml。

NamedDomainObjectContainer和NamedDomainObjectCollection

NamedDomainObjectContainer虽然不属于android作用域下的一个配置项,但也很重要。你要用它的create方法来创建一个配置项的名称。同样你可以通过NamedDomainObjectCollection的getByName方法来拿到一个已经创建好的配置项的名称。

kotlin 复制代码
productFlavors {
      create("dev") {
            dimension = "app"
            applicationIdSuffix ".dev"
            versionNameSuffix = "-dev"
      }
      create("alpha") {
            dimension = "app"
            applicationIdSuffix ".alpha"
            versionNameSuffix = "-alpha"
      }
      create("beta") {
            dimension = "app"
            versionNameSuffix = "-beta"
      }
}

sourceSets {
    getByName("main") {
        jniLibs.srcDirs("libs")
    }
}

productFlavor(ApplicationProductFlavor)

productFlavor用来区分不同变体特异的配置,比如不同的渠道包的应用名称、包名、版本号、域名等配置。

kotlin 复制代码
dimension = "app"
versionNameSuffix = "-beta"
buildConfigField("String", "BUGLY_APP_ID", ""3278336e37"")
buildConfigField("boolean", "ENCRYPT_MESSAGE", "true")
buildConfigField("String", "SERVER_URL", ""http://dorachat.com:9090/"")
buildConfigField("String", "WS_URL", ""ws://dorachat.com:9090/websocket/"")

sourceSets(AndroidSourceSet)

sourceSets用来一些资源等编译目录,让代码结构更加灵活。

buildFeatures(ApplicationBuildFeatures)

buildFeatures用来配置一些特性,比如是否使用databinding、aidl、compose、buildConfig等。 如果你需要在某个变体下依赖第三方库,你需要开启buildConfig。

kotlin 复制代码
dependencies {
        dependencies.add("betaImplementation", platform("com.google.firebase:firebase-bom:30.2.0"))
        dependencies.add("betaImplementation", "com.google.firebase:firebase-crashlytics-ktx")
        dependencies.add("betaImplementation", "com.google.firebase:firebase-analytics-ktx")
        dependencies.add("betaImplementation", "com.google.firebase:firebase-config-ktx")
        dependencies.add("betaImplementation", "com.google.firebase:firebase-analytics-ktx")
}

buildTypes(ApplicationBuildType)

buildTypes则是用来区分debug和release包的混淆、是否可debugdebug以及签名的差异性。

kotlin 复制代码
signingConfigs {
    create("official") {
        storeFile = File("../doramusic.jks")
        keyAlias = "key0"
        keyPassword = "123456"
        storePassword = "123456"
    }
}
buildTypes {
    release {
        isMinifyEnabled = true
        isDebuggable = false
        isShrinkResources = true
        signingConfig = signingConfigs.getByName("official")
        proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
    }
}

compileOptions(CompileOptions)

compileOptions用来指定生成的java字节码版本。

49 = Java 5

50 = Java 6

51 = Java 7

52 = Java 8

53 = Java 9

54 = Java 10

55 = Java 11

56 = Java 12

57 = Java 13

58 = Java 14

59 = Java 15

60 = Java 16

61 = Java 17

62 = Java 18

63 = Java 19

64 = Java 20

splits(Splits)

splits用来指定要编译出的动态库。

kotlin 复制代码
splits {
    abi {
        isEnable = true
        reset()
        include("x86", "x86_64", "armeabi-v7a", "arm64-v8a")
        // select ABIs to build APKs for
        isUniversalApk = true
        // generate an additional APK that contains all the ABIs
    }
}

externalNativeBuild(ExternalNativeBuild)

externalNativeBuild用来指定NDK开发中native原生代码编译配置CMake文件的路径。

kotlin 复制代码
externalNativeBuild {
    cmake {
        path = file("src/main/cpp/CMakeLists.txt")
        version = "3.18.1"
    }
}

总结

我这里只是简单讲解了一些主要的配置代码,你在实际的项目开发中可能还需要自行研究Gradle Kotlin DSL的更多源码以满足不同的编译需要。当你迈出了将build.gradle转化为build.gradle.kts这关键的一步,你离熟练掌握Gradle构建脚本就很近了。当然你也要常常关注Gradle的最新变化,最后附上Gradle的官方文档地址,docs.gradle.org/current/use... ,祝你好运。

相关推荐
温辉_xh15 分钟前
uiautomator案例
android
工业甲酰苯胺1 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
少说多做3432 小时前
Android 不同情况下使用 runOnUiThread
android·java
Estar.Lee3 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
找藉口是失败者的习惯4 小时前
从传统到未来:Android XML布局 与 Jetpack Compose的全面对比
android·xml
Jinkey5 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
大白要努力!7 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟7 小时前
Android音频采集
android·音视频
小白也想学C9 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程9 小时前
初级数据结构——树
android·java·数据结构