【译文】Android Gradle 教程:入门

什么是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 块的结构类似于该 buildscript 块,但是在这里您为所有模块定义存储库,而不是为 Gradle 本身定义存储库。通常,您不会为定义该 dependencies 部分 allprojects。每个模块的依赖关系都不同,并且应位于模块级 build.gradle 中。

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'
}

上面的代码执行以下操作:

  1. 指定构建模块所需的插件列表。该 com.android.application 插件对于设置构建过程的 Android 特定设置是必需的。com.android.library 如果要创建库模块,也可以在这里使用。在 kotlin-android 和 kotlin-android-extensions 插件允许你使用 kotlin 语言和相关插件到您的模块中。

  2. 在该 android 块中,放置模块的所有具体平台参数的选项。

  3. compileSdkVersion 选项指示您的应用将使用的 API 级别。换句话说,您不能使用 API​​ 中高于此值的功能。在这里,您已设置了使用 Android Oreo API 的值。

  4. buildToolsVersion 选项指示编译器的版本。从 Gradle 插件 3.0.0 开始,此字段是可选的。如果未指定,则 Android SDK 使用构建工具的最新下载版本。

  5. defaultConfig 块包含默认情况下将应用于您应用的所有构建版本(例如,调试,发行等)的选项。

  6. applicationId 是你的应用程序的标识。它应该是唯一的,以便在 Google Play 商店中成功发布或更新您的应用。

  7. 为了设置支持的最低API级别,请使用 minSdkVersion。在 API 级别较低的设备上,您的应用将无法在 Google Play 商店中使用。

  8. targetSdkVersion 参数定义了您的应用经过测试的最大 API 级别。也就是说,您确定您的应用程序可以在具有此 SDK 版本的设备上正常运行,并且不需要任何向后兼容行为。最好的方法是使用最新的API彻底测试应用,并保持您的 targetSdkVersion 等于 compileSdkVersion。

  9. versionCode 是应用程序版本的数值。

  10. versionName 是应用程序版本的用户友好字符串。

  11. 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
}

注意:与密钥库文件相关的两个重要注意事项:

  1. 将应用发布到Google Play商店后,后续提交必须使用相同的密钥库文件和密码,以确保安全。

  2. 确保不要将密钥库密码提交给版本控制系统,例如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"]
    }
} 
  1. 您需要指定 flavorDimensions 以正确匹配构建类型。在当前示例中,只需要一个维度 - appMode。

  2. 在 productFlavors 指定具体的  flavors 和 具体的设置。在当前示例中,分别是 free 和 paid。

  3. 指定第一个 productFlavors 的名称为:free。

  4. 必须指定 dimension 参数值。这里 free flavor 属于 appMode dimension。

  5. 由于您要为免费和付费功能创建单独的应用程序,因此需要它们具有不同的应用程序标识符。该 applicationIdSuffix 参数定义了会被附加到一个 applicationId 上,从而让你的应用程序拥有唯一标识符。

  6. 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
        }
    }
}

下面说下相关逻辑:

  1. 您定义一个 addCurrentDate() 任务。

  2. 您遍历所有输出构建变量。

  3. 您遍历所有 APK 文件。

  4. 您创建一个实例 Date 并设置其格式。

  5. 您创建一个新的文件名,将当前日期附加到初始名称之后。

  6. 您将新文件名设置为当前的 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 插件等需要继续学习。

 

参考文章

原文:Gradle Tutorial for Android: Getting Started

 

 
posted @ 2020-01-18 18:08  huansky  阅读(1535)  评论(0编辑  收藏  举报