引言 {#引言}
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与Wrapper}
Gradle可以直接去官网下载安装,但一般没这个必要,因为Android Studio会自带一个Gradle,就在Android Studio的安装目录下。同时Gradle也支持我们在没有安装 Gradle 的机器上运行 Gradle 构建,方法就是使用Gradle wrapper
。这里的Gradle wrappe
r可以理解为一个绿色版的便携的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的内容如下:
|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| #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
文件里,我们可以找到:
|---------------|------------------------------------------------------------------|
| 1 2 3
| task clean(type: Delete) { delete rootProject.buildDir }
|
这里就定义了叫做clean
的task
,我们可以在命令行里使用命令gradlew tasks
来查看当前目录下的build.gradle
文件里的tasks
列表。我对一个新建的空项目使用了这个命令,得到如下信息:
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| :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,如:
|---------------|--------------------------------------------------|
| 1 2 3
| 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 {#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中可以看到:
|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11
| 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文件里:
|-----------|-------------------------------------------------|
| 1
| apply plugin: 'com.android.application'
|
一般在引入插件后,下面就两个代码块:
|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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{}内有以下选项可以配置:
|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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项目构建官方文档
参考链接:https://www.jianshu.com/p/a54a49424f7a