β

理解Android Gradle构建系统

稀有猿诉 159 阅读
 

Gradle是一个新型的强大的构建系统。Android很早就开始支持Gradle了,到现在已经完全切换到Gradle构建。它的优势也是比较明显的,更强大的配置,方便的依赖管理,简洁的语法(Groovy DSL),跟啰嗦的XML相对,这是很大的进步。

基本概念

为了方便讨论和理解,需要对一些概念进行定义:

项目结构

典型的项目结构是酱紫的:

|-project
| |-app
| | |-build.gradle
| |-library1
| | |-build.gradle
| |-build.gradle
| |-settings.gradle
| |-gradle/wrapper/gradle-wrapper.properties
| |-local.properties
| |-gradle.properties
 include ':app', ':library1'

当然,这是典型的项目结构,但是没有完全这样,因为Gradle的配置是相当灵活且强大的,也就是说真实的文件夹结构,跟Gradle中的项目结构是没有关系的,只不过默认的情况下(也即没有特别的指定和定制)模块的名字就是子目录的名字,项目的结构就按文件夹结构来确定的。

但是可以不用这样,下面详细说

配置非文件夹结构的项目

意思就是每一个模块,不一定非在项目所在文件夹里,换句话说,你可以在项目中引用随便在哪里的模块,举个例子:

你的项目project是在,Documents/project/,想引用一个库是在Downloads/library/,不必非把library拷贝到project下面,只需要在project/settings.gradle中配置一下就可以了:

include ':app', ':library'

project(':library').projectDir = new File(settingsDir, '../../../Downloads/library')

这样就可能在项目project中引入了模块library。

分清楚二个版本

Gradle是一个构建系统,像make和cmake,ant和maven一样。安卓的项目里推荐使用gradle wrapper,实际上就是在项目中指定gradle的版本,这样有一个好处就是,这个项目换了操作系统环境,也不受影响。我们都知道软件的不同的版本对软件的使用是有影响的。所以如果像make或者cmake一样,使用操作系统环境中的gradle,那么同一个项目会因为不同的环境而带来一些诡异的配置相关的问题。

Gradle跟Android或者Google没有关系,它是由Gradle Inc.在开发和维护的。所以Gradle的升级要到 gradle.org

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

Gradle是一个构建系统,有它自身的规则,可以用来构建任何语言的任何项目。但每一个语言和平台都有自己的特性,如果直接使用Gradle也不是不可以,但是要做很多重复性的工作。Gradle是有插件机制的,也就是每个语言或者平台实现一些Gradle插件,以让开发者更加方便来构建,而不从头一条指令一条的写。Android Gradle Plugin就是专门用来构建安卓应用开发相关的插件。这个是由Google开发并维护,与SDK一起发布的。

常见命令

除了在Android Studio中直接操作以外,gradle是支持命令行的。而且命令行有时候会更方便。执行的方式是./gradlew 。gradlew实际上就是一个Shell脚本,它的作用是运行gradle/wrapper/中的Gradle二进制文件。task(任务)是Gradle构建中的可执行单元,与makefile中的target有些类似,可以理解为一个应用的构建,就是执行一些定义好的task。常见的task有:

可以用gradle tasks来查看支持的所有任务。

Dependency managament

在每个模块的build.gradle中dependencies {} DSL中定义该模块的依赖树。

dependencies {
  // 本地lib的依赖
  compile fileTree(dir: 'libs', include: ['*.jar'])

  // 对其他模块的依赖
  compile (project(':library'))

  // 从远程的repo中下载依赖
  compile "com.android.support:support-v4:23.1.0"
  compile 'com.android.support:appcompat-v7:23.0.0'
  compile 'com.squareup.picasso:picasso:2.5.2'
}

有几种不的指定编译方式:

常见的tricks

./gradle/wrapper/gradle-wrapper.properties中的distributionUrl=https://services.gradle.org/distributions/gradle-2.14.1-all.zip,这个地址下载十分缓慢,或者根本无法下载,导致gradle sync花费很长时间,甚至卡死无法完成。改成国内的镜像会好很多distributionUrl=http://mirrors.taobao.net/mirror/gradle/gradle-2.14.1-all.zip

