Android开发中Gradle配置的相关概念

Gradle是一个项目构建工具,类似Maven,可用于管理项目内部组件的依赖关系,完成自动化构建。因为Android Studio生成的Android项目默认使用gradle进行构建,因此大多数Android程序员都要跟它打交道,今天这篇文章主要想厘清Android开发中与gradle相关的一些简单但是很基础的概念。

项目自动化构建

首先想一下我们为什么需要项目的自动化构建工具,一般的开发中我们点一下Run/Debug按钮等一会apk就自动装到手机上去了,但实际上发生了很多我们看不到的事:

  • xml文件被编译成二进制文件,aidl文件编译成java,一些编译时的java代码被生成(如R文件)
  • java代码被编译成*.class字节码,最后编译成dex文件
  • 代码文件和资源文件放到一起被打包
  • 使用密钥进行安装包的签名,然后进行字节对齐的优化

以上是大致过程(细节或许有出入),其中每个过程还可以配置详细的参数(比如资源编译处理时的进程数、class编译到dex过程中进程数量、堆大小等等),如果这些小步骤都要程序员一步步去做就太繁琐了(可以看看这篇文章:手动命令行编译APK)。我们可以写一个脚本自动化地去做这些事(也就是说不用gradle这类的工具也是可以的),但是一个项目也许会引用到几十上百个库、模块之间存在复杂的依赖关系,而且项目构建还涉及到清理(clean)、测试、模块发布等环节,因此使用自动化构建工具就会方便很多。

Gradle与Wrapper

Gradle可以直接去官网下载安装,但一般没这个必要,因为Android Studio会自带一个Gradle,就在Android Studio的安装目录下。同时Gradle也支持我们在没有安装 Gradle 的机器上运行 Gradle 构建,方法就是使用Gradle wrapper。这里的gradle wrapper可以理解为一个绿色版的便携的gradle。

在Android开发中,一个团队内可能每个人机器上的gradle版本是不一样的,版本不一样可能导致构建出现问题,因此Android Studio对于项目默认是使用gradle wrapper的,而不是使用本地gradle。每个项目根目录下的gradle目录内都有一个gradle-wrapper.properties文件,里面规定了这个项目使用的gradle版本。一般Android Studio打开加载一个新的项目时会根据这个文件的内容去下载相应版本的gradle wrapper,当然如果本地已经有了这个版本的gradle wrapper就不用下载了。对于Windows系统,下载的wrapper一般在“C://用户目录/.gradle/wrapper/dists”下

假设gradle-wrapper.properties的内容如下:

#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

则说明将会去下载2.14.1的gradle wrapper,一般我们打开一个github上下载下来的项目,很容易卡死在这个环节(因为gradle.org服务器在国外,网速慢)。一般有多种解决办法:

  • 从国内站点下一个wrapper,这样网速快很多,然后拷到本地的"C://用户目录/.gradle/wrapper/dists"下,注意命名一致
  • 修改gradle-wrapper.properties里的版本号,找一下本地有哪些下好的版本,直接修改成这个版本,但是我是不推荐这么做,因为
    • 替换成不同版本的gradle wrapper可能导致构建失败,因为不同版本的特性可能不一样,如果只是下一个demo看看则无所谓,如果是团队协作应保证版本的一致

基本概念

在Gradle中,比较重要的两个概念就是projects和tasks。每一个构建都是由一个或多个 projects 构成的,每一个 project 是由一个或多个 tasks 构成的,一个 task 代表一些更加细化的构建, 可能是编译一些 classes, 创建一个 JAR, 生成 javadoc, 或者生成某个目录的压缩文件。

每一次Android Studio为我们自动生成的项目里的build.gradle文件里,我们可以找到:

task clean(type: Delete) {
    delete rootProject.buildDir
}

这里就定义了叫做clean的task,我们可以在命令行里使用命令gradlew tasks来查看当前目录下的build.gradle文件里的tasks列表。我对一个新建的空项目使用了这个命令,得到如下信息:

: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 - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
clean - Deletes the build directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.

Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'Demo'.
components - Displays the components produced by root project 'Demo'. [incubating]
dependencies - Displays all dependencies declared in root project 'Demo'.
dependencyInsight - Displays the insight into a specific dependency in root project 'Demo'.
help - Displays a help message.
model - Displays the configuration model of root project 'Demo'. [incubating]
projects - Displays the sub-projects of root project 'Demo'.
properties - Displays the properties of root project 'Demo'.
tasks - Displays the tasks runnable from root project 'Demo' (some of the displayed tasks may belong to subprojects).

Install tasks
-------------
installDebug - Installs the Debug build.
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
uninstallAll - Uninstall all applications.
uninstallDebug - Uninstalls the Debug build.
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
uninstallRelease - Uninstalls the Release build.

