解决方案

【Gradle-2】一文搞懂Gradle配置

seo靠我 2023-09-25 21:06:44

1、前言

“Gradle的配置太多了,经常版本更新还有变化,而且它还能扩展,记是记不住了,只能用到再搜了,哎,难顶”

真的难顶,但是我想挑战一下…

本文介绍的重点:

Gradle配置简介Gradle中的配置有SEO靠我哪些,都是用来干什么的,以及7.0版本之后的变化;Gradle中的配置怎么来的;

前置必读:https://blog.csdn.net/yechaoa/article/details/130174456SEO靠我

2、Gradle配置简介

Gradle的配置主要是用来管理Gradle自己的运行环境和我们的项目,这句话听起来有点抽象,用大白话拆解一下:

第一点其实很好理解,比如Gradle需要java11的运行环境,SEO靠我再比如我们为了加快编译而给Gradle设置更大的运行空间org.gradle.jvmargs=-Xmx2048m等,这类配置往往相对固定的,因为它是跟随项目走的,即使是多团队协作,大家基本也都是用的同SEO靠我一个环境。第二点,Gradle作为构建工具,主要是帮助我们编译打包apk的,apk是由各种文件组成的,比较多见的是代码文件和资源文件,那其实可以理解为Gradle本质上是在帮我们管理这些散落在各处的文SEO靠我件,比如代码文件有app目录下的源码、module、还有依赖的jar和aar等等,而配置可以决定我们依赖哪些代码,也可以决定哪些代码进入merge,以及打出来的apk产物是release还是debugSEO靠我,但是这类配置往往并不是固定不变的,它是根据开发人员的需求走的,比如提测用debug包,发布用release包,针对厂商适配可能还要再定制一个渠道包,又或者我需要修改一下版本号等等,这些都是通过配置来SEO靠我改的,具有一定的动态可配性。

2.1、配置的优先级

为什么会有优先级的说法呢,是因为Gradle的配置不仅丰富,而且渠道还不是单一的,这种渠道的不单一,也说明了Gradle优秀的扩展性和定制性。

比如我们要SEO靠我运行编译,既可以用Android Studio自带的可视快捷按钮,也可以使用命令行,而这两种编译方式的取配置是不一样的(根据优先级),那自然编译的结果也不一样,所以搞清楚配置的优先级也能帮助我们在不同SEO靠我场景下的使用需求。

优先级分以下4种(由高到低):

Command-line flags:命令行标志,如–stacktrace,这些优先于属性和环境变量;System properties:系统属性,如sSEO靠我ystemProp.http.proxyHost=somehost.org存储在gradle.properties文件中;Gradle properties:Gradle属性,如org.gradle.SEO靠我caching=true,通常存储在项目根目录或GRADLE_USER_HOME环境变量中的gradle.properties文件中;Environment variables:环境变量,如GRADLSEO靠我E_OPTS,由执行Gradle的环境源;

以上4种,我们较常用的是命令行标志和项目根目录的gradle.properties文件。

2.2、项目初始配置

Android Studio Dolphin | SEO靠我2021.3.1

Gradle 7.4

看一下新建项目之后的初始配置:

有两个一级目录,分别是app和Gradle Scripts,Gradle Scripts里面除了proguard-rules.pro用SEO靠我于混淆之外,其余的6个文件配置今天都会介绍到。

为了把这些文件的关系看的更直观一点,打印个tree看看:

. ├── README.md ├── app │SEO靠我 ├── build.gradle │ ├── ... ├── build.gradle ├── gradle │ └── wrappeSEO靠我r │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properSEO靠我ties ├── local.properties └── settings.gradle

3、Gradle配置

3.1、gradle-wrapper

. ├SEO靠我── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properSEO靠我ties ├── gradlew └── gradlew.bat

顾名思义,wrapper是对Gradle的一层封装,封装的意义在于可以使Gradle的版本跟着项目走,这SEO靠我样这个项目就可以很方便的在不同的设备上运行,比如开源项目一般都不会把gradle文件夹设置到gitignore文件里,就是为了保证你clone下来是可以运行的,在团队协作上也是如此。

