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语言可以使配置能加灵活和强大,不过我还在学习中,没法展开了。