Android官方技术文档翻译——Gradle 插件用户指南(1-3)

时间:2024-01-21 11:01:35

不知道是什么网络问题,上午一直发不了博客,其它页面基本正常,就是在写博客这里,每次打开都是响应超时。刚才用了VPN,顺便试了一下,竟然能够编辑。想是CDN之类的问题吧。

这次翻译的是Gradle 插件用户指南,也就是Gradle上的Android插件的官方文档。文档非常长,加上近期激情不够,翻译得有些慢。到昨天为止,才译到第四章。今天先发前三章。

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

翻译不易,转载请注明CSDN博客上的出处:

http://blog.csdn.net/maosidiaoxian/article/details/41944325

翻译工作耗时费神,假设你认为本文翻译得还OK,请点一下“顶”,我在精神上会倍受鼓舞的,谢谢。翻译如有错讹,敬请指正。

Gradle 插件用户指南

Android官方技术文档翻译——Gradle 插件用户指南(1-3)

文件夹

  1. 简单介绍
    1. 1.1 新构建系统的目标
    2. 1.2 为什么是 Gradle ?
  2. 要求
  3. 基本项目
    1. 3.1 简单的构建文件
    2. 3.2 项目结构
      1. 3.2.1 配置项目结构
    3. 3.3 构建任务
      1. 3.3.1 常规任务
      2. 3.3.2 Java 项目任务
      3. 3.3.3 Android 任务
    4. 3.4 基本生成的自己定义
      1. 3.4.1 清单条目
      2. 3.4.2 Build Types
      3. 3.4.3 签名配置
      4. 3.4.4 运行混淆
  4. 依赖、
    Android Library和多项目设置
    1. 4.1 二进制包的依赖
      1. 4.1.1 本地包
      2. 4.1.2 远程文件
    2. 4.2 多项目设置
    3. 4.3 Library项目
      1. 4.3.1 创建一个 Library 项目
      2. 4.3.2 普通项目和Library
        项目之间的差别
      3. 4.3.3 引用Library项目
      4. 4.3.4 Library项目的公布
  5. 測试
    1. 5.1 基础知识和配置
    2. 5.2 执行測试
    3. 5.3 測试 Android Library
    4. 5.4 測试报告
      1. 5.4.1 单个项目
      2. 5.4.2 多项目报告
    5. 5.5 Lint 的支持
  6. Build Variants
    1. 6.1 Product flavors
    2. 6.2 Build
      Type + Product Flavor = Build Variant
    3. 6.3 Product Flavor
      配置
    4. 6.4 Sourcesets 和 Dependencies
    5. 6.5 Building 和 Tasks
    6. 6.6 測试
    7. 6.7 Multi-flavor variants
  7. 高级构建自己定义
    1. 7.1 构建选项
      1. 7.1.1 Java 编译选项
      2. 7.1.2 aapt 选项
      3. 7.1.3 dex 选项
    2. 7.2 操纵任务
    3. 7.3 BuildType
      和 Product Flavor 的属性引用
    4. 7.4 使用 sourceCompatibility
      1.7

简单介绍

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

新构建系统的目标

新的构建系统的目标是:
  • 能够非常easy地重用代码和资源
  • 能够非常easy地创建应用程序的几个变种,不管是多APK分发还是不同定制版的应用程序
  • 能够非常easy地配置、 扩展和自己定义构建过程
  • 好的 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对象里面来实现。 

这里有一个样例,使用旧的项目结构的主源代码并又一次映射androidTest sourceSet 到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 server上使用的。
  • 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 怎么签名。



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



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



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


android {
    buildTypes {
        debug
{
         
  applicationIdSuffix ".debug"
        }

        jnidebug.initWith(buildTypes.debug)
        jnidebug {
            packageNameSuffix ".jnidebug"
            jniDebuggable true
        }
    }
}


上面的代码段可实现下面操作:
  • 配置默认的Debug Build 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 的password
  • 一个 key 的别名
  • 一个 key 的password
  • 存储类型

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



默认情况下,有一个debug的配置,配置使用了一个debug keystore。这个keystore使用了一个已知的key和一个已知的password。 

这个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)。

注意: 假设您将这些文件增加版本号控制,您可能不希望这些文件里有你的password。以下的 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()将返回的文件的完整路径。它们除了是否启用优化之外,其他都是同样的。