下面介绍一下上面这SEO靠我几个文件的作用:

gradle-wrapper.jar:主要是Gradle的运行逻辑,包含下载Gradle;gradle-wrapper.properties:gradle-wrapper的配置文件,核SEO靠我心是定义了Gradle版本;gradlew:gradle wrapper的简称,linux下的执行脚本gradlew.bat:windows下的执行脚本

重点看一下gradle-wrapper.propSEO靠我erties:

#Sun Oct 16 15:59:36 CST 2022 distributionBase=GRADLE_USER_HOME distributionUSEO靠我rl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionPath=wrapper/diSEO靠我sts zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME distributionBaSEO靠我se:下载的Gradle的压缩包解压后的主目录;zipStoreBase:同distributionBase,不过是存放zip压缩包的主目录;distributionPath:相对于distributSEO靠我ionBase的解压后的Gradle的路径,为wrapper/dists;zipStorePath:同distributionPath,不过是存放zip压缩包的;distributionUrl:GraSEO靠我dle版本的下载地址;

Gradle版本的下载地址,可以查看Gradle官方的版本发布,或者去Gradle的Github。

这里有几种类型,分别是all、bin、doc:doc:顾名思义,用户文档;binSEO靠我:即binary,可运行并不包含多余的东西;all:包含所有,除了bin之外还有用户文档、sample等;

所以一般选择bin就可以了。

Gradle、Android Gradle Plugin、AndrSEO靠我oid Studio三者的版本映射关系查看Android官网Gradle版本说明。

AGP > Gradle: AS > AGP:

3.2、build.gradle(Project)

位于项目的根目录下,用于SEO靠我定义适用于项目中所有模块的依赖项。

3.2.1、7.0之后

Gradle7.0之后,project下的build.gradle文件变动很大,默认只有plugin的引用了,其他原有的配置挪到settingsSEO靠我.gradle文件中了。

// Top-level build file where you can add configuration options common to all sub-projecSEO靠我ts/modules. plugins {id com.android.application version 7.3.0 apply falseid com.android.librSEO靠我ary version 7.3.0 apply falseid org.jetbrains.kotlin.android version 1.7.10 apply false }

pluSEO靠我gin格式:

id «plugin id» version «plugin version» [apply «false»]

id和version比较好理解。

apply false表示不将该plugin应SEO靠我用于当前项目,比如在多项目构建中,我只想在某个子项目依赖该plugin就好了,那可以这么写:plugins {id "yechaoa" version "1.0.0" apply false SEO靠我 }subprojects { subproject ->if (subproject.name == "subProject") {apply plugin: yechaoa} SEO靠我 }

apply plugin在7.0之前的写法:

apply plugin: kotlin-android// 加上下面buildscript {...dependencies {classpath "SEO靠我org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20"} }

除了自带插件和远端插件之外,还可以是我们自定义的脚本插件,比如自定义了一个comSEO靠我mon.gradle

apply from: common.gradle

这两种方式的区别:

apply plugin:‘yechaoa’:叫做二进制插件,二进制插件一般都是被打包在一个jar里独立发布的,SEO靠我比如我们自定义的插件,再发布的时候我们也可以为其指定plugin id,这个plugin id最好是一个全限定名称,就像你的包名一样;apply from:‘yechaoa.gradle’:叫做应用脚SEO靠我本插件,应用脚本插件,其实就是把这个脚本加载进来,和二进制插件不同的是它使用的是from关键字,后面紧跟一个脚本文件,可以是本地的,也可以是网络存在的,如果是网络上的话要使用HTTP URL。 虽然它SEO靠我不是一个真正的插件,但是不能忽视它的作用,它是脚本文件模块化的基础,我们可以把庞大的脚本文件进行分块、分段整理拆分成一个个共用、职责分明的文件,然后使用apply from来引用它们,比如我们可以把常SEO靠我用的函数放在一个utils.gradle脚本里,供其他脚本文件引用。