Verification tasks
------------------
check - Runs all checks.
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
connectedCheck - Runs all device checks on currently connected devices.
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
test - Run unit tests for all variants.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.

Other tasks
-----------
clean
extractProguardFiles
jarDebugClasses
jarReleaseClasses
transformResourcesWithMergeJavaResForDebugUnitTest
transformResourcesWithMergeJavaResForReleaseUnitTest

To see all tasks and more detail, run gradlew tasks --all

To see more detail about a task, run gradlew help --task <task>

BUILD SUCCESSFUL

Total time: 14.137 secs

可以看到名为clean的task已经在Other Task分类下。让gradle执行一个task的命令是"gradle 任务名",在Android Studio的命令行下也可以用"gradlew 任务名"(gradlew是gradle wrapper的意思)。因此对于上面列出的task清单,可以分别去跑这些task,如:

gradlew init
gradlew build
gradlew clean

这些task具体是干什么的就不做深究了。另外gradle/gradlew命令后面可以跟参数:比如加-q就是静默构建,不显示任何log信息,加--info就是显示info级别的log信息,加--debug就是显示debug级别的log信息。

Gradle 默认在 src/main/java 目录下查找项目源代码, 在 src/test/java 目录下查找测试代码, 因此Android Studio生成的项目的目录结构是跟gradle有关系的。(在Eclipse上开发的Android项目的目录就跟AS生成的不一样)

Gradle使用groovy语言来描述构建脚本,groovy语言跟Java比较像。这里不多介绍了。

Android Plugin

Gradle最早的版本在2007年发布,而Android手机2008年才出现,Gradle其实跟Android开发本来是没有什么关系的,直到Google开始推Android Studio后Gradle才在Android开发中慢慢使用开来。

Google推出了Android Gradle Plugin,以便在Android项目中使用gradle进行自动化构建。Android Studio生成的build.gradle自动引入了Android Gradle Plugin,在项目根目录的build.gradle中可以看到:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

这里的2.2.3就是Android Plugin的版本号。如果我们要使用别的gradle插件(如android-apt),就要在这里的dependencies里添加相应的类路径(classpath),否则就可能报找不到插件之类的错误。
Google开发的Gradle插件有3种:

  • com.android.application
  • com.android.library
  • com.android.test

字面上就可以看出,分别是用于应用、库和测试模块的。应用这些插件的代码在项目的子模块下的build.gradle文件里:

apply plugin: 'com.android.application'

一般在引入插件后,下面就两个代码块:

android {
    compileSdkVersion xx
    buildToolsVersion "xxx"
    defaultConfig {
      xxx
    }
    buildTypes {
      xxx
    }
}

dependencies {
  xxx
}

一般就是android{}和dependencies{}。其中android代码块里面的各种配置全部源自于com.android.xxx 这个插件内,我们可以通过阅读官方文档进行相关参数的配置。而dependencies代码块内一般是对项目所需要各种库的描述。我们都知道,在GitHub上找到了一个合适的库,只要Maven仓库里有,就可以直接用一句 "compile xxx.xxx:abc:x.y.z" 代码就可以引入到项目里,项目构建时就会自动下载并添加到依赖项里。

相关配置

根据官方文档,android{}内有以下选项可以配置:

aaptOptions { }
adbOptions { }
buildTypes { }
compileOptions { }
dataBinding { }
defaultConfig { }
dexOptions { }
externalNativeBuild { }
jacoco { }
lintOptions { }
packagingOptions { }
productFlavors { }
signingConfigs { }
sourceSets { }
splits { }
testOptions { }

但不是每个选项都会经常用到。经常用到的可能有:

  • signingConfigs{} 用于配置签名信息
  • splits{} 可以根据dpi、abi进行分包
  • productFlavors {} 多渠道打包
  • dexOptions{} 加速编译

groovy语言可以使配置能加灵活和强大,不过我还在学习中,没法展开了。

参考文档

Gradle User Guide的中文翻译
android plugin的参考文档
Android项目构建官方文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • 1.构建Android应用程序的Gradle。1.1 使用Gradle Android应用程序。默认情况下,A...
    Cfvdjnl阅读 1,040评论 1 2
  • Gradle对于很多开发者来说有一种既熟悉又陌生的感觉,他是离我们那么近,以至于我每天做项目都需要他,但是他又是离...
    阿_希爸阅读 9,513评论 10 199
  • 前言 为什么需要学Gradle? Gradle 是 Android 现在主流的编译工具,虽然在Gradle 出现之...
    真笨笨鱼阅读 1,459评论 0 0
  • 今天看到个帖子,大概是“80后看得懂,90后看半懂,00后全军覆没”,勾起了心里的怀旧情绪。小时候看感觉没什么,现...
    苦寂生阅读 439评论 0 2