Gradle自学 —— 起步

2,417 阅读6分钟

Gradle自学 —— 起步

Building Android Apps Sample (gradle.org)

配置 build  |  Android 开发者  |  Android Developers (google.cn)

开发Android应用的时候,Gradle总是很难不引起我们的注意,在项目达到一定级别之后,对于Gradle的恰当使用可以让项目更加灵活易用

1. Android项目的构建流程

附上一张Android官方的应用构建流程图

image.png

  • 首先,编写的项目代码、资源文件、aidl接口、其他的依赖最终会统一通过编译器先转换为.class文件,然后再次由Dex工具编译成.dex文件
  • 打包器将资源文件和.dex文件统一打包,生成.apk文件
  • 然后对应的KeyStore对.apk文件进行签名
  • 如果是Release KeyStore,会使用zipalign工具进行apk对齐优化,减少运行时的内存开销

2. 项目默认生成的配置文件

项目创建之初,Android Studio会创建一系列Gradle的配置文件,并且预设一些默认配置 这些配置文件通过Groovy进行编写,包含DSL元素配置,降低了使用门槛 image.png 一些配置文件对应于项目标准,在自定义之前,首先需要了解这些预设的文件在项目中所扮演的角色,新创建的项目中主要有以下Gradle相关文件 image.png

2.1. Gradle设置文件(settings.gradle)

该文件正好对应于上图的第三部分的settings.gradle
位置:项目的根目录下
作用:定义项目级的代码库设置,在构建时决定包含哪些模块

// 该块定义查找和下载插件的存储库
pluginManagement {      
    repositories {      
        gradlePluginPortal()    // gradle插件门户
        google()                // 谷歌Maven仓库
        mavenCentral()          // Maven中央仓库
    }
}
// 该块定项目默认使用的仓库依赖,应当在模块级build.gradle中进一步指定
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "GradleDemo"
include ':app'

2.2. 顶层build文件

即第三个框中的build.gradle文件
位置:项目根目录下
作用:用于定义适用于项目中所有模块的依赖项

// 定义项目中所有模块共用的Gradle依赖项
plugins {
    // apply false 不直接应用于当前项目,提供给子模块使用
    id 'com.android.application' version '7.2.0' apply false   
    id 'com.android.library' version '7.2.0' apply false
    id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
}
// 用于清理build目录
task clean(type: Delete) {
    delete rootProject.buildDir
}

现在许多的Android应用的功能达到一定的量级之后会进行多模块的拆分,在这样的应用场景下,会需要在模块间进行一些属性的共享,方便于进行全局的管理和配置

比如说我想要在子级模块中使用这个依赖统一的版本,方便管理,不需要每个模块下更改 image.png 那么,进到顶层build.gradle,加一个ext块,将版本用一个变量表示

ext {
    versionKtx = '1.7.0'   // 指定版本,可以统一修改
}