如果没有可用的镜像网站,还有一个解决办法就是,去其他网站下载Gradle的二进制文件,然后解压放到~/.gradle/wrapper/dists/。(如果是windows的话,应该是在C:\Users\.gradle\wrapper\dists)。

dependencies {
  compile ('com.squareup.picasso:picasso:2.5.2') {
    transitive false
  }
}

依赖是一个树状结构,比如项目中依赖了rxlifecircle,但rxlifecircle本身也有依赖,解析依赖时,会把所有依赖以及依赖的依赖都下载下来,这就构成了依赖树,当然,也会涉及冲突的处理,比如二个库都依赖了另外一个库,但是不同的版本,这个Gradle本身是有策略的。

可以用./gradlew -q dependencies –configuration compile命令来查看依赖树 * 指定依赖的具体类型@aar or @jar

dependencies {
  compile "com.android.support:support-v4:23.1.0"
  compile 'com.android.support:appcompat-v7:23.0.0'
  compile 'com.squareup.picasso:picasso:2.5.2@jar'
}

默认情况,Gradle认为依赖库都是Java 的jar类型。也就说当其在repo中寻找依赖时会去找jar。所以,如果是aar的依赖库,就需要指定其具体类型,通过在版本号后面加上@aar或者@jar来指定其具体的类型。

FAILURE: Build failed with an exception.

* What went wrong: A problem occurred configuring root project ‘pailitao-sdk’. Could not resolve all dependencies for configuration ‘:classpath’.

> Could not find com.android.tools.build:gradle:2.2.2.

Searched in the following locations: file:/Users/alexhilton/.m2/repository/com/android/tools/build/gradle/2.2.2/gradle-2.2.2.pom file:/Users/alexhilton/.m2/repository/com/android/tools/build/gradle/2.2.2/gradle-2.2.2.jar https://repo1.maven.org/maven2/com/android/tools/build/gradle/2.2.2/gradle-2.2.2.pom https://repo1.maven.org/maven2/com/android/tools/build/gradle/2.2.2/gradle-2.2.2.jar Required by: :pailitao-sdk:unspecified

* Try:

Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

这个问题的根本原因是Android Gradle Plugin没有找到。查看要目录的build.gradle,在repositories里面加上jcenter(),或者把mavenCenteral()改成jcenter()就可以解决了。

 |-project
 | |-app
 | |-library

在根目录执行命令./gradlew assembleDebug或者assembleRelease,会构建整个应用。假如只想构建library呢?可以执行这样的命令: ./gradlew :library:assembleRelease 也即,前面是子项目,后面跟命令。

这个错误的原因是Android Studio运行的JVM版本太低了,看一下Android Studio的关于,里面会有JVM的版本信息,如果是1.6就会上面的错误。如果是Mac,到app/info.list里面把JVM的版本改成1.7+

明显是Gradle运行时,内存爆了。解决方法就是加大它的内存配额。在相应的build.gradle中加入:

dexOptions {
  incremental true
  javaMaxHeapSize 4g
}

查看根目录的build.gradle通常都指定有github的插件,把1.3升级到1.4.1就可以解决,参考 这篇文章

默认情况下,当有compile project(‘:library’)形式的依赖时,只会编译library的release模式,这对调试是非常不方便的,因为release模式通常会开启混淆,这时可以在子模块中加入默认的打包配置来强制默认打debug包:

android {
  defaultPublishConig 'debug'
}

进阶之Gradle

对于日常的开发,了解基本的就够用了,但若想做一些额外的事情,比如自定义一些task等就需要深入研究Gradle本身了。这个建议直接看Gradle的 文档 比较好。

进阶之Groovy

Gradle的文件是用Groovy语言来描述的,所以如果想要实现高级功能,也必须熟悉Groovy语言。同样还是要参考相应的文档。

参考资料

 
作者:稀有猿诉
原文地址:理解Android Gradle构建系统, 感谢原作者分享。

发表评论