后面的文章也会讲到插件的依赖管理。

3.2.1、7.0之前

来看下Gradle7.0之前,project下的build.gradle文件SEO靠我

// Top-level build file where you can add configuration options common to all sub-projects/modules. SEO靠我 buildscript {ext.kotlin_version = "1.5.0"repositories {google()mavenCentral()}dependencies {SEO靠我classpath "com.android.tools.build:gradle:4.2.1"classpath "org.jetbrains.kotlin:kotlin-gradle-pluginSEO靠我:$kotlin_version"// NOTE: Do not place your application dependencies here; they belong// in the indiSEO靠我vidual module build.gradle files} }allprojects {repositories {google()mavenCentral()jcenter(SEO靠我) // Warning: this repository is going to shut down soon} }task clean(type: Delete) {delete SEO靠我rootProject.buildDir } buildscript

buildscript中的声明是gradle脚本自身需要使用的资源。可以声明的资源包括依赖项、第三SEO靠我方插件、maven仓库地址等。7.0之后改在settings.gradle中配置了(pluginManagement)。

多聊一点,为什么需要buildscript/pluginManagement,因SEO靠我为项目的编译过程,除了项目本身需要的依赖之外,还有就是Gradle自己运行需要的依赖,比如你的插件要去hook Gradle的生命周期,因为运行时机的不同,所以加了一个script,当然buildSrSEO靠我c也可以解决这个问题。 ext

项目全局属性,多用于自定义,比如把关于版本的信息都利用ext放在另一个新建的gradle文件中集中管理,比如version.gradle,然后apply引用即可,这是较为早SEO靠我期的版本管理方式。

repositories

仓库,比如google()、maven()、jcenter()、jitpack等三方托管平台。

dependencies

当然配置了仓库还不够,我们还需要在depSEO靠我endencies{}里面的配置里,把需要配置的依赖用classpath配置上,因为这个dependencies在buildscript{}里面,所以代表的是Gradle需要的插件。

7.0之后把pluSEO靠我gin的配置简化了,由apply+classpath简化为只要apply就可以了。 allprojects

allprojects块的repositories用于多项目构建,为所有项目提供共同所需依赖包。SEO靠我而子项目可以配置自己的repositories以获取自己独需的依赖包。

task clean(type: Delete)

运行gradle clean时,执行此处定义的task。

该任务继承自Delete,SEO靠我删除根目录中的build目录。相当于执行Delete.delete(rootProject.buildDir)。其实这个任务的执行就是可以删除生成的Build文件的,跟Android Studio的cSEO靠我lean是一个道理。

3.3、build.gradle(Module)

位于每个 project/module/ 目录下,用于为其所在的特定模块配置 build 设置。

3.2.1、7.0之后

其实跟7.0之前SEO靠我差别也不是太大。

