一文搞懂 Gradle 配置,7.0之后有哪些变化?
本文作者
作者:yechaoa
链接:
https://juejin.cn/post/7160337743552675847
本文由作者授权发布。
看文之前,有个请求哈,最近掘金正在举办年度人力榜单投票,目前Android 唯一一个有可能进前 10 的作者:yechaoa,也是我之前给大家推荐的BaguTree每周六分享的组织者之一,辛苦大家扫码投票支持一下,让安卓人冲击个前 10,重铸安卓荣光(注意每人可以投很多票,可以多点几次,么么哒)。
也可以点击左下角阅读原文访问
“Gradle的配置太多了,经常版本更新还有变化,而且它还能扩展,记是记不住了,只能用到再搜了,哎,难顶”
Gradle配置简介 Gradle中的配置有哪些,都是用来干什么的,以及7.0版本之后的变化; Gradle中的配置怎么来的;
前置必读:
https://juejin.cn/post/7155109977579847710
Gradle的配置主要是用来管理Gradle自己的运行环境和我们的项目,这句话听起来有点抽象,用大白话拆解一下:
2.1、配置的优先级
Command-line flags:命令行标志,如--stacktrace,这些优先于属性和环境变量; System properties:系统属性,如systemProp.http.proxyHost=somehost.org存储在gradle.properties文件中; Gradle properties:Gradle属性,如org.gradle.caching=true,通常存储在项目根目录或GRADLE_USER_HOME环境变量中的gradle.properties文件中; Environment variables:环境变量,如GRADLE_OPTS,由执行Gradle的环境源;
2.2、项目初始配置
Android Studio Dolphin | 2021.3.1 Gradle 7.4
.
├── README.md
├── app
│ ├── build.gradle
│ ├── ...
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── local.properties
└── settings.gradle
3.1、gradle-wrapper
.
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
gradle-wrapper.jar:主要是Gradle的运行逻辑,包含下载Gradle; gradle-wrapper.properties:gradle-wrapper的配置文件,核心是定义了Gradle版本; gradlew:gradle wrapper的简称,linux下的执行脚本 gradlew.bat:windows下的执行脚本
#Sun Oct 16 15:59:36 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
distributionBase:下载的Gradle的压缩包解压后的主目录; zipStoreBase:同distributionBase,不过是存放zip压缩包的主目录; distributionPath:相对于distributionBase的解压后的Gradle的路径,为wrapper/dists; zipStorePath:同distributionPath,不过是存放zip压缩包的; distributionUrl:Gradle版本的下载地址;
Gradle版本的下载地址,可以查看Gradle官方的版本发布,或者去Gradle的Github。
https://services.gradle.org/distributions/
https://github.com/gradle/gradle/releases
doc:顾名思义,用户文档; bin:即binary,可运行并不包含多余的东西; all:包含所有,除了bin之外还有用户文档、sample等;
Gradle、Android Gradle Plugin、Android Studio三者的版本映射关系查看Android官网Gradle版本说明。
https://developer.android.google.cn/studio/releases/gradle-plugin?hl=zh-cn#updating-gradle
3.2、build.gradle(Project)
3.2.1、7.0之后
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.3.0' apply false
id 'com.android.library' version '7.3.0' apply false
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
}
id «plugin id» version «plugin version» [apply «false»]
plugins {
id "yechaoa" version "1.0.0" apply false
}
subprojects { subproject ->
if (subproject.name == "subProject") {
apply plugin: 'yechaoa'
}
}
apply plugin: 'kotlin-android'
// 加上下面
buildscript {
...
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20"
}
}
apply from: 'common.gradle'
apply plugin:'yechaoa':叫做二进制插件,二进制插件一般都是被打包在一个jar里独立发布的,比如我们自定义的插件,再发布的时候我们也可以为其指定plugin id,这个plugin id最好是一个全限定名称,就像你的包名一样; apply from:'yechaoa.gradle':叫做应用脚本插件,应用脚本插件,其实就是把这个脚本加载进来,和二进制插件不同的是它使用的是from关键字,后面紧跟一个脚本文件,可以是本地的,也可以是网络存在的,如果是网络上的话要使用HTTP URL。 虽然它不是一个真正的插件,但是不能忽视它的作用,它是脚本文件模块化的基础,我们可以把庞大的脚本文件进行分块、分段整理拆分成一个个共用、职责分明的文件,然后使用apply from来引用它们,比如我们可以把常用的函数放在一个utils.gradle脚本里,供其他脚本文件引用。
后面的文章也会讲到插件的依赖管理。
3.2.1、7.0之前
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.5.0"
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
jcenter() // Warning: this repository is going to shut down soon
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
buildscript
ext
repositories
dependencies
allprojects
task clean(type: Delete)
3.3、build.gradle(Module)
3.2.1、7.0之后
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.yechaoa.gradlex'
compileSdk 32
defaultConfig {
applicationId "com.yechaoa.gradlex"
minSdk 23
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}3.3.1、7.0之前
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.yechaoa.app"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.2.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'
implementation "com.google.android.material:material:1.3.0"
implementation project(':yutils')
implementation project(':yutilskt')
}
plugins/apply plugin
namespace
com.android.application
App插件id:com.android.application Library插件id:com.android.library Kotlin插件id:org.jetbrains.kotlin.android
android{}
compileSdkVersion/compileSdk
(api等级对应关系)
https://blog.csdn.net/yechaoa/article/details/83011869?spm=1001.2014.3001.5502
buildToolsVersion
defaultConfig{}
applicationId
minSdkVersion/minSdk
targetSdkVersion/targetSdk
versionCode
versionName
multiDexEnabled
ndk{}
sourceSets
buildTypes
buildTypes {
debug {
buildConfigField("String", "AUTHOR", ""yechaoa"")
minifyEnabled false
}
release {
buildConfigField("String", "AUTHOR", ""yechaoa"")
signingConfig signingConfigs.release
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
name:build type的名字。 applicationIdSuffix:应用id后缀。 versionNameSuffix:版本名称后缀。 debuggable:是否生成一个debug的apk。 minifyEnabled:是否混淆。 proguardFiles:混淆文件。 signingConfig:签名配置。 manifestPlaceholders:清单占位符。 shrinkResources:是否去除未利用的资源,默认false,表示不去除。 zipAlignEnable:是否使用zipalign工具压缩。 multiDexEnabled:是否拆成多个Dex。 multiDexKeepFile:指定文本文件编译进主Dex文件中。 multiDexKeepProguard:指定混淆文件编译进主Dex文件中。
signingConfigs
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
v1SigningEnabled true
v2SigningEnabled true
}
}
productFlavors
buildConfigField
Build Variants
buildFeatures
buildFeatures {
viewBinding = true
// dataBinding = true
}
dexOptions{}
compileOptions
kotlinOptions
composeOptions
lintOptions
用于配置lint选项。Example
https://developer.android.com/reference/tools/gradle-api/4.1/com/android/build/api/dsl/LintOptions
dependencies{}
compile > implementation/api androidTestCompile > androidTestImplementation testCompile > testImplementation instrumentTest > androidTest
implementation 'androidx.core:core-ktx:1.7.0'
implementation和api的区别
图源:19snow93
3.4、settings.gradle
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "GradleX"
include ':app'
pluginManagement
dependencyResolutionManagement
rootProject.name
include
3.5、gradle.properties
Gradle本身配置
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# ---------- 编译相关 start ----------
#并行编译
org.gradle.parallel=true
#构建缓存
org.gradle.caching=true
# ---------- 编译相关 end ----------
版本管理
# ---------- 版本相关 start ----------
yechaoaPluginVersion="1.0.0"
# ---------- 版本相关 end ----------
pluginManagement {
plugins {
id 'com.yechaoa.gradlex' version "${yechaoaPluginVersion}"
}
}
3.6、local.properties
本地配置
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Feb 08 19:07:41 CST 2021
sdk.dir=/Users/yechao/Library/Android/sdk
ndk.dir=/Users/yechao/Library/Android/ndk
sdk.dir:SDK 的路径。 ndk.dir:NDK 的路径,已废弃,用SDK目录下的NDK目录。
环境管理
isRelease=true
#isDebug=false
#isH5Debug=false前面介绍了这么多的Gradle配置,最常用的就是app > build.gradle了,这个文件里的配置是最多的,也是跟Android开发打交道最多的,那么,这些配置是哪里来的呢?
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.yechaoa.gradlex'
compileSdk 32
defaultConfig {
applicationId "com.yechaoa.gradlex"
minSdk 23
targetSdk 32
versionCode 1
versionName "1.0"
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
}
在上一篇入门文章中我们讲到,Gradle是一个通用的自动化构建工具,通用也就是说,不仅可以构建Android项目,还可以构建java、kotlin、swift等项目。再结合android{}里面的配置属性,我们可以确定,那这就是Android项目专属的配置DSL了。
https://juejin.cn/post/7155109977579847710
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
implementation "com.android.tools.build:gradle:7.4"
BaseAppModuleExtension com.android.build.gradle.internal.dsl Closure org.gradle.api.Project
@HasInternalProtocol
public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
...
/**
* <p>Configures the dependencies for this project.
*
* <p>This method executes the given closure against the {@link DependencyHandler} for this project. The {@link
* DependencyHandler} is passed to the closure as the closure's delegate.
*
* <h3>Examples:</h3>
* See docs for {@link DependencyHandler}
*
* @param configureClosure the closure to use to configure the dependencies.
*/
void dependencies(Closure configureClosure);
...
}
android(Closure configuration)
/** 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
}
/** Gradle plugin class for 'application' projects, applied on the base application module */
public class AppPlugin extends AbstractAppPlugin<...> {
//...
@NonNull
@Override
protected ExtensionData<...> createExtension(...) {
// ...
if (getProjectServices().getProjectOptions().get(BooleanOption.USE_NEW_DSL_INTERFACES)) {
// noinspection unchecked,rawtypes: Hacks to make the parameterized types make sense
Class<ApplicationExtension> instanceType = (Class) BaseAppModuleExtension.class;
BaseAppModuleExtension android =
(BaseAppModuleExtension)
project.getExtensions()
.create(
new TypeOf<ApplicationExtension>() {},
"android",
instanceType,
dslServices,
bootClasspathConfig,
buildOutputs,
dslContainers.getSourceSetManager(),
extraModelInfo,
applicationExtension);
project.getExtensions()
.add(
BaseAppModuleExtension.class,
"_internal_legacy_android_extension",
android);
initExtensionFromSettings(applicationExtension);
return new ExtensionData<>(android, applicationExtension, bootClasspathConfig);
}
BaseAppModuleExtension android =
project.getExtensions()
.create(
"android",
BaseAppModuleExtension.class,
dslServices,
bootClasspathConfig,
buildOutputs,
dslContainers.getSourceSetManager(),
extraModelInfo,
applicationExtension);
initExtensionFromSettings(android);
return new ExtensionData<>(android, applicationExtension, bootClasspathConfig);
}
//...
}
其实所有的DSL配置都是通过插件的方式引入的。
通过依赖'com.android.application'插件,有了android{}这个配置DSL; 一个项目对应一个Project对象,Project对象里面包含dependencies函数; android{}这个配置DSL点进去就是Project对象里面dependencies这个函数,二者都接收一个闭包; 然后通过DependencyHandler这个类,执行android(Closure configuration)这个闭包并委托给dependencies(Closure configureClosure),也就是Project对象; 最后Gradle在执行阶段去解析这个Project对象并拿到android{}里面的配置参数,后面就是执行Task等等;
源码部分对新手可能有点不太友好,闭包、DSL、Plugin这些概念可能暂时还不太好理解,不过不用担心,后面会继续讲到,先了解下大致流程就行~
Github:
参考文档
Build Environment
https://docs.gradle.org/current/userguide/build_environment.html
彻底弄明白Gradle相关配置
https://blog.csdn.net/yechaoa/article/details/80484468
Configure your build
https://developer.android.com/studio/build
build api dsl
https://developer.android.com/reference/tools/gradle-api/4.1/com/android/build/api/dsl/AaptOptions
Gradle入门教程
https://www.bilibili.com/video/BV1DE411Z7nt/?p=1
Gradle的快速入门学习
https://juejin.cn/post/6844904200120303623
Mastering Gradle
https://juejin.cn/book/6844733819363262472
upgrading_version_6
https://docs.gradle.org/current/userguide/upgrading_version_6.html
apply plugin和plugins两种应用gradle插件的区别
https://huangxshuo.github.io/2021/03/04/apply%20plugin%E5%92%8Cplugins%E4%B8%A4%E7%A7%8D%E5%BA%94%E7%94%A8gradle%E6%8F%92%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB/
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!