什么是Gradle?
Gradle 是一个开源的构建自动化系统。它拥有基于 Groovy 的 DSL 的便利以及 Ant 和 Maven 的优势。
使用 Gradle,您可以轻松地操纵构建过程及其逻辑,以创建应用程序的多个版本。与单独使用 Ant 或 Maven 相比,它更易于使用,更加简洁和灵活。
入门
新建一个 Android project,将以该项目进行讲解。
在开始处理项目之前,让我们在 Android Studio 的 "project" 选项中查看其结构:
注意带有绿色 Gradle 图标和扩展名 .gradle 的文件。这些文件由Android Studio在项目创建过程中自动生成。他们负责处理项目的构建。它们包含有关项目结构,库依赖项,库版本以及在构建过程中将获得的应用程序版本的必要信息。
Project 层的 build.gradle
在项目的根目录中找到 build.gradle 文件。它称为顶级(项目级别)build.gradle 文件。它包含适用于项目所有模块的设置。
// 1
buildscript {
// 2
repositories {
google()
jcenter()
}
// 3
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.51'
}
}
// 4
allprojects {
repositories {
google()
jcenter()
}
}
这是逐步进行的操作:
- 在 buildscript
- 在 repositories 块中,添加 Gradle 应搜索使用的库的存储库名称。
- 该 dependencies 块包含必要的插件依赖性,在这种情况下为 Gradle 和 Kotlin 插件。不要将模块依赖项放在此块中。
- 该 allprojects
Moudle 层的 build.gradle
现在转到应用程序模块目录中的build.gradle文件。它包含依赖项(模块所依赖的库)以及构建过程的说明。每个模块定义其自己的build.gradle文件。
// 1
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
// 2
android {
// 3
compileSdkVersion 27
// 4
buildToolsVersion "26.0.2"
// 5
defaultConfig {
// 6
applicationId "com.raywenderlich.socializify"
// 7
minSdkVersion 21
// 8
targetSdkVersion 27
// 9
versionCode 1
// 10
versionName "1.0"
}
}
// 11
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.1.51'
implementation 'com.android.support:appcompat-v7:27.0.1'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
}
上面的代码执行以下操作:
- 指定构建模块所需的插件列表。该 com.android.application
- 在该 android
- 该 compileSdkVersion
- 该 buildToolsVersion
- 该 defaultConfig
- 该 applicationId
- 为了设置支持的最低API级别,请使用 minSdkVersion。在 API 级别较低的设备上,您的应用将无法在 Google Play 商店中使用。
- 该 targetSdkVersion
- versionCode
- versionName
- 该 dependencies
settings.gradle
根目录中的 settings.gradle 文件。其内容应如下所示:
include ':app'
在此文件中,应按名称定义项目的所有模块。在这里,我们只有一个模块 — app。在大型,多模块的项目中,此文件会有更长的列表。
Gradle 命令
要执行Gradle命令,您可以同时使用命令行和 Android Studio。最好从命令行开始,以更深入地了解正在发生的事情。那么,如何开始使用 Gradle 命令呢?非常简单:使用 gradlew。
什么是 gradlew
gradlew 是 Gradle 包装器。您无需担心在计算机上安装 Gradle,包装程序将为您完成此操作。甚至更多,它使您可以使用不同版本的 Gradle 构建不同的项目。
打开命令行并移至入该项目的根目录,之后,执行以下命令:
./gradlew tasks
您将看到一个包含所有可用任务的列表:
> Task :tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.
Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.
assembleAndroidTest - Assembles all the Test applications.
assembleDebug - Assembles all Debug builds.
assembleRelease - Assembles all Release builds.
...
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Help tasks
----------
...
Install tasks
-------------
...
Verification tasks
------------------
...
lint - Runs lint on all variants.
...
To see all tasks, run gradlew tasks --all
To get more detail about task, run gradlew help --task <task>
这些命令可以帮助您完成项目初始化,构建,测试和分析等任务。如果您忘记了一个特定的命令,只需执行 ./gradlew tasks
gradlew assemble
现在,再次浏览命令列表,并在该部分下找到以 “assemble” 开头的命令 Build tasks。运行第一个命令:
./gradlew assemble
以下是执行此命令的输出
> Task :app:compileDebugKotlin
Using kotlin incremental compilation
> Task :app:compileReleaseKotlin
Using kotlin incremental compilation
BUILD SUCCESSFUL in 29s
52 actionable tasks: 52 executed
从输出中,这是显而易见的是摇篮的编译应用程序的两个版本 - debug 和 release。
通过更改到构建输出目录来验证此内容:
cd app/build/outputs/apk/
要查看目录的内容,请运行以下命令:
ls -R
该 ls 命令显示当前目录中的所有文件和目录。该 -R 参数强制此命令以递归方式执行。换句话说,您不仅会看到当前目录的内容,还会看到子目录的内容。
您将获得以下输出:
debug release
./debug:
app-debug.apk output.json
./release:
app-release-unsigned.apk output.json
如您所见,Gradle 生成了 debug 和 release apk。
管理依赖关系
现在是时候对应用程序本身进行更改了。
首先,在项目的根目录中创建一个名为 dependencies.gradle 的文件。您将使用此文件在一处识别所有项目依赖项版本。将以下内容添加到此文件:
ext {
minSdkVersion = 17
targetSdkVersion = 27
compileSdkVersion = 27
buildToolsVersion = “ 26.0.2”
kotlinVersion = “ 1.1.51 ”
supportVersion = “ 27.0.1”
picassoVersion = “ 2.5.2”
}
打开项目级别的 build.gradle 文件(位于根目录中的一个,而不是 app 目录中的一个!),然后在文件顶部添加以下行:
apply from: 'dependencies.gradle'
现在,您可以像下面这样使用其他项目构建文件中在 dependencies.gradle 文件中指定的属性:
应用程序模块级别的 build.gradle
android {
compileSdkVersion rootProject.compileSdkVersion
buildToolsVersion rootProject.buildToolsVersion
defaultConfig {
applicationId "com.raywenderlich.socializify"
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.targetSdkVersion
versionCode 1
versionName "1.0"
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "com.android.support:appcompat-v7:$rootProject.supportVersion"
implementation "com.android.support:design:$rootProject.supportVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.kotlinVersion"
}
Gradle依赖项配置
implementation
您先前使用的关键字是依赖项配置,该配置告诉 Gradle 以这种方式添加依赖,其他模块无法使用它。该选项大大加快了构建时间。
在某些其他情况下,您可能希望项目的其他模块可以访问依赖项。在这种情况下,您可以使用 api
关键字。
其他选项包括 runtimeOnly
和 compileOnly
配置,它们仅在运行时或编译时标记依赖项的可用性。
准备发布:使用 Product Flavors and Build Types
您的应用已准备就绪,您正在考虑怎么从项目中获利的方法:
一种解决方案是拥有多个版本的应用程序:免费和付费版本。幸运的是,gradle 在构建级别支持此功能,使您可以定义不同构建类型的边界。但是,在开始之前,您需要了解 Gradle 如何允许您使用不同的应用程序版本。
构建类型
默认情况下,有两种构建类型 debug 和 release。它们之间的唯一区别是 debuggable 参数的值。换句话说,您可以使用调试版本查看日志并调试应用程序,而发布版本则用于将您的应用程序发布到 Google Play 商店。您可以通过在 android 模块级 build.gradle 文件的块中添加以下代码来为构建类型配置属性:
buildTypes {
release {
}
debug {
}
}
在 debug 和 release 块中,您可以指定应用程序的特定于类型的设置。
Build Signing
构建的最重要的配置之一是其签名。没有签名,您将无法发布您的应用程序,因为有必要验证您是否是特定应用程序的所有者。尽管您无需签署调试版本(Android Studio会自动进行签名),但发行版本应由开发人员签名。
当你的密钥库已准备就绪,下面添加的代码位于 android 块下,与上述 buildTypes 块处于 module 层级的的 build.gradle 文件:
signingConfigs {
release {
storeFile file("path to your keystore file")
storePassword "your store password"
keyAlias "your key alias"
keyPassword "your key password"
}
}
在 signingConfigs 块中,为构建类型指定签名信息。注意密钥库文件路径。应该相对于模块目录进行指定。换句话说,如果您在模块目录中创建了密钥库文件并将其命名为“ keystore.jks”,则应指定的值将等于文件名。
更新 buildTypes 块以自动签署发布版本:
release {
signingConfig signingConfigs.release
}
注意:与密钥库文件相关的两个重要注意事项:
- 将应用发布到Google Play商店后,后续提交必须使用相同的密钥库文件和密码,以确保安全。
- 确保不要将密钥库密码提交给版本控制系统,例如GitHub。您可以通过以下方式进行操作:将密码保存在与中不同的文件中build.gradle(例如keystorePassword.gradle,在Signing目录中),然后build.gradle通过以下方式从应用程序模块级别引用该文件:
apply from: "../Signing/keystorePassword.gradle
然后确保保持 keystorePassword.gradle 版本控制系统忽略它。其他技术包括将密码保存在 OS 级环境变量中,尤其是在远程持续集成系统(例如 CircleCI )上。
Build Flavors
为了创建您的应用程序的多个版本,您需要使用 productflavors。Flavors 是一种区分应用程序属性的方法,无论它是免费/付费的,分阶段的/生产的等等。
您将使用不同的应用程序名称来区分您的应用程序风格。首先,将以下名称添加为 strings.xml 文件中的字符串:
<string name="app_name_free">Socializify Free</string>
<string name="app_name_paid">Socializify Paid</string>
并删除现有的:
<string name="app_name">test</string>
现在,原始 app_name 字符串不再可用,请编辑 AndroidManifest.xml 文件,并将在 application 中的 android:label="@string/app_name" 替换为 android:label="${appName}" 。
同时在 modle 层级 build.gradle 文件的 android 块中添加以下代码:
// 1
flavorDimensions "appMode"
// 2
productFlavors {
// 3
free {
// 4
dimension "appMode"
// 5
applicationIdSuffix ".free"
// 6
manifestPlaceholders = [appName: "@string/app_name_free"]
}
paid {
dimension "appMode"
applicationIdSuffix ".paid"
manifestPlaceholders = [appName: "@string/app_name_paid"]
}
}
- 您需要指定 flavorDimensions 以正确匹配构建类型。在当前示例中,只需要一个维度 - appMode。
- 在 productFlavors 指定具体的 flavors 和 具体的设置。在当前示例中,分别是 free 和 paid。
- 指定第一个 productFlavors 的名称为:free。
- 必须指定 dimension 参数值。这里 free flavor 属于 appMode dimension。
- 由于您要为免费和付费功能创建单独的应用程序,因此需要它们具有不同的应用程序标识符。该 applicationIdSuffix 参数定义了会被附加到一个 applicationId 上,从而让你的应用程序拥有唯一标识符。
- manifestPlaceholders 允许你在构建的时候修改 AndroidManifest.xml 中的属性。在当前示例中,会根据不同的版本来修改应用名称。
再次 sync project with Gradle。项目同步后,运行 tasks 命令,并查看哪些内容发生了改变:
./gradlew tasks
您将获得与第一次运行此命令时类似的任务列表:
...
Build tasks
-----------
...
assembleDebug - Assembles all Debug builds.
assembleFree - Assembles all Free builds.
assemblePaid - Assembles all Paid builds.
assembleRelease - Assembles all Release builds.
...
可以发现,任务添加了一些新的选项。现在,每种构建类型和构建 flavors 都有自己单独的命令。
从上一个 ./gradlew assemble
任务中删除生成的输出文件夹,以便您可以在添加 buildTypes 和 productFlavors
之后看到明显的区别。运行命令:
rm -rf app/build/outputs/apk
然后
./gradlew assembleDebug
命令完成后,检查输出目录:
cd app/build/outputs/apk
ls -R
您将获得如下内容:
free paid
./free:
debug
./free/debug:
app-free-debug.apk output.json
./paid:
debug
./paid/debug:
app-paid-debug.apk output.json
您应该生成两个应用 – freeDebug
和 paidDebug
。
什么是Build Variant
从上面的输出中,您实际生成的是不同的构建变体,它们是构建类型 (buildType) 和构建风格 (flavors)组合。也就是说,您有四个可能的构建变体– paidDebug,paidRelease,freeDebug 和 freeRelease。
现在您有两种不同的构建风格,但是,不同的名称不足以让您从中获利。相反,您将根据构建风格 (flavors)配置应用程序的行为!
现在我们在 MainActivity 中定义一个常量:
private static String PAID_FLAVOR = "paid";
在 onCreate 方法中添加如下变量:
if (BuildConfig.FLAVOR == PAID_FLAVOR) {
Toast.makeText(this, "3453", Toast.LENGTH_SHORT).show();
}
如果是付费版本,就会有个 toast 提示。当然,上面只是一个示例,大家后面
创建任务
有时,您需要构建系统执行更复杂的操作或以某种方式自定义构建过程。例如,您可能希望Gradle输出名称中包含构建日期的APK文件。一种可能的解决方案是创建自定义 Gradle 任务。
将以下代码添加到模块级别的 build.gradle 文件中,与 android block 处于同一级别:
// 1
task addCurrentDate() {
// 2
android.applicationVariants.all { variant ->
// 3
variant.outputs.all { output ->
// 4
def date = new Date().format("dd-MM-yyyy")
// 5
def fileName = variant.name + "_" + date + ".apk"
// 6
output.outputFileName = fileName
}
}
}
下面说下相关逻辑:
- 您定义一个 addCurrentDate() 任务。
- 您遍历所有输出构建变量。
- 您遍历所有 APK 文件。
- 您创建一个实例 Date 并设置其格式。
- 您创建一个新的文件名,将当前日期附加到初始名称之后。
- 您将新文件名设置为当前的 APK 文件。
现在,您需要在构建过程的特定时刻执行此任务。在 task addCurrentDate() 块下面添加以下代码:
gradle.taskGraph.whenReady {
addCurrentDate
}
whenReady 当前图形中充满任务并准备开始执行时,块中指定的任务将被调用一次。在这里,您指定 addCurrentDate 任务的名称。
现在,返回命令行,并确保您位于根目录中。运行以下命令以组装构建:
./gradlew assemblePaidRelease
任务完成后,转到输出目录,检查是否正确命名了内部版本:
cd app/build/outputs/apk/paid/release/
ls
您应该得到类似的输出:
output.json paidRelease_12-29-2019.apk
如果您的任务正确执行,则所有构建都将使用此约定命名。
到此,关于 gradle 的介绍就到这里。当然这也只是入门,后续还有 gradle 插件等需要继续学习。