Android官方技术文档翻译——Gradle 插件用户指南

本文译自Android官方技术文档《Gradle Plugin User Guide》,原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide。

 

Gradle 插件用户指南

简介

本文档是 Gradle 插件 0.9 版本的文档。在 1.0 之前,我们所介绍的早期版本可能由于不兼容问题会有所不同。

新构建系统的目标

新的构建系统的目标是:

  • 可以很容易地重用代码和资源
  • 可以很容易地创建应用程序的几个变种,无论是多APK分发还是不同定制版的应用程序
  • 可以很容易地配置、 扩展和自定义构建过程
  • 好的 IDE 集成

为什么是 Gradle ?

Gradle 是一个先进的构建系统和构建工具,它允许通过插件创建自定义的构建逻辑。

基于Gradle的以下特点,我们选择了它:

  • 域特定语言 (DSL) 来描述和处理构建逻辑
  • 构建文件基于 Groovy ,并允许通过 DSL来混合声明性元素,以及使用代码来处理 DSL 元素以提供自定义逻辑。
  • 基于 Maven 和 Ivy 的内置依赖管理。
  • 非常灵活。允许使用最佳实现,但并不强制自己的实现方式。
  • 插件可以提供自己的 DSL 和API供构建文件使用。
  • 良好的Tooling API 供 IDE 集成

要求

  • Gradle 版本需要 1.10,1.11或 1.12。插件版本需要 0.11.1
  • SDK Build Tools版本要求为 19.0.0。某些功能可能需要更高版本。

基本项目

Gradle 项目在项目的根文件夹里的build.gradle文件中描述它的构建逻辑。

简单的构建文件

最简单的 纯Java项目的build.gradle如下所示:

apply plugin: ‘java’

这里配置使用了Gradle内置的 Java 插件。该插件提供用于构建并测试 Java 应用程序所需要的东西。最简单的 Android 项目的 build.gradle 则是以下内容:

buildscript {
    repositories {

mavenCentral()
}

    dependencies {
        classpath ‘com.android.tools.build:gradle:0.11.1’
    }
}
apply plugin: ‘android’
android {
    compileSdkVersion 19

    buildToolsVersion “19.0.0”

}

在这个 Android 构建文件中,有3个主要部分:

buildscript { … }配置了驱动构建的代码。
在上面的这种情况中,它声明了使用 Maven 中央库,并且对一个Maven 文件有一个类路径依赖。这个文件是包含 Gradle Android 插件的 0.11.1版本的库
注: 这只会影响运行构建的代码,不会影响项目的源代码。项目本身需要定义它自己的仓库和依赖关系。稍后会提及这部分。

然后,和先前的提到的 Java 插件一样,这里配置使用了 android插件。

最后, android { … }配置了用于 android 构建的所有参数。这是Android DSL的入口。
默认情况下,只需要配置编译目标,以及build-tools的版本。它通过compileSdkVersion和buildtoolsVersion属性来完成。

编译目标相当于旧的构建系统中project.properties 文件内的target属性。这个新的属性可以设置为一个 int 值 (表示api 级别),或者是和以前的target的值一样,设置为字符串。

重要提示:你应该只配置使用这个android插件。如果同时配置使用了java插件也会导致构建错误。

注:您还需要一个local.properties文件,通过sdk.dir属性来设置 SDK 的位置,并且所设置的这个SDK要求存在。
或者,您也可以设置一个ANDROID_HOME环境变量。这两种方法之间没什么差别,你喜欢,你选择。

项目结构

上述的基本构建文件要求有一个默认的文件夹结构。Gradle 遵循约定大于配置的概念,在可能的情况下提供了合理的默认选项值。
基本项目开始于两个名为“source sets”的组件。即主源代码和测试代码。它们分别在:
  • src/main/
  • src/androidTest/
里面的每个文件夹中都存在对应的源代码组件的文件夹。
对于 Java 和 Android 插件,Java 源代码和 Java 资源的位置如下:

  • java/
  • resources/

对于Android 插件,Android所特有的额外的文件和文件夹是:

  • AndroidManifest.xml
  • res/
  • assets/
  • aidl/
  • rs/
  • jni/

注: src/androidTest/AndroidManifest.xml是不需要的,因为它会被自动创建。

配置项目结构

When the default project structure isn’t adequate, it is possible to configure it. 根据 Gradle 文档,为一个Java 项目重新配置 sourceSets可以通过如下方法实现:

sourceSets {
    main {
        java {

srcDir ‘src/java’

        }

        resources {

            srcDir ‘src/resources’

        }

    }

}
注: srcDir实际上会将给定的文件夹添加到现有的源文件夹列表中 (这在Gradle 文档中没有提及,但这是实际的行为)。如果要替换默认的源文件夹,您就要使用传入一个路径数组的srcDirs来代替。以下是使用涉及的对象的另一种不同的方法:

sourceSets {
    main.java.srcDirs = [‘src/java’]
    main.resources.srcDirs = [‘src/resources’]
}

欲了解更多信息,请参阅 Gradle 文档中关于 Java 插件的内容,见这里

Android 插件使用类似的语法,但因为它使用它自己的sourceSets,所以在android对象里面来实现。
这里有一个例子,使用旧的项目结构的主源码并重新映射androidTestsourceSet 到tests文件夹:

android {
sourceSets {
main {
manifest.srcFile ‘AndroidManifest.xml’
java.srcDirs = [‘src’]

            resources.srcDirs = [‘src’]
aidl.srcDirs = [‘src’]

            renderscript.srcDirs = [‘src’]

            res.srcDirs = [‘res’]
assets.srcDirs = [‘assets’]

        }

androidTest.setRoot(‘tests’)
}
}