随后,回到子模块下,找到对应的build.gradle,使其指向顶层(即rootProjectbuild.gradle中的版本 image.png

使用${}进行插值时注意把包裹的单引号改为双引号,单引号不支持插值

2.3. 模块级build文件

也就是模块级的build.gradle,对应于之前第一个红框
位置<项目>/<模块>/下,对应每个模块会有一个
作用:为所在模块进行一些配置,可对清单文件和顶层build.gradle中的一些配置进行覆盖

plugins {    // 取自于顶层build文件的插件版本,应用于当前模块
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}
// 用于指定所有Android相关的构建配置
android {
    compileSdk 32  // 编译版本要求<=该版本

    defaultConfig {  // 默认配置,可以覆盖对应清单文件
        applicationId "com.minos.gradledemo"  // 发布唯一标识符,应当保持命名空间与appId一致
        minSdk 21  // 可以运行的最小版本
        targetSdk 32   // 用于测试的版本
        versionCode 1   // app版本号
        versionName "1.0"  // 用户友好的版本名

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    // 用于配置多种构建类型,构建系统默认定义2种,即debug和release
    buildTypes { 
    // debug并未显示,但是会应用对应debug签名
    // release默认应用proguard,不签名
        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.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

我们在实际的开发中其实经常会经常遇到需要多渠道打包的场景,这项配置也可以在此进行 默认情况下,是不会创建给设置,需要自己添加productFlavors块,用于为应用定制版本,直接加在android块下

首先,需要使用flavorDimensions指定维度,其实就是添加一个标签,表明该特性的归属,分类的依据是什么 比如根据是否是vip,分别指定专业版和社区版,这样就会有两套apk,具体打包内容需要另外配置了,这里并未给出

flavorDimensions "vip"  // 标签
productFlavors {
    community {  // 社区版
        applicationId "com.minos.gradledemo.community"
        dimension "vip"
    }
    
    profession {   // 专业版
         applicationId "com.minos.gradledemo.profession"
         dimension "vip"
    }
}

配置完后,进行打包 image.png 这个时候,发现可以选用不同的脚本对应配置的不同渠道版本 image.png image.png 最终生成的就是配置的两种版本的apk image.png

2.4. 属性文件

另外,还有两个.properties的属性文件,在第三个红框中
位置:项目根目录下
作用:指定Gradle构建工具包本身的属性参数设置 首先看一下gradle.properties的内容

# 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 -Dfile.encoding=UTF-8   
# 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
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

以键值对的形式给出一些配置,比如守护进程的参数、代码格式之类的配置

local.properties主要是本地项目的一些配置,最常见的就是sdk本地目录的指定

## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *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.
sdk.dir=C:\Users\XXX\AppData\Local\Android\Sdk

其实,还有中间一个红框没有提到,因为这涉及到了另一个内容:Gradle Wrapper

3. Gradle Wrapper

The Gradle Wrapper

这是Gradle官方对于Gradle Wrapper工作流的描述 image.png 首先解释一下Wrapper,这是包装器,怎么理解呢?
可以想象这样一个场景,小明买了一台电脑(整套的),我要一台和小明一样的电脑,这个时候,我可以自己找配件自己组装,当然,更加简单和保险的方式当然是直接找小明要个购买链接,我也来一套一样的(提供这种套装就是Gradle Wrapper的职责)
回到Gradle这种项目构建工具的初衷,是需要标准化、自动化项目的构建、打包流程,那么Gradle Wrapper将项目需要的这种Gradle构建工具标准制定好,团队内部的其他成员去拉取项目代码,进行构建时,如果本地没有指定的Gradle,那么Gradle Wrapper会根据配置的路径到云端下载一份,解压,然后提供给构建流程以完成项目的构建,这也就是上图描述的工作流,很多小伙伴第一次构建项目卡住估计不少都是因为Gradle没能从云端下载下来吧

了解到这里,接着上面一节的内容,打开之前中间红框对应的gradle-wrapper.properties

#Sat Jul 16 10:02:53 CST 2022
distributionBase=GRADLE_USER_HOME   # 解包后存储的主目录
distributionUrl=https://services.gradle.org/distributions/gradle-7.3.3-bin.zip # 包下载路径
distributionPath=wrapper/dists   # 指定目录的子目录
zipStorePath=wrapper/dists   # 压缩包存储主目录
zipStoreBase=GRADLE_USER_HOME  # 压缩包存储子目录

似乎就能从中发现这些配置的目的是为了标准化构建的工具集

gradle-wrapper.jar文件包含下载指定版本Gradle远程包的相关逻辑代码

除此以外,在最后一个红框中还有两个与Gradle Wrapper相关的文件,分别是gradlewgradlew.bat,分别对应于Linux和Windows下执行Gradle命令的包装器脚本

有了这层包装,gradlew命令相较于gradle命令显得更加可靠,另外也可以方便地进行版本的升级以及自定义Gradle Wrapper

Gradle User Manual
配置 build  |  Android 开发者  |  Android Developers (google.cn)
The Gradle Wrapper