plugins {id com.android.applicationid org.jetbrains.kotlin.android }android {namespaSEO靠我ce com.yechaoa.gradlexcompileSdk 32defaultConfig {applicationId "com.yechaoa.gradlex"minSdk 23targetSEO靠我Sdk 32versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunnSEO靠我er"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile(proguard-android-opSEO靠我timize.txt), proguard-rules.pro}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCoSEO靠我mpatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = 1.8} }dependencies {implementSEO靠我ation androidx.core:core-ktx:1.7.0implementation androidx.appcompat:appcompat:1.4.1implementation coSEO靠我m.google.android.material:material:1.5.0implementation androidx.constraintlayout:constraintlayout:2.SEO靠我1.3testImplementation junit:junit:4.13.2androidTestImplementation androidx.test.ext:junit:1.1.3androSEO靠我idTestImplementation androidx.test.espresso:espresso-core:3.4.0 }

3.3.1、7.0之前

apply plugin: coSEO靠我m.android.application apply plugin: kotlin-androidandroid {compileSdkVersion 30defaultConfigSEO靠我 {applicationId "com.yechaoa.app"minSdkVersion 19targetSdkVersion 30versionCode 1versionName "1.0"teSEO靠我stInstrumentationRunner androidx.test.runner.AndroidJUnitRunner}buildTypes {release {minifyEnabled fSEO靠我alseproguardFiles getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro}}buildFeSEO靠我atures {viewBinding = true}}dependencies {implementation fileTree(dir: libs, include: [*.jar])implemSEO靠我entation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"implementation androidx.appcompat:SEO靠我appcompat:1.2.0implementation androidx.constraintlayout:constraintlayout:2.0.4testImplementation junSEO靠我it:junit:4.13.2androidTestImplementation androidx.test.ext:junit:1.1.2androidTestImplementation andrSEO靠我oidx.test.espresso:espresso-core:3.3.0implementation "com.google.android.material:material:1.3.0"impSEO靠我lementation project(:yutils)implementation project(:yutilskt) } plugins/apply plugiSEO靠我n

前文介绍了,参考 # 3.2、build.gradle(Project)

namespace

应用程序的命名空间。主要用于访问应用程序资源。

com.android.application SEO靠我App插件id:com.android.applicationLibrary插件id:com.android.libraryKotlin插件id:org.jetbrains.kotlin.androiSEO靠我d android{}

是Android插件提供的一个扩展类型,可以让我们自定义Gradle Android工程,是Gradle Android工程配置的唯一入口。

compileSdkVSEO靠我ersion/compileSdk

编译所依赖的Android SDK的版本,即API Level,可以使用此API级别及更低级别中包含的API功能。

(api等级对应关系)buildToolsVersiSEO靠我on

是构建该Android工程所用构建工具的版本。

后被废弃了,因为7.0之后,假如你的buildToolsVersion是30.0.1,低于AGP7.0.2所要求的的最低版本30.0.2,那就会使用3SEO靠我0.0.2的版本,而不是你指定的版本,后续AGP会应用一个对应的默认的版本。 defaultConfig{}

默认配置,它是一个ProductFlavor。ProductFlavor允许我们根据不同的情况SEO靠我同时生成多个不同的apk包。

applicationId

包名,app的唯一标识。其实他跟AndroidManifest里面的package是可以不同的,他们之间并没有直接的关系。

minSdkVersioSEO靠我n/minSdk

是支持Android系统的api level,这里是23,也就是说低于Android 6.0版本的机型不能使用这个app。

targetSdkVersion/targetSdk

是标示apSEO靠我p基于哪个Android版本开发的,这里是32,也就是适配到Android 12.0。

versionCode

版本号,一般用于版本控制。

versionName

版本名称,公开信息,默认1.0,7.0之前默SEO靠我认是1.0.0,行业规范3位数,但并没有强制。

multiDexEnabled

用于配置该BuildType是否启用自动拆分多个Dex的功能。一般用程序中代码太多,超过了65535个方法的时候。

ndk{}SEO靠我

多平台编译,生成有so包的时候使用,之前用armeabi的比较多,要求做32/64位适配之后开始拆分(提高性能),armeabi-v7a’表示32位cpu架构, arm64-v8a’表示64位, x8SEO靠我6’是只模拟器或特定rom。

一般使用第三方提供的SDK的时候,可能会附带so库。 sourceSets

源代码集合,是Java插件用来描述和管理源代码及资源的一个抽象概念,是一个Java源代码文件和资源文SEO靠我件的集合,我们可以通过sourceSets更改源集的Java目录或者资源目录等。

buildTypes

构建类型,在Gradle Android工程中,它已经帮我们内置了release构建类型,一般还会加SEO靠我上debug,两种模式主要区别在于,能否在设备上调试以及签名不一样,其他代码和文件资源都是一样的(如果没有做处理的话-log)。

buildTypes {debug {buildConfigField(SEO靠我"String", "AUTHOR", "\"yechaoa\"")minifyEnabled false}release {buildConfigField("String", "AUTHOR", SEO靠我"\"yechaoa\"")signingConfig signingConfigs.releaseshrinkResources trueminifyEnabled trueproguardFileSEO靠我s getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro}} name:build tySEO靠我pe的名字applicationIdSuffix:应用id后缀versionNameSuffix:版本名称后缀debuggable:是否生成一个debug的apkminifyEnabled:是否混淆pSEO靠我roguardFiles:混淆文件signingConfig:签名配置manifestPlaceholders:清单占位符shrinkResources:是否去除未利用的资源,默认false,表示不去SEO靠我除。zipAlignEnable:是否使用zipalign工具压缩。multiDexEnabled:是否拆成多个DexmultiDexKeepFile:指定文本文件编译进主Dex文件中multiDexSEO靠我KeepProguard:指定混淆文件编译进主Dex文件中 signingConfigs

签名配置,一个app只有在签名之后才能被发布、安装、使用,签名是保护app的方式,标记该app的SEO靠我唯一性。

signingConfigs {release {keyAlias keystoreProperties[keyAlias]keyPassword keystoreProperties[keySEO靠我Password]storeFile file(keystoreProperties[storeFile])storePassword keystoreProperties[storePasswordSEO靠我]v1SigningEnabled truev2SigningEnabled true}}

官方建议不直接明文写,而是从文件读取。

productFlavors

多渠道打包配置,可以实现定制化版本的需求。

bSEO靠我uildConfigField

他是BuildConfig文件的一个函数,而BuildConfig这个类是Android Gradle构建脚本在编译后生成的。比如版本号、一些标识位什么的。

Build VSEO靠我ariants

选择编译的版本。

buildFeatures

开启或关闭构建功能,常见的有viewBinding、dataBinding、compose。

buildFeatures {viewBindingSEO靠我 = true// dataBinding = true} dexOptions{}

我们知道,Android中的Java/kotlin源代码被编译成class字节码后,在打包成apkSEO靠我的时候被dx命令优化成Android虚拟机可执行的dex文件。

对于这些生成dex文件的过程和处理,Android Gradle插件都帮我们处理好了,Android Gradle插件会调用SDK中的dxSEO靠我命令进行处理。

可以设置编译时所占用的内存(javaMaxHeapSize),从而提升编译速度。

7.0之后已经废弃。 compileOptions

Java编译选项,指定java环境版本。

kotlinOptSEO靠我ions

Kotlin编译选项,通常指定jvm环境。

composeOptions

Compose功能的可选设置。比如指定Kotlin Compiler版本,一般用默认。

lintOptions

用于配置linSEO靠我t选项。Example

dependencies{}

我们平时用的最多的大概就这个了,Gradle3.2之后有依赖方式的变更,因为不支持依赖关系细粒度的范围界定。

compile > implementatSEO靠我ion/apiandroidTestCompile > androidTestImplementationtestCompile > testImplementationinstrumentTest SEO靠我> androidTest implementation androidx.core:core-ktx:1.7.0 implementation和api的区别

implSEO靠我ementation指令依赖是不会传递的,也就是说当前引用的第三方库仅限于本module内使用,其他module需要重新添加依赖才能用,使用api指令的话可以传递。(后面也会细讲依赖)

一图胜千言:

图源SEO靠我:19snow93

3.4、settings.gradle

位于项目的根目录下,用于定义项目级代码库设置。

pluginManagement {repositories {gradlePluginPortaSEO靠我l()google()mavenCentral()} } dependencyResolutionManagement {repositoriesMode.set(ReSEO靠我positoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()} } rootProSEO靠我ject.name = "GradleX" include :app pluginManagement

插件管理,指定插件下载的仓库,及版本。

dependencyResSEO靠我olutionManagement

依赖管理,指定依赖库的仓库地址,及版本。即7.0之前的allprojects。

顺序决定了先从哪个仓库去找依赖库并下载,一般为了编译稳定,会把阿里的镜像地址(或自建私有SEO靠我仓库)放在Google()仓库之前。 rootProject.name

项目名称。

include

用于指定构建应用时应将哪些模块包含在内,即参与构建的模块。

也可用于动态引用,在编译提速时,会module打成SEO靠我aar依赖来节省编译时间,但是为了开发方便,一般会动态选择哪些module使用源码依赖。

3.5、gradle.properties

位于项目的根目录下,用于指定 Gradle 构建工具包本身的设置,也可SEO靠我用于项目版本管理。

Gradle本身配置

比如Gradle 守护程序的最大堆大小、编译缓存、并行编译、是否使用Androidx等等。

# Project-wide Gradle settings. SEO靠我 # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will ovSEO靠我erride* # any settings specified in this file. # For more details on how to configurSEO靠我e your build environment visit # http://www.gradle.org/docs/current/userguide/build_environmSEO靠我ent.html # Specifies the JVM arguments used for the daemon process. # The setting isSEO靠我 particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSSEO靠我ize=512m # When configured, Gradle will run in incubating parallel mode. # This optiSEO靠我on should only be used with decoupled projects. More details, visit # http://www.gradle.org/SEO靠我docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.paralleSEO靠我l=true # AndroidX package structure to make it clearer which packages are bundled with the SEO靠我 # Android operating system, and which are packaged with your app"s APK # https://deveSEO靠我loper.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true SEO靠我 # Automatically convert third-party libraries to use AndroidX android.enableJetifier=trueSEO靠我 # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=oSEO靠我fficial# ---------- 编译相关 start ----------#并行编译 org.gradle.parallel=true#构建缓存 org.graSEO靠我dle.caching=true# ---------- 编译相关 end ---------- 版本管理 # ---------- 版本相关 start -----SEO靠我-----yechaoaPluginVersion="1.0.0"# ---------- 版本相关 end ----------

在版本管理中,可以从gradle.properties文件中读取版本,SEO靠我不仅可以作用于依赖库,也可作用于依赖插件。本质上是key-value形式的参数。

pluginManagement {plugins {id com.yechaoa.gradlex version "$SEO靠我{yechaoaPluginVersion}"} }

3.6、local.properties

位于项目的根目录下,用于指定 Gradle 构建配置本地环境属性,也可用于项目环境管理。

本地SEO靠我配置 ## This file must *NOT* be checked into Version Control Systems, # as it containsSEO靠我 information specific to your local configuration. # # Location of the SDK. This is SEO靠我only used by Gradle. # For customization when using a Version Control System, please read thSEO靠我e # header note. #Mon Feb 08 19:07:41 CST 2021 sdk.dir=/Users/yechao/LibrarySEO靠我/Android/sdk ndk.dir=/Users/yechao/Library/Android/ndk sdk.dir:SDK 的路径ndk.dir:NDK 的SEO靠我路径,已废弃,用SDK目录下的NDK目录。 环境管理

可以用作项目本地调试的一些开关:

isRelease=true #isDebug=false #isHSEO靠我5Debug=false

4、Gradle配置怎么来的

前面介绍了这么多的Gradle配置,最常用的就是app > build.gradle了,这个文件里的配置是最多的,也是跟Android开发打交道最多SEO靠我的,那么,这些配置是哪里来的呢?

再来回顾一下app > build.gradle:

plugins {id com.android.applicationid org.jetbrains.kotlin.SEO靠我android }android {namespace com.yechaoa.gradlexcompileSdk 32defaultConfig {applicationId "coSEO靠我m.yechaoa.gradlex"minSdk 23targetSdk 32versionCode 1versionName "1.0"} }dependencies {implemSEO靠我entation androidx.core:core-ktx:1.7.0 }

按结构可以分为3部分,plugins、android和dependencies。

在上一篇入门文章中我们讲到SEO靠我,Gradle是一个通用的自动化构建工具,通用也就是说,不仅可以构建Android项目,还可以构建java、kotlin、swift等项目。再结合android{}里面的配置属性,我们可以确定,那这就SEO靠我是Android项目专属的配置DSL了。

既然如此,如果让你来设计Gradle的架构框架你会怎么做?

这种架构通常都是底层通用能力+上层定制化的经典设计,上层定制化也就是说Android项目有AndroiSEO靠我d的配置DSL,Java项目有Java配置的DSL,不同项目有不同配置。

那么回到问题本身,android{}是怎么来的,创建项目就有,那是跟随开发工具来的?好像也不对啊,Android Studio不SEO靠我仅可以开发Android项目啊,别的也行,而且别的开发工具也能开发Android项目呢。那既然不是跟随开发工具,又要做到定制化,那是怎么来的。

回到build.gradle配置结构的第一部分:

plugiSEO靠我ns {id com.android.applicationid org.jetbrains.kotlin.android }

注意到,这里有一个名为com.android.applicSEO靠我ation的plugin,看名字也是android项目专属无疑了,再去源码里看一下这个plugin是干嘛的。

看Gradle源码有个比较简单的方式,就是直接拉依赖,比如我现在用的Gradle7.4,直接SEO靠我依赖对应版本:

implementation "com.android.tools.build:gradle:7.4"

如果发现还是点不进去源码,再把下载Gradle的类型改了,gradle-7.4-biSEO靠我n.zip > gradle-7.4-all.zip。完事重新sync就可以直接点进源码了。

先看下android{}的提示:

提炼几个信息:

BaseAppModuleExtensioncom.androSEO靠我id.build.gradle.internal.dslClosureorg.gradle.api.Project

这几个信息足够验证我们之前的猜想了,android{}是通过插件的方式引入的。

然后点进SEO靠我去:

@HasInternalProtocol public interface Project extends Comparable<Project>, ExtensionAware,SEO靠我 PluginAware {.../*** <p>Configures the dependencies for this project.** <p>This method executes theSEO靠我 given closure against the {@link DependencyHandler} for this project. The {@link* DependencyHandlerSEO靠我} is passed to the closure as the closures delegate.** <h3>Examples:</h3>* See docs for {@link DepenSEO靠我dencyHandler}** @param configureClosure the closure to use to configure the dependencies.*/void depeSEO靠我ndencies(Closure configureClosure);... }

是一个dependencies函数,接收一个闭包。

再来看BaseAppModuleExtension 的SEO靠我android:

android(Closure configuration)

也是接收一个闭包,这个闭包其实就是android{}这个配置,配置里面定义的就是我们日常编译运行需要的配置参数,defaulSEO靠我tConfig、minSdk、versionCode之类的。

再看下BaseAppModuleExtension源码:

/** The `android` extension for base featuSEO靠我re module (application plugin). */ open class BaseAppModuleExtension(dslServices: DslServiceSEO靠我s,bootClasspathConfig: BootClasspathConfig,buildOutputs: NamedDomainObjectContainer<BaseVariantOutpuSEO靠我t>,sourceSetManager: SourceSetManager,extraModelInfo: ExtraModelInfo,private val publicExtensionImplSEO靠我: ApplicationExtensionImpl ) : AppExtension(dslServices,bootClasspathConfig,buildOutputs,souSEO靠我rceSetManager,extraModelInfo,true ), InternalApplicationExtension by publicExtensionImpl {//SEO靠我 Overrides to make the parameterized types match, due to BaseExtension being part of// the previous SEO靠我public API and not wanting to paramerterize that.override val buildTypes: NamedDomainObjectContainerSEO靠我<BuildType>get() = publicExtensionImpl.buildTypes as NamedDomainObjectContainer<BuildType>override vSEO靠我al defaultConfig: DefaultConfigget() = publicExtensionImpl.defaultConfig as DefaultConfigoverride vaSEO靠我l productFlavors: NamedDomainObjectContainer<ProductFlavor>get() = publicExtensionImpl.productFlavorSEO靠我s as NamedDomainObjectContainer<ProductFlavor>override val sourceSets: NamedDomainObjectContainer<AnSEO靠我droidSourceSet>get() = publicExtensionImpl.sourceSetsoverride val composeOptions: ComposeOptions = pSEO靠我ublicExtensionImpl.composeOptionsoverride val bundle: BundleOptions = publicExtensionImpl.bundle as SEO靠我BundleOptionsoverride val flavorDimensionList: MutableList<String>get() = flavorDimensionsoverride vSEO靠我al buildToolsRevision: Revisionget() = Revision.parseRevision(buildToolsVersion, Revision.Precision.SEO靠我MICRO)override val libraryRequests: MutableCollection<LibraryRequest>get() = publicExtensionImpl.libSEO靠我raryRequests }

我们可以看到一些熟悉的配置,比如buildTypes、defaultConfig、sourceSets等等。不过这只是一部分,剩下的配置在父类AppExteSEO靠我nsion里,就不贴代码了。

然后android{}这个配置标签是怎么创建出来的呢?

/** Gradle plugin class for application projects, applied oSEO靠我n the base application module */ public class AppPlugin extends AbstractAppPlugin<...> {//..SEO靠我.@NonNull@Overrideprotected ExtensionData<...> createExtension(...) {// ...if (getProjectServices().SEO靠我getProjectOptions().get(BooleanOption.USE_NEW_DSL_INTERFACES)) {// noinspection unchecked,rawtypes: SEO靠我Hacks to make the parameterized types make senseClass<ApplicationExtension> instanceType = (Class) BSEO靠我aseAppModuleExtension.class;BaseAppModuleExtension android =(BaseAppModuleExtension)project.getExtenSEO靠我sions().create(new TypeOf<ApplicationExtension>() {},"android",instanceType,dslServices,bootClasspatSEO靠我hConfig,buildOutputs,dslContainers.getSourceSetManager(),extraModelInfo,applicationExtension);projecSEO靠我t.getExtensions().add(BaseAppModuleExtension.class,"_internal_legacy_android_extension",android);iniSEO靠我tExtensionFromSettings(applicationExtension);return new ExtensionData<>(android, applicationExtensioSEO靠我n, bootClasspathConfig);}BaseAppModuleExtension android =project.getExtensions().create("android",BaSEO靠我seAppModuleExtension.class,dslServices,bootClasspathConfig,buildOutputs,dslContainers.getSourceSetMaSEO靠我nager(),extraModelInfo,applicationExtension);initExtensionFromSettings(android);return new ExtensionSEO靠我Data<>(android, applicationExtension, bootClasspathConfig);}//... }

我把多余代码都删了,简而言之,在AppPluginSEO靠我里用project.getExtensions().create()方法创建的"android"标签,AppPlugin即id为’com.android.application’的插件,跟自定义PluSEO靠我gin一样配置,后续再展开。

其实所有的DSL配置都是通过插件的方式引入的。

最后我们再来捋一下思路:

通过依赖’com.android.application’插件,有了android{}这个配置DSL;SEO靠我一个项目对应一个Project对象,Project对象里面包含dependencies函数;android{}这个配置DSL点进去就是Project对象里面dependencies这个函数,二者都接收SEO靠我一个闭包;然后通过DependencyHandler这个类,执行android(Closure configuration)这个闭包并委托给dependencies(Closure configureSEO靠我Closure),也就是Project对象;最后Gradle在执行阶段去解析这个Project对象并拿到android{}里面的配置参数,后面就是执行Task等等;

5、总结

我们先是简单介绍了GradlSEO靠我e的配置,以及配置的优先级和初始配置等概念,然后针对我们常用的配置进行了详细的介绍,以及Gradle7.0版本前后的对比,最后通过源码分析介绍了Android核心配置是怎么来的。

源码部分对新手可能有点SEO靠我不太友好,闭包、DSL、Plugin这些概念可能暂时还不太好理解,不过不用担心,后面会继续讲到,先了解下大致流程就行~

写作不易,点个赞吧!

6、Github

https://github.com/yechSEO靠我aoa/GradleX

7、参考文档

Build Environment彻底弄明白Gradle相关配置Configure your buildbuild api dslGradle入门教程Gradle的快SEO靠我速入门学习Mastering Gradleupgrading_version_6apply plugin和plugins两种应用gradle插件的区别BaseAppModuleExtension
“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2