gradle简单解析
gradle概述
Gradle 是 Android 现在主流的编译工具,对于一些简单的程序我们几乎不需要任何代码上的配置只使用 Android Studio 就可以完成编译和运行。
通过了解gradle,我们可以做:
- 自定义编译输出文件格式
- hook Android 编译过程
- 配置和改善 Gradle 编译速度
- 等等…
gradle编译周期
在解析 Gradle 的编译过程之前我们需要理解在 Gradle 中非常重要的两个对象。Module和Task。
每个项目的编译至少有一个 Module,一个 build.gradle
就代表一个Module
,每个Module
里面包含了多个task
,task
里面又包含很多action
,action
是一个代码块,里面包含了需要被执行的代码。
在编译过程中, Gradle 会根据 build
相关文件,聚合所有的Module
和task
,执行task
中的 action
。因为 build.gradle
文件中的task非常多,先执行哪个后执行那个需要一种逻辑来保证。这种逻辑就是依赖逻辑,几乎所有的Task
都需要依赖其他 task
来执行,没有被依赖的task
会首先被执行。所以到最后所有的 Task
会构成一个 有向无环图(DAG Directed Acyclic Graph)的数据结构。
编译过程分为三个阶段:
- 初始化阶段:创建 Project 对象,如果有多个build.gradle,也会创建多个project。
- 配置阶段:在这个阶段,会执行所有的编译脚本,同时还会创建project的所有的task,为后一个阶段做准备。
- 执行阶段:在这个阶段,gradle 会根据传入的参数决定如何执行这些task,真正action的执行代码就在这里。
gradle file tree
对于一个android studio工程,最基本的配置如下:
MyApp
->build.gradle
->setting.gradle
->[app]
->build.gradle
一个项目有一个setting.gradle
、包括一个顶层的 build.gradle
文件、每个Module
都有自己的一个build.gradle
文件。
- setting.gradle:这个 setting 文件定义了哪些module 应该被加入到编译过程,对于单个module 的项目可以不用需要这个文件,但是对于 multimodule 的项目我们就需要这个文件,否则gradle 不知道要加载哪些项目。这个文件的代码在初始化阶段就会被执行。
- 顶层的build.gradle:顶层的build.gradle文件的配置最终会被应用到所有项目中。它典型的配置如下:
buildscript {
repositories {
//一个知名的maven代码仓库
jcenter()
}
dependencies {
// Android 编译工具的类路径
classpath 'com.android.tools.build:gradle:2.2.2'
}
}
//定义的属性会被应用到所有 moudle 中,但是为了保证每个项目的独立性,我们一般不会在这里面操作太多共有的东西
allprojects{
repositories{
jcenter()
}
}
- 每个项目单独的 build.gradle:针对每个moudle 的配置,如果这里的定义的选项和顶层build.gradle定义的相同,后者会被覆盖。典型的 配置内容如下:
//使用Android 程序的gradle插件,该插件提供了Android 编译、测试、打包等等的所有task。
apply plugin: 'com.android.application'
//关于android 的所有特殊配置
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.torch.easydev.okhttpdemo"
minSdkVersion 17
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
//定义编译类型,针对每个类型我们可以有不同的编译配置
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
//定义了当前项目需要依赖的其他库
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
...
}
gradle wrapper
除了以上几个gradle相关的文件,新建一个studio工程,默认还会生成一些和gradle wrapper相关的一些文件:
MyApp
->gradlew
->gradlew.bat
->gradle
->wrapper
->gradle-wrapper.jar
->gradle-wrapper.properties
那这个gradle-wrapper
有什么用呢?主要是用于gradle版本的兼容性问题,gradlew.bat
是一个可执行文件,当开始sync project时,首先会根据gradle-wrapper.properties
文件中gradle的版本号去查找本地,如果本地不存在会去网上下载对应的版本。
gradle使用指南
简单了解了gradle的作用和相关文件的结构之后,接下来主要结合项目过程常见的使用场景,来看看具体该如何使用gradle。
导入第三方库或者工程
日常开发过程中,经常会碰到要使用第三方库或者工程做二次开发,这时候免不了要导入,导入步骤为:
File->New->import project
找到对应的project所在的位置,找到顶层的`build.gradle`点击确定即可
导入后常常会碰到一直在sync project,最后更新还不成功。
这时候主要检查以下几个地方:
1、检查gradle-wrapper.properties
中的gradle版本号。可以和本地原有项目直接比对,若不同会从网上下载,但默认情况下更新会失败,因为gradle的下载地址被墙了。这时候要不使用代理地址;要不就直接更改为本地已下载完成的gradle版本号。
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
//更改为本地已下载的gradle版本号
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
2、检查各个module下的build.gradle文件的
android sdk版本号。要和本地的sdk版本号相对应,否则需要更新到当前配置的sdk版本号才行。
android {
//要和本地sdk版本相对应
compileSdkVersion 22
buildToolsVersion '23.0.3'
...
}
3、检查各个module下的build.gradle
文件的依赖库版本号。
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//support版本要和sdk manager下载的v7库相对应
compile 'com.android.support:appcompat-v7:23.3.0'
testCompile 'junit:junit:4.12'
}
解决上面这些问题后,基本上可以正常导入第三方库或者工程啦。如果还有问题,就要结合实际情况分析了。
eclipse项目迁移到android studio
点击File->New->import project 找到eclipse项目根目录,导入。
导入jar包
- 将jar包复制到对应工程module的libs文件夹下
- 配置
build.gradle
依赖
dependencies {
//第一种方法,直接配置编译libs下所有jar包
compile fileTree(include: ['*.jar'], dir: 'libs')
//第二种方法,配置对应的jar包
compile files('libs/AMap_Location_V3.4.0_20170427.jar')
}
添加.so文件
- 在libs下新建一个文件夹,名称为armeabi, 将so文件复制到该文件夹下。
- 配置
build.gradle
文件
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
自定义包名及版本号
android {
...
defaultConfig {
//自定义包名
applicationId "com.boc.spos.service"
minSdkVersion 17
targetSdkVersion 23
versionCode 4
//版本号
versionName "1.0.4"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
当AndroidManifest.xml
文件中也配置包名和版本号时,已build.gradle
文件的配置为主。
需要注意的是,在我们曾经定义的AndroidManifest.xml中,那里定义的包名有两个用途:一个是作为程序的唯一识别ID,防止在同一手机装两个一样的程序;另一个就是作为我们R资源类的包名。在以前我们修改这个ID会导致所有用引用R资源类的地方都要修改。但是现在我们如果修改applicationId只会修改当前程序的ID,而不会去修改源码中资源文件的引用。
自定义APK文件名
// rename the apk with the version name
// add output file sub folder by build type
applicationVariants.all {
variant ->
def time = new java.text.SimpleDateFormat("yyyyMMdd").format(new Date())
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent + "/${variant.buildType.name}",
"MyApp_${variant.versionName}_${variant.productFlavors[0].name + time}.apk".toLowerCase())
}
}
将会生成格式为:MyApp_1.0.0_debug20170527.apk的一个文件
不同签名打包
一个产品,在开发阶段和发布阶段,经常需要使用不同的签名,以前在eclipse要通过导出两次apk来实现这个目的。现在有了gradle,只需要简单配置一下build.gradle
,就能实现啦。
android {
//用于演示,同一个签名
signingConfigs {
debug {
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
}
release {
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.debug
}
}
}
配置gradle.properties
文件
RELEASE_KEY_PASSWORD=android
RELEASE_KEY_ALIAS=androiddebugkey
RELEASE_STORE_PASSWORD=android
RELEASE_STORE_FILE=E:/star-net/keystore/test.keystore
多渠道打包
android {
...
productFlavors {
Inner {
resValue("string" , "IS_DEBUG_MODE", "true")
}
PROC {
resValue("string" , "IS_DEBUG_MODE", "false")
}
}
}
代码中,根据配置好的变量做相应版本的处理
private static String IS_DEBUG_MODE_GRADLE = HuaxiaBankApplication.getContext().getResources().getString(R.string.IS_DEBUG_MODE);
当然,也可以通过不同的buildConfig来配置不同的版本
android {
...
productFlavors {
Inner {
buildConfigField "boolean", "IS_DEBUG", "false"
}
PROC {
buildConfigField "boolean", "IS_DEBUG", "true"
}
}
}
同样的在代码中,根据配置好的变量做相应版本的处理
Log.d("MyApp", "开始初始化: IS_DEBUG=" + BuildConfig.IS_DEBUG);
参考资料
Gradle完整指南:http://www.jianshu.com/p/9df3c3b6067a#
装载请注明出处:http://blog.youkuaiyun.com/youyu_torch/article/details/72786723, 谢谢!!