注意: 因为旧的结构把所有源文件 (java、 aidl、 renderscript和 java 资源) 都放在相同的文件夹中,我们需要重新映射sourceSet的所有这些新组件到相同的src文件夹中。
注意: setRoot()会将整个sourceSet (和它的子文件夹) 移到一个新的文件夹中。这将移动src/androidTest/*tests/*
下。这是 Android 专用的,不适用于 Java sourceSets。这也是一个“迁移”的例子。

构建任务

常规任务

在构建文件中配置使用一个插件,将自动创建一系列要运行的构建任务。Java 插件和 Android 插件都是。

约定的任务如下:

  • assemble
    组装项目的输出的任务
  • check
    运行所有检查的任务。
  • build
    这个任务将执行assemble和check。
  • clean
    这个任务将清理项目的输出

assemble,check和build这些任务,实际上不做任何事情。他们是锚记任务,用于让插件添加实际的任务去做这些事情。这允许您能够调用同样的任务,无论项目的类型是什么,或者是配置使用了什么插件


例如,配置使用findbugs插件将创建一个新的任务和使check任务依赖于它,使得每当调用check任务时都会调用到它。

您可以从命令行中运行下面的命令来获取更高级别的任务:

gradle tasks

下面的命令可以得到一个完整的任务列表,并且看到任务运行之间的依赖关系:

gradle tasks –all

注: Gradle 会自动监视一个任务所声明的输入和输出。
在没有变化的情况下,运行两次build会使 Gradle 报告所有任务为UP-TO-DATE状态,这个状态意味着没有任何事情需要执行。这允许任务正确地相互依赖而无需不必要的构建操作。

Java 项目任务

Java 插件主要创建两个任务,它们是主要锚记任务的依赖任务:

  • assemble
    • jar
      这个任务将创建输出。
  • check
    • test
      这个任务将运行测试。

jar任务本身会直接或间接地依赖其他任务: 例如,classes任务用于编译 Java 代码。
testClasses任务用于编译测试,但它很少会被调用,因为test任务依赖于它 (以及classes任务)。

一般情况下,你将可能永远只调用assemble或check,而无视其他任务。

在这里,你可以看到Java 插件的所有任务和对它们的描述。

Android 任务

Android 的插件使用相同的约定配置以兼容其他插件,并添加了另外的锚记任务:

  • assemble
    组装项目的输出的任务
  • check
    运行所有检查的任务。
  • connectedCheck
    运行需要一个已连接的设备或模拟器的检查。它们将在所有已连接的设备上并行运行。
  • deviceCheck
    使用 API 连接到远程设备运行检查。这一个是在 CI 服务器上使用的。
  • build
    这项任务将执行assemble 和 check
  • clean
    这个任务将清理项目的输出
新的锚记任务是有必要的,以便能够运行定期的检查而无需连接的设备。
注意到,build任务不依赖于deviceCheck或connectedCheck。Android 项目具有至少两个输出: debug版本的APK 和release版本的 APK。这里的每一个输出都有自己的锚记任务,以便单独构建它们:

  • assemble
    • assembleDebug
    • assembleRelease

它们两个都依赖于执行构建一个 APK所需的多个步骤的其他任务。assemble任务取则依赖于这两个任务,所以调用 assemble 将会构建出这两个 APKs。

提示:在命令行上,Gradle 支持任务名称的驼峰命名法的简写。例如:

gradle aR

相当于输入

gradle assembleRelease

只要没有其他任务匹配 “aR”

check锚记任务有它们自己的依赖项:

  • check
    • lint
  • connectedCheck
    • connectedAndroidTest
    • connectedUiAutomatorTest (暂未实现)
  • deviceCheck
    • 这个任务依赖于当其他插件实现了测试扩展点时创建的任务。

最后,该插件为所有构建类型 (debugreleasetest)创建了omstal/uninstall 任务,只要他们可以被安装(需要签名)。

基本的构建定制

Android 插件提供了大量的 DSL,以通过构建系统直接地自定义大部分事情。

清单条目

通过 DSL 可以配置以下清单条目:

  • minSdkVersion
  • targetSdkVersion
  • versionCode
  • versionName
  • applicationId (有效的包名 —— 更多的信息请参阅ApplicationId 与packageName
  • 用于测试应用程序的包名
  • Instrumentation test runner

示例:

android {
    compileSdkVersion 19

    buildToolsVersion “19.0.0”

    defaultConfig {

versionCode 12

        versionName “2.0”

        minSdkVersion 16
targetSdkVersion 16
}

}
android元素的内部的defaultConfig元素是定义所有这些配置的地方。
以前版本的 Android 插件使用packageName来配置清单的“packageName”属性。
从 0.11.0开始,你应该在 build.gradle 中使用 applicationId 来配置清单中的“packageName”条目。
它消除了应用程序的包名(指它的 ID)和java 包名之间的所引起的混乱。

在构建文件中描述它的强大之处是它可以是动态的。
例如,可以从文件中的某处或使用一些自定义的逻辑读取版本信息:

def computeVersionName() {
    …
}
android {
    compileSdkVersion 19
    buildToolsVersion “19.0.0”
    defaultConfig {
        versionCode 12

versionName computeVersionName()
minSdkVersion 16
targetSdkVersion 16
}

}
注意: 不要使用在作用域内可能与已存在的getter函数有冲突的函数名称。例如 defaultConfig { …} 实例调用 getVersionName() 时将自动使用 defaultConfig.getVersionName() 的 getter 方法,而不是自定义的方法。
如果一个属性未通过 DSL 来设置,它将使用默认值。下表描述了对于未设置的属性的处理方式。

 属性名称  DSL 对象中的默认值  默认值
versionCode  -1  如果在清单中存在,则使用清单中的值
versionName  null  如果在清单中存在,则使用清单中的值
minSdkVersion  -1  如果在清单中存在,则使用清单中的值
targetSdkVersion  -1  如果在清单中存在,则使用清单中的值
applicationId  null  如果在清单中存在,则使用清单中的值
testApplicationId  null  applicationId + “.test”
testInstrumentationRunner  null  android.test.InstrumentationTestRunner
signingConfig  null  null
 proguardFile  N/A (只设置)  N/A (只设置)
 proguardFiles  N/A (只设置)  N/A (只设置)

第二列的值是很重要的,如果您在构建脚本中使用自定义逻辑查询这些属性的话。例如,您可以编写:

if (android.defaultConfig.testInstrumentationRunner == null) {
    // assign a better default…
}
如果值仍然为null,那么在构建的时候它将会被设为第三列中的实际默认值,但是由于 DSL 元素不包含此默认值,因此您无法查询它。
这是为了防止解析应用程序的清单,除非真的很需要。

构建类型

默认情况下,Android 插件自动将项目设置为生成应用程序的的debug和release版本。

这两个版本的不同,大多是围绕在调试一个安全的(非开发版的)设备的能力,以及 apk 怎么签名。

调试版本使用自动创建的密钥/证书签名,并且密钥/证书的用户名/密码是已知的(以防止构建过程中需要相关的信息)的。release版本在构建的时候不会进行签名,需要在之后进行签名。

这个配置是通过一个叫BuildType的对象来完成的。默认情况下,2 个实例会被创建,分别是debug版和release版。

Android 插件允许自定义这两个实例,以及创建其他的构建类型。它通过buildTypes DSL 容器来实现:

android {
    buildTypes {
        debug {
            applicationIdSuffix “.debug”
        }
        jnidebug.initWith(buildTypes.debug)
        jnidebug {
            packageNameSuffix “.jnidebug”
            jniDebuggable true
        }
    }
}
上面的代码段可实现以下操作:

  • 配置默认的DebugBuild Type
    • 设置包名为<app appliationId>.debug,以便能够在相同的设备上安装debugrelease两个版本的apk
  • 创建一个叫jnidebug的新的BuildType对象 ,并将其配置为debug生成类型的一个副本。
  • 通过启用 JNI 组件的debug构建,并添加不同的包后缀,继续配置jnidebug。

创建新的 Build Types 就是简单地在buildTypes下添加一个新的元素,然后调用 initWith()或者是使用一个闭包来配置。

以下是可能用到的属性和它们的默认值:

 属性名称  用于 debug的默认值  用于 release/其他 的默认值
debuggable  true  false
jniDebuggable  false  false
renderscriptDebuggable  false  false
renderscriptOptimLevel  3  3
applicationIdSuffix  null  null
versionNameSuffix  null  null
signingConfig  android.signingConfigs.debug  null
zipAlignEnabled  false  true
minifyEnabled  false  false
 proguardFile  N/A (只设置)  N/A (只设置)
 proguardFiles  N/A (只设置)  N/A (只设置)

除了这些属性,Build Types还会影响到构建的代码和资源。
对每个Build Type都会创建一个自动匹配的sourceSet,默认位置为

src/<buildtypename>/

这意味着Build Type的名字不能为main或者是androidTest (这是插件所强制的),并且它们之间必须是唯一的。

与任何其他source set一样,生成类型的source set的位置也是可以重新设置的:

android {
    sourceSets.jnidebug.setRoot(‘foo/jnidebug’)
}

此外,对于每个Build Type,会创建一个新的assemble<BuildTypeName>任务。

已经提到过的assembleDebugassembleRelease这两个任务,这里也会讲一下它们是怎么来的。当debugreleaseBuild Types被预创建的时候,他们的任务也会被自动创建。然后,

上面的build.gradle片段也会生成一个assembleJnidebug任务,并且assemble将会依赖于它,就像它依赖于assembleDebug和assembleRelease任务一样。

提示: 请记住您可以输入gradle aJ来运行assembleJnidebug任务。

可能会用到的情况:

  • release模式下不需要,但debug模式下需要的权限
  • 自定义的debug实现
  • 为调试模式使用不同的资源 (例如某个资源的值与签名证书相绑定时)。

BuildType的代码和资源通过以下方式被使用:

  • manifest将被合并到应用程序的manifest中
  • 代码只是作为另一个源文件夹来起作用
  • 资源将覆盖main里面的资源,并替换已经存在的值。

签名配置

对应用程序进行签名,要求如下:

  • 一个 keystore
  • 一个 keystore 的密码
  • 一个 key 的别名
  • 一个 key 的密码
  • 存储类型

签名文件的位置,key的名称,以及这两个密码和存储类型,一起构成了一个签名配置 ( SigningConfig类型)

默认情况下,有一个debug的配置,配置使用了一个debug keystore。这个keystore使用了一个已知的key和一个已知的密码。
这个debug keystore 位于$HOME/.android/debug.keystore,并且会在不存在时被创建。debug Build Type被设置为自动使用此debug

SigningConfig

你也可以创建其他配置,或者自定义某个默认的内置配置。通过signingConfigs DSL 容器来实现:
android {
    signingConfigs {
        debug {
            storeFile file(“debug.keystore”)
        }
        myConfig {
            storeFile file(“other.keystore”)
            storePassword “android”
            keyAlias “androiddebugkey”
            keyPassword “android”
        }
    }
    buildTypes {
        foo {
            debuggable true
            jniDebuggable true
            signingConfig signingConfigs.myConfig
        }
    }
}

上面的代码段把debug keystore的位置修改为在项目的根位置下。这会自动影响到任何设置为使用它的Build Types,在这里,影响到的是debug Build Type

代码的代码还创建了一个新的Signing Config和使用新配置的新的Build Type 。

注:只有位于默认位置下的debug keystores才会被自动创建。如果debug keystore的位置被更改了,它将不会在需要时自动创建。创建一个使用一个不同的名称SigningConfig,但使用了默认的debug keystore的路径,它也会被自动创建。换句话说,会不会被自动创建与keystore的路径有关,而与配置名称无关。

注: keystore的路径通常使用项目根目录的相对路径,但也可以是使用绝对路径,尽管这不推荐 (除了自动创建的debug keystore)。

注意: 如果您将这些文件加入版本控制,您可能不希望这些文件中有你的密码。下面的 Stack Overflow 链接显示了如何从控制台或环境变量中读取值的方法。

我们会在以后更新本指南补充更详细的信息。

运行ProGuard

ProGuard 是通过 Gradle plugin for ProGuard version 4.10来进行支持的。ProGuard 插件会被自动配置使用,并且如果Build Type通过minifyEnabled属性配置为运行ProGuard,对应的任务将被自动创建。

android {
buildTypes {
release {
minifyEnabled true
proguardFile getDefaultProguardFile(‘proguard-android.txt’)
}
}

    productFlavors {

flavor1 {

        }
        flavor2 {

proguardFile ‘some-other-rules.txt’

        }

}

}
变种使用他们的构建类型中所声明的规则文件,product flavors(定制版本)则使用flavor中声明的规则文件。
这里有 2 个默认的规则文件
  • proguard-android.txt
  • proguard-android-optimize.txt
它们位于 SDK 中。使用getDefaultProguardFile()将返回的文件的完整路径。它们除了是否启用优化之外,其它都是相同的。

依赖、 Android Library和多项目设置

Gradle 项目可以对其他组件具有依赖关系。这些组件可以是外部的二进制包,或其他的 Gradle 项目。

二进制包的依赖

本地包

要配置一个外部库 jar 包的依赖,您需要在compile配置中添加一个依赖关系。

dependencies {
    compile files(‘libs/foo.jar’)
}
android {
    …
}
注意:dependencies DSL 元素是标准的 Gradle API 的一部分,不属于android 元素内。compile配置用于编译主应用程序。里面的所有内容都会被添加到编译类路径,并且打包到最终生成的 apk 当中。
下面是添加依赖时其他可能用到的配置:

  • compile: 主应用程序
  • androidTestCompile: 测试的应用程序
  • debugCompile: debug Build Type
  • releaseCompile: release Build Type.

因为不可能构建一个没有任何关联的Build Type的 APK,apk 总是配置两个(或以上)的配置:compile和<buildtype>Compile。
创建一个新的Build Type会基于它的名字自动创建一个新的配置。

这可能会有用,比如debug版本需要使用一个自定义库(例如报告崩溃的信息),而release版本则不需要,或者是他们依赖于同一个库的不同版本的情况下。

远程文件

Gradle 支持从 Maven 和 Ivy 仓库中拉取文件。

首先,这个仓库必须添加到列表当中,然后必须用Maven 或 Ivy 声明文件的方式声明这个依赖。

repositories {
    mavenCentral()
}
dependencies {
    compile ‘com.google.guava:guava:11.0.2’
}
android {
    …
}
注: mavenCentral()是指定maven中央仓库的URL的快捷方法。Gradle支持远程和本地仓库。
注:Gradle 将遵循所有依赖关系的传递性。这意味着,如果一个依赖有它自己的依赖关系,这些依赖也会被拉取。有关设置依赖关系的更多信息,请参阅 Gradle 用户指南(这里),和DSL文档(这里)。

多项目设置

Gradle 项目也可以通过使用多项目设置依赖于其他的 Gradle 项目。

一个多项目设置通常是通过让所有的项目作为给定根项目的子文件夹来实现。

例如,给定以下项目结构:

MyProject/
 + app/
 + libraries/
    + lib1/
    + lib2/
我们可以识别出3个项目。Gradle 将通过以下名称引用它们:
:app
:libraries:lib1
:libraries:lib2
每一个项目都有其自己的build.gradle文件,定义自己如何构建。
此外,在根路径下还将有一个叫settings.gradle的文件用于声明所有的项目。
这些文件的结构如下:
MyProject/
 | settings.gradle
 + app/
    | build.gradle
 + libraries/
    + lib1/
       | build.gradle
    + lib2/
       | build.gradle
settings.gradle的内容很简单:

include ‘:app’, ‘:libraries:lib1’, ‘:libraries:lib2’

它定义了哪个文件夹实际上是一个 Gradle 项目。
:app项目可能依赖于libraries,这是通过声明如下的依赖关系来配置的:
dependencies {
    compile project(‘:libraries:lib1’)
}
关于多项目设置的更多常用信息请参阅这里

库项目

在上面的多项目的设置中,:libraries:lib1和:libraries:lib2可以是Java项目,而:app Android项目将会使用到它们的jar包输出。
但是,如果你想共享访问了 Android API或使用了 Android-style的资源的代码,这些库项目就不能是普通的Java项目,而应该是 Android Library 项目。

创建库项目

Library项目与普通的 Android 项目非常相似,只有一些不同。

由于构建库项目与构建应用程序有些不同不同,所以使用的是不同的插件。这两个插件内部共享了大部分的相同的代码,并且它们都由同样的com.android.tools.build.gradle jar 包提供。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath ‘com.android.tools.build:gradle:0.5.6’
    }
}
apply plugin: ‘android-library’
android {
    compileSdkVersion 15
}

上面的例子中创建了一个使用API 15编译的库项目。SourceSets和依赖关系与它们在应用程序项目中的处理方式一样,并且支持同样方式的自定义。

普通项目和Library 项目之间的区别

一个 Library 项目主要输出的是一个.aar包(它代表Android的归档文件)。它组合了编译代码(如一个jar文件或原生的.so文件)和资源(manifest,res,assets)。
一个库项目还可以生成测试apk,独立于应用程序测试这个库。
库项目用着同样的锚任务(assembleDebug, assembleRelease),所以构建这样一个项目的命令也没有任何区别。
对于其他的内容,库项目和应用程序项目的行为是一样的。。他们都有构建类型(build types)和产品定制(product flavors),并且都可以生成多个版本的aar。
需要注意的是,Build Type的大部分配置都不适用库项目。但是,您可以根据一个库项目是否被其他项目使用还是被测试,使用自定义 sourceSet 来更改库项目的内容。

引用一个库项目

引用一个库库和引用其他任何项目的方法是一样的:

dependencies {
    compile project(‘:libraries:lib1’)
    compile project(‘:libraries:lib2’)
}

注意: 如果您有多个库,那么排序将非常重要。这类似于旧的生成系统中, project.properties 文件的依赖项的顺序的重要性。

库项目发布

默认情况下,一个库项目只发布它的release variant。这variant将被所有引用该库的项目使用,无论那些项目构建的是哪种variant。这是由于 Gradle 限制而有的一个临时限制,我们正在努力消除这个问题。
您可以控制要发布哪一个variant
android {
    defaultPublishConfig “debug”
}
注意,这个发布的配置名称引用的是完整的 variant 名称。releasedebug,只在没有定义flavor时适用。如果你想在使用flavors时更改默认的发布variant,你可以这样写:
android {
    defaultPublishConfig “flavor1Debug”
}

发布一个库项目的所有variants也是可以做到的。我们正计划在正常的项目对项目(project-to-project)的依赖(如上面的例子)时也可以这样做,但现在因为 Gradle 的限制(我们也在努力修复这些问题),还无法做到。

默认情况下没有启用发布所有variant。要启用它们可以这样做:

android {
    publishNonDefault true
}
发布多个variants意味着发布多个aar文件,而不是发布一个包含多个variants的aar文件,能意识到这一点是非常重要的。每一个 aar 包都是包含一个单一的variant。
发布一个variant,意识着让这个可用的 aar 作为 Gradle 项目的输出文件。这个文件将会在发布到一个maven仓库中,或者另一个项目创建对这个项目依赖时用到。
Gradle 有一个默认文件的概念。它就是在编写下面的代码时用到的:

compile project(‘:libraries:lib2’)

若要创建对一个项目的另一个已发布的文件的依赖,您需要指定使用哪一个:
dependencies {
    flavor1Compile project(path: ‘:lib1’, configuration: ‘flavor1Release’)
    flavor2Compile project(path: ‘:lib1’, configuration: ‘flavor2Release’)
}
 

重要说明:注意已发布的配置是一个完整的variant,包括生成类型,并且需要像以上那样被引用。

重要说明:当启用非默认的发布时,Maven 发布插件将把这些额外的variant作为额外的包(按分类器分类)发布。这意味着它对发布到一个 maven 仓库并不是真正的兼容。您应该只向一个仓库发布一个单一的 variant,或者是,为项目之间的依赖启用所有的发布配置。

测试

构建一个测试应用程序已经集成到应用程序项目中了。所以已经没有必要再去创建一个单独的测试项目。

基础知识和配置

正如前面所提及,在main sourceSet旁边的是androidTest sourceSet,默认情况下,它位于src /androidTest/
从这里的 sourceSet 构建出来的是一个测试的apk,它可以部署到设备上,使用 Android 的测试框架去测试应用程序。它可以包含单元测试、 instrumentation 测试和后来的 uiautomator 测试。这个
SourceSet 不应该包含 AndroidManifest.xml ,因为它是会自动生成的。下面是可以用来配置测试应用程序的几个值:

  • testPackageName
  • testInstrumentationRunner
  • testHandleProfiling
  • testFunctionalTest

正如前面所看到的,它们在defaultConfig对象中配置:

android {
    defaultConfig {
        testPackageName “com.test.foo”
        testInstrumentationRunner “android.test.InstrumentationTestRunner”
        testHandleProfiling true
        testFunctionalTest true
    }
}

在测试程序里的manifest里的instrumentation节点中,targetPackage属性的值会自动设为被测试的应用程序的包名称,即使它通过defaultConfig或Build Type对象自定义过。这是manifest 自动生成的原因之一。

此外,sourceSet可以配置自己的依赖。
默认情况下,应用程序和它自己的依赖都会被添加到测试应用程序的classpath中,但是也可以通过以下来扩展

dependencies {
    androidTestCompile ‘com.google.guava:guava:11.0.2’
}

这个测试程序是由assembleTest任务构建的。它不是main里的assemble任务的依赖项,当设置测试运行时它不会被自动调用。

目前只有一种Build Type会进行测试。默认情况下是debugBuild Type,但它可以被重新配置:

android {
    …
    testBuildType “staging”
}

运行测试

正如前面提到的,通过锚任务 connectedCheck运行的检查,需要一个已连接的设备。

它依赖于任务androidTest,因此将运行 androidTest。该任务执行以下操作:

  • 确保应用程序和测试应用程序都被构建 (依赖于 assembleDebug 和 assembleTest)
  • 安装这两个应用程序
  • 运行测试
  • 卸载这两个应用程序。

如果连接了多个设备,所有的测试都会并行运行在所有连接的设备上。如果任何一个设备的其中一项测试失败,那么整个构建都将失败。

所有测试结果都会保存为 XML 文件,路径为

build/androidTest-results

(这类似于 jUnit 定期运行的结果保存在 build/text-result 下面)

它可以通过以下方式来配置
配置

android {
    …
    testOptions {
        resultsDir = “$project.buildDir/foo/results”
    }
}

Android.testOptions.resultsDir的值将通过Project.file(String) 获得

测试 Android Libraries

测试 Android Library项目与测试应用程序项目的方式完全一样。

唯一的区别是整个库 (和它的依赖项) 会自动作为Library依赖添加到测试应用程序中。结果就是测试 APK 不只包含其自己的代码,还包括测试库以及测试库的所有依赖项。
这个Library的manifest 会合并到测试应用程序的manifest中(如引用此Library的任何项目)。

AndroidTest任务改为仅安装 (以及卸载)测试 APK (因为没有其他的 APK 要安装)

其他的都是相同的。

测试报告

当运行单元测试时,Gradle 会输出 HTML 报告,以方便查看结果。
Android 插件在此基础上扩展了 HTML 报告,它聚合了所有连接的设备的测试结果。

单个项目的报告

这个测试报告的项目会在运行测试时自动生成。它的默认位置是

build/reports/androidTests

它类似于 jUnit 报告的位置build/reports/tests,或其他通常位于build/reports/<plugin>/的报告。这个位置可以通过以下方式自定义

android {
    …
    testOptions {
        reportDir = “$project.buildDir/foo/report”
    }
}

该报告将聚合在不同的设备运行的测试。

多项目报告

在一个设置了一个或多个application和 library 项目的多项目中,当同时运行所有的测试,为所有测试生成单个报告可能是非常有用的。

要做到这一点,需要使用同一个文件中的另一个插件。这个插件可以如下配置:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath ‘com.android.tools.build:gradle:0.5.6’
    }
}
apply plugin: ‘android-reporting’

这个插件应该在根项目中配置使用,即在 settings.gradle同级目录的build.gradle中。

然后在根文件夹中,下面的命令就可以运行所有的测试并聚合测试报告:

gradle deviceCheck mergeAndroidReports –continue

注: –continue选项确保所有子项目的测试都会被运行,即使其中的一个子项目的测试失败了。如果不加上这个选项,第一个失败的测试将会中断所有测试的运行,这可能导致有些项目还没有执行它们的测试。

Lint 支持

从 0.7.0 版本起,您可以为一个指定的variant或所有的variants 运行lint,在这种情况下,它会生成一个报告,描述每一个给定的问题都存在于哪些指定的variants 。
您可以通过添加以下的一个 lintOptions 节点对lint进行配置。通常,您只需要指定其中的几个 ;以下列出了所有可用的选项。

android {

    lintOptions {

        // 设置为 true时lint将不报告分析的进度
        quiet true
        // 如果为 true,则当lint发现错误时停止 gradle构建
        abortOnError false
        // 如果为 true,则只报告错误
        ignoreWarnings true
        // 如果为 true,则当有错误时会显示文件的全路径或绝对路径 (默认情况下为true)
        //absolutePaths true
        // 如果为 true,则检查所有的问题,包括默认不检查问题
        checkAllWarnings true
        // 如果为 true,则将所有警告视为错误
        warningsAsErrors true
        // 不检查给定的问题id
        disable ‘TypographyFractions’,’TypographyQuotes’
        // 检查给定的问题 id
        enable ‘RtlHardcoded’,’RtlCompat’, ‘RtlEnabled’
        // * 仅 * 检查给定的问题 id
        check ‘NewApi’, ‘InlinedApi’
        // 如果为true,则在错误报告的输出中不包括源代码行
        noLines true
        // 如果为 true,则对一个错误的问题显示它所在的所有地方,而不会截短列表,等等。
        showAll true
        // 重置 lint 配置(使用默认的严重性等设置)。
        lintConfig file(“default-lint.xml”)
        // 如果为 true,生成一个问题的纯文本报告(默认为false)
        textReport true
        // 配置写入输出结果的位置;它可以是一个文件或 “stdout”(标准输出)
        textOutput ‘stdout’
        // 如果为真,会生成一个XML报告,以给Jenkins之类的使用
        xmlReport false
        // 用于写入报告的文件(如果不指定,默认为lint-results.xml)
        xmlOutput file(“lint-report.xml”)
        // 如果为真,会生成一个HTML报告(包括问题的解释,存在此问题的源码,等等)
        htmlReport true
        // 写入报告的路径,它是可选的(默认为构建目录下的 lint-results.html )
        htmlOutput file(“lint-report.html”)

   // 设置为 true, 将使所有release 构建都以issus的严重性级别为fatal(severity=false)的设置来运行lint

   // 并且,如果发现了致命(fatal)的问题,将会中止构建(由上面提到的 abortOnError 控制)

   checkReleaseBuilds true

        // 设置给定问题的严重级别(severity)为fatal (这意味着他们将会
        // 在release构建的期间检查 (即使 lint 要检查的问题没有包含在代码中)
        fatal ‘NewApi’, ‘InlineApi’
        // 设置给定问题的严重级别为error
        error ‘Wakelock’, ‘TextViewEdits’
        // 设置给定问题的严重级别为warning
        warning ‘ResourceAsColor’
        // 设置给定问题的严重级别(severity)为ignore (和不检查这个问题一样)
        ignore ‘TypographyQuotes’
    }

}

Build Variants

新的构建系统的目标之一是可以创建同一个程序的不同版本。

这里有两个主要的使用场景:

  1. 同一应用程序的不同版本
    例如,一个应用的免费/演示版本 和“专业”付费版本。
  2. 为了在Google Play Store发布同一个程序的多个APK,而使用不同的包名。
    请参阅 http://developer.android.com/google/play/publishing/multiple-apks.html 以获取更多详细信息。
  3. 综合了1和2 两种情况

这个目标就是要让从同一个项目生成这些不同的APK成为可能,而不是使用一个单独的类库项目和两个以上的应用程序项目中来生成。

Product flavors

一个product flavor 定义了由一个项目构建的应用程序的自定义版本。单个项目可以有不同的flavors来改变生成的应用程序。

这个新概念的设计是为了解决不同版本之间差异很小的情况。如果“这是同一个应用程序吗?”的答案是肯定回答,那么把它转为Library Project的做法也是可以的。

Product flavors使用一个productFlavors DSL 容器来声明:

android {
    ….
    productFlavors {
        flavor1 {
            …
        }
        flavor2 {
            …
        }
    }
}
上面的代码创建了两个flavor,分别是flavor1 和 flavor2。
注意:flavors的名字不能和已经存在的Build Type 的名字或者是 androidTest 的 sourceSet有冲突。

Build Type + Product Flavor = Build Variant

正如我们之前所看到的,每一个Build Type 都会生成一个新的 APK。

Product Flavors 也一样:项目的输出变成 Build Types 和Product Flavors(如果有定义)的所有可能的组合。

每一个 (Build TypeProduct Flavor)组合都称为一个 Build Variant

例如,通过和默认的 debug 和 releaseBuild Types的组合,上面的例子会生成四个 Build Variants:

  • Flavor1 – debug
  • Flavor1 – release
  • Flavor2 – debug
  • Flavor2 – release

即使项目没有定义 flavor,也仍然会有 Build Variants,但是是使用 默认的 flavor或配置。它没有名字,所以使 variants和列表看起来和 Build Types的列表一样。

Product Flavor 配置

每个flavor都通过一个闭包进行配置:

android {
    …
    defaultConfig {
        minSdkVersion 8
        versionCode 10
    }
    productFlavors {
        flavor1 {
            packageName “com.example.flavor1”
            versionCode 20
        }
        flavor2 {
            packageName “com.example.flavor2”
            minSdkVersion 14
        }
    }
}

请注意, android.productFlavors.*对象的类型是ProductFlavor ,和android.defaultConfig对象的类型一样。这意味着它们共享相同的属性。

defaultConfig提供所有flavor的基本配置,并且每个flavor都可以重写配置里的任何值。在上面的示例中,这个配置最终会是:

  • flavor1
    • packageName: com.example.flavor1
    • minSdkVersion: 8
    • versionCode: 20
  • flavor2
    • packageName: com.example.flavor2
    • minSdkVersion: 14
    • versionCode: 10

通常情况下,Build Type的配置将覆盖其他的配置。例如, Build Type的 packageNameSuffix 将会追加到 Product Flavor的 packageName后面。

也有一些情况是,一个设置可以同时在 Build Type 和 Product Flavor中设置。在这种情况下,就因情况而异了。

例如, signingConfig 就是一个这样的属性。
它既可以通过设置 android.buildTypes.release.signingConfig使所有的relase包都共享相同的SigningConfig,也可以通过单独地设置每一个android.productFlavors.*.signingConfig 对象来让每一个release包使用它们自己的SigningConfig

Sourcesets 和 Dependencies

和 Build Types 一样, Product Flavors 也会通过它们自己的 sourceSets提供源代码和资源。

上面的例子中创建了四个 sourceSets

  • android.sourceSets.flavor1
    位于 src/flavor1/
  • android.sourceSets.flavor2
    位于 src/flavor2/
  • android.sourceSets.androidTestFlavor1
    位于 src/androidTestFlavor1/
  • android.sourceSets.androidTestFlavor2
    位于 src/androidTestFlavor2/

这些sourceSets用于与android.sourceSets.mainBuild Tupe sourset一起构建 apk。

当处理所有的 sourcesets 来生成单个的 APK 时,下面的规则将会被用到:

  • 多个文件夹里的所有源代码 (src / * / java) 都会一起用于生成一个输出。
  • 所有manifest会被合并为一个manifest。这使得Product Flavors类似于Build Types,可以有不同的组件或权限。
  • 所有的资源(Android res 和 assets)使用的覆盖优先级为Build Type 覆盖 Product Flavor,并最终覆盖 mainsourceSet
  • 每一个Build Variant都根据资源生成其自己的R类 (或其他生成的源代码)。variant之间不共享任何内容。

最后,像Build Types一样,Product Flavors可以有它们自己的依赖。例如,如果flavor用于生成广告版的应用程序和付费版的应用程序,其中一个flavor可能要依赖广告的 SDK,而另一个不需要。

dependencies {
    flavor1Compile “…”
}
在这种特殊的情况下,src/flavor1/AndroidManifest.xml文件可能需要包含访问网络的权限。
每一个variant也会创建额外的sourceSets:
  • android.sourceSets.flavor1Debug
    位于 src/flavor1Debug/
  • android.sourceSets.flavor1Release
    位于 src/flavor1Release/
  • android.sourceSets.flavor2Debug
    位于 src/flavor2Debug/
  • android.sourceSets.flavor2Release
    位于 src/flavor2Release/
这些都有比构建类型的sourcesets更高的优先级,并且允许在variant的层次上进行自定义。

Building 和 Tasks

我们在之前已经看到,每个Build Type都会创建自己的assemble<name>任务,但Build VariantsBuild TypeProduct Flavor的一种组合。

当使用Product Flavor 时,会创建更多的assemble类型的任务。它们是:

  1. assemble<Variant 名称>
  2. assemble<Build Type 名称>
  3. assemble<Product Flavor 名称>

#1 允许直接构建一个单一的variant例如assembleFlavor1Debug

#2 允许构建指定的一个Build Type 的所有APK。例如assembleDebug将会构建Flavor1Debug和Flavor2Debug 两个variant。

#3 允许构建一个指定的flavor的所有APK。例如assembleFlavor1将会构建Flavor1Debug和Flavor1Release的两个variant。

assemble 任务将构建所有可能组合的variant。

测试

测试multi-flavors项目与测试简单的项目非常相似。

androidTest sourceset 是所有flavors的共用的测试,而每一个flavor 也都可以有自己的测试。

正如上所述, 用于测试每一个flavor的sourceSets会被创建:

  • android.sourceSets.androidTestFlavor1
    位于 src/androidTestFlavor1/
  • android.sourceSets.androidTestFlavor2
    位于 src/androidTestFlavor2/

同样,它们也可以有其自己的依赖项:

dependencies {
    androidTestFlavor1Compile “…”
}

这些测试可以通过main deviceCheck锚任务或main androidTest任务(当使用flavors时会被作为锚任务)来完成执行。

每一个flavor都有自己的任务来运行测试: androidTest<VariantName>。例如:

  • androidTestFlavor1Debug
  • androidTestFlavor2Debug

同样,每一个variant也都有对应的测试 APK 构建任务和install/uninstall的任务:

  • assembleFlavor1Test
  • installFlavor1Debug
  • installFlavor1Test
  • uninstallFlavor1Debug

最后,HTML 报告支持通过 flavor 合并生成。
测试结果和报告的位置如下,首先为每个flavor版本,然后是聚合之后的版本:

  • build/androidTest-results/flavors/<FlavorName>
  • build/androidTest-results/all/
  • build/reports/androidTests/flavors<FlavorName>
  • build/reports/androidTests/all/

自定义上面的任一路径,将只更改根文件夹,并且仍然会创建每一个flavor的子文件夹和聚合后的结果及报告。

Multi-flavor variants

在某些情况下,人们可能想要基于多个标准创建同一个应用程序的多个版本。
比如,在Google Play中的多 apk 支持,能支持4个不同的过滤器。创建不同 APK并能在每个过滤器中区分,需要能够使用多维的Product Flavors。以一个游戏为例,假如需要有深圳版本,付费版本,并且想要在多版本支持中使用ABI过滤器。这个应用程序带有三个ABI和两种版本,就需要生成6个APK(不计算由不同的Build Types引入的variants)。
然而,对这三种ABI来说付费版本的代码是相同的,因此创建6个flavors来实现并不是一个好办法。
相反,使用两个维度的flavor,并且variant应该自动构建所有可能的组合。

这个功能是使用Flavor Dimensions来实现的。把 Flavor 分配到指定的维度中

android {
    …
    flavorDimensions “abi”, “version”
    productFlavors {
        freeapp {
            flavorDimension “version”
            …
        }
        x86 {
            flavorDimension “abi”
            …
        }
    }
}

android.flavorDimensions数组定义了可能的维度以及顺序。每个定义的Product Flavor被分配到一个维度。

通过以下维度的 Product Flavors [freeapp, paidapp] 和 [x86, arm, mips],以及Build Types的 [debug, release] 的组合,将创建以下的build variant:

  • x86-freeapp-debug
  • x86-freeapp-release
  • arm-freeapp-debug
  • arm-freeapp-release
  • mips-freeapp-debug
  • mips-freeapp-release
  • x86-paidapp-debug
  • x86-paidapp-release
  • arm-paidapp-debug
  • arm-paidapp-release
  • mips-paidapp-debug
  • mips-paidapp-release

android.flavorDimensions定义的维度顺序是非常重要的。

每一个variant都通过几个Product Flavor对象来配置:

  • android.defaultConfig
  • abi 维度中的一个对象
  • version维度中的一个对象

维度的顺序决定了哪一个flavor将覆盖其他的flavor,这对于资源来说非常重要,因为一个flavor的值会替换定义在低优先级的flavor中的值。
flavor 维度首先被定义为具有较高的优先级。所以在这种情况下:

abi > version > defaultConfig

Multi-flavors项目也有额外的 sourcesets,类似于 variant 的 sourcesets,但是没有构建类型:
  • android.sourceSets.x86Freeapp
    位于 src/x86Freeapp/
  • android.sourceSets.armPaidapp
    位于 src/armPaidapp/
  • 等等……
上面这些都允许在flavor-combination的级别上进行自定义。它们有着比基本的 sourcesets更高的优先级,但低于构建类型的sourcesets的优先级。

高级构建定制

构建选项

Java 编译选项

android {
    compileOptions {
        sourceCompatibility = “1.6”
        targetCompatibility = “1.6”
    }
}
默认值为“1.6”。这个配置会影响所有编译 Java 源代码的任务。

aapt 选项

android {
    aaptOptions {
        noCompress ‘foo’, ‘bar’
        ignoreAssetsPattern “!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~”
    }
}
这个配置会影响所有使用aapt的任务。

dex 选项

android {
    dexOptions {
        incremental false

        preDexLibraries = false

        jumboMode = false

    }
}
这个配置会影响所有使用dex 的任务。

操作任务

基本的 Java 项目有一组有限的任务能够共同协作来创建一个输出。
其中classes 任务是将 Java 源代码进行编译的那个任务。
build.gradle通过简单地在脚本中使用classes就能很容易地访问它。这是project.tasks.classes的简洁写法。

在 Android 项目中,它会比较复杂一点,因为可能有大量的相同的任务并且他们的名字都是基于Build TypesProduct Flavors生成。

android对象中有两个(译者注:我怎么感觉是三个。难道是原文笔误?)属性就是为解决这个问题的:

  • applicationVariants(仅适用于应用程序插件)
  • libraryVariants(仅适用于库插件)
  • testVariants (对两个插件都适用)

这三个会分别返回ApplicationVariant、LibraryVariant和TestVariant的DomainObjectCollection对象。

注意,访问这些集合的任何一个都将触发所有任务的生成。这意味着在访问这些集合之后不应该再进行(重新)配置。

DomainObjectCollection可以对所有对象进行直接访问,或通过过滤器(这将会很方便)过滤。

android.applicationVariants.each { variant ->
    ….
}
这三个variant 类都有以下属性:

 属性名称  属性类型  描述
 name  String  variant的名称。必须保证是唯一的。
 description  String  人类可读的对variant的描述。
 dirName  String  variant的子文件夹名称。必须保证是唯一的。可能会是多个文件夹,即”debug/flavor1″
 baseName  String  variant的输出的基础名称必须保证是唯一的。
 outputFile  File  variant的输出。这是一个可读可写的属性
 processManifest  ProcessManifest  处理manifest的任务。
 aidlCompile  AidlCompile  编译AIDL文件的任务。
 renderscriptCompile  RenderscriptCompile  编译Renderscript文件的任务。
 mergeResources  MergeResources  合并资源的任务。
 mergeAssets  MergeAssets  合并assets的任务。
 processResources  ProcessAndroidResources  处理和编译资源的任务。
 generateBuildConfig  GenerateBuildConfig  生成 BuildConfig 类的任务。
 javaCompile  JavaCompile  编译 Java 代码的任务。
 processJavaResources  Copy  处理 Java 资源的任务。
 assemble  DefaultTask  variant 的assemble锚任务。

ApplicationVariant 类增加了以下属性:

 属性名称  属性类型  描述
 buildType  BuildType  variant 的 BuildType。
 productFlavors  List<ProductFlavor>  variant 的 ProductFlavors。总是不为null,但可以是空集合。
 mergedFlavor  ProductFlavor  对android.defaultConfig 和 variant.productFlavors的合并
 signingConfig  SigningConfig  用于 variant 的 SigningConfig 对象
 isSigningReady  boolean  如果该 variant 有签名所需的所有信息则为true。
 testVariant  BuildVariant  将会测试该variant的TestVariant
 dex  Dex  将代码生成dex的任务。如果variant是一个库,这个值可以为 null。
 packageApplication  PackageApplication  打包最终的APK的任务。如果variant是一个库,这个值可以为 null。
 zipAlign  ZipAlign  对apk进行zipaligns(优化对齐)的任务。如果variant是一个库或者APK不能被签名,这个值可以为 null。
 install  DefaultTask  安装任务。可以为 null。
 uninstall  DefaultTask  卸载任务。

LibraryVariant 类增加了以下属性:

 属性名称  属性类型  描述
 buildType  BuildType  variant 的 BuildType。
 mergedFlavor  ProductFlavor  DefaultConfig 的值
 testVariant  BuildVariant  将会测试该variant 的 Build Variant
 packageLibrary  Zip  打包成Library AAR 归档文件的任务。如果不是库项目可以为null。

TestVariant 类增加了以下属性:

 属性名称  属性类型  描述
 buildType  BuildType  variant 的 BuildType。
 productFlavors  List<ProductFlavor>  variant 的 ProductFlavors。总是不为null,但可以是空集合。
 mergedFlavor  ProductFlavor  对android.defaultConfig 和 variant.productFlavors的合并
 signingConfig  SigningConfig  用于 variant 的 SigningConfig 对象
 isSigningReady  boolean  如果该 variant 有签名所需的所有信息则为true。
 testedVariant  BaseVariant  经过TestVariant测试过的BaseVariant。
 dex  Dex  将代码生成dex的任务。如果variant是一个库,这个值可以为 null。
 packageApplication  PackageApplication  打包最终的APK的任务。如果variant是一个库,这个值可以为 null。
 zipAlign  ZipAlign  对apk进行zipaligns(优化对齐)的任务。如果variant是一个库或者APK不能被签名,这个值可以为 null。
 install  DefaultTask  安装任务。可以为 null。
 uninstall  DefaultTask  卸载任务。
 connectedAndroidTest  DefaultTask  在已连接的设备上运行 android 测试的任务。
 providerAndroidTest  DefaultTask  使用扩展 API 运行android 测试的任务。
Android 的特定任务类型的 API。

  • ProcessManifest
    • File manifestOutputFile
  • AidlCompile
    • File sourceOutputDir
  • RenderscriptCompile
    • File sourceOutputDir
    • File resOutputDir
  • MergeResources
    • File outputDir
  • MergeAssets
    • File outputDir
  • ProcessAndroidResources
    • File manifestFile
    • File resDir
    • File assetsDir
    • File sourceOutputDir
    • File textSymbolOutputDir
    • File packageOutputFile
    • File proguardOutputFile
  • GenerateBuildConfig
    • File sourceOutputDir
  • Dex
    • File outputFolder
  • PackageApplication
    • File resourceFile
    • File dexFile
    • File javaResourceDir
    • File jniDir
    • File outputFile
      • 要修改最终输出的文件,可以在 variant 对象上直接使用“outputFile”(译者注:1.0 版本通过variant获取到的是outputs,是一个List,需要通过对其遍历或取第一个元素variant.outputs[0].outputFile才能获得outputFile对象)。
  • ZipAlign
    • File inputFile
    • File outputFile
      • 要修改最终输出的文件,可以在 variant 对象上直接使用“outputFile”(译者注:1.0 版本通过variant获取到的是outputs,是一个List,需要通过对其遍历或取第一个元素variant.outputs[0].outputFile才能获得outputFile对象)。
由于Gradle的工作原理以及Android 插件的配置方式,用于每个任务类型的API会有所限制。
首先,Gradle 想要让任务只能配置输入或输出的位置和可能使用的可选标志。所以在这里,这些任务只能定义一些输入或输出。
其次,这些任务的绝大多数的输入都是有实际意义的,它们往往来自sourceSetsBuild TypesPruduct Flavor的混合值。为了保持构建文件易于阅读和理解,目的是要让开发人员通过DSL进行稍微调整就可以修改构建,而不是要深入任务的选项和输入并且去修改它们。
此外注意到,除了 ZipAlign 任务类型,所有其他类型都需要设立私有数据来让它们正常运行。这意味着不可能手动创建这些类型的新任务。

这个 API 也可能会被更改。一般情况下,当前 API 是围绕着任务给定的输出或输入(如果可能)的入口来添加额外的处理的(如果需要)。欢迎反馈意见,特别是那些未预知的需求。

关于 Gradle 任务 (DefaultTask,JavaCompile,Copy,Zip),请参阅 Gradle 文档。

BuildType 和 Product Flavor 的属性参考

即将推出。
关于 Gradle 任务 (DefaultTask,JavaCompile,Copy,Zip),请参阅 Gradle 文档。 <br4>

使用 sourceCompatibility 1.7

通过 Android KitKat (buildToolsVersion 19),你可以使用钻石运算符(即<>),multi-catch,在switch语句中使用string, try with resources等等。要做到这一点,请将以下配置添加到您的构建文件中:
android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"
    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 19
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}
注意,你可以把 minSdkVersion 的值设为19之前的版本,只是你只能使用除了try with resources之外的其他新语言特性。如果你想要使用 try with resources,你就需要把minSdkVersion 也设为 19。
你还需要确认 Gradle 使用JDK 1.7或更高的版本。(并且Android Gradle 插件也需要0.6.1或更高的版本。)

批量读取productFlavors

productFlavors {
        def path="./channel.txt"
        file(path).eachLine { line->
            def words = line.split(':')
            def key = words[0]
            def channel = words[1]
            if (key == '') {
                key = channel
            }
            def name = 's'+channel
            "$name" {
                manifestPlaceholders=[APP_KEY_PLACEHOLDER:key, APP_PID_PLACEHOLDER:name]
            }
        }
    }