Gradle In Action

前言

从2013年Google推出Android Studio(后面以AS简称)开始,到现在已经历经3年,版本也发展到了2.x版本,目前Android开发者基本上已经没有再用Eclipse开发的了。从Eclipse切换到AS,项目组织结构和环境变动很大,不过上手AS还是很简单的,新建一个项目,选择API版本,选择一个默认的空Activity,然后点击确定一个项目就创建好了,直接点击运行就可以把项目运行到你手机上或者模拟器上面。

上面很容易创建了一个Android项目,然后就可以愉快的进行开发了。很快遇到了一个需要显示网络图片的需求,先看看网上有没有现成的轮子,随便一搜发现Facebook出品的一个叫Fresco的库,网上一片好评,那就用它了。安装官方说明,找到项目build.gradle文件,在dependencies段加入如下一行

 compile 'com.facebook.fresco:fresco:0.14.1'  

同步一下项目,然后在代码中发现已经可以引用到fresco库了,虽然不懂是怎么解决的,但是既然已经能用了 ,就继续开发。很快项目开发好了,准备发版测试了,突然QA提出要记录每次打包的时间,显示在应用内的调试页面,这样以免以后撕逼时乌龙,果然是老司机!怎么实现呢?官方文档翻了几遍,终于看到一篇讲怎么注入变量到Manifest里面的:

android {    
        defaultConfig {        
                manifestPlaceholders = [hostName:"www.example.com"]    
        }    ...
}  

思路有了,我在AndroidManifest里面配置一个变量表示打包时间BUILD_TIME,然后打包时利用上面的方法把当前时间赋值给BUILD_TIME,程序从AndroidManifest中读取BUILD_TIME显示到调试面板中,经历各种Google细节完成如下:

<!--AndroidManifest中配置打包时间->
<meta-data android:name="BUILD_TIME"    android:value="${BUILD_TIME}" />

def releaseTime() { 
   return new Date().format("yyyyMMdd hh:mm:ss", TimeZone.getTimeZone("GMT+8"))
}
defaultConfig {    
    multiDexEnabled true    
    applicationId "xxxxx"     
    minSdkVersion 16   
    targetSdkVersion 23    
    versionCode 3    
    versionName "1.1.1"    
    manifestPlaceholders = [BUILD_TIME:"${releaseTime()}"]
}

程序运行下看看,竟然好使!等等,defaultConfig里面那堆东西看起来那么面熟啊,这不是AndroidManifest里面配置的东西么,这里面到底还能塞进来什么东西?我咋知道minSdkVersion有没有拼写错误啊?不管了,反正程序现在能跑,赶紧继续发版,今天还要早点下班约会,虽然不知道跟谁约。
刚打好包运营妹子就跑了过来,说哥哥我要发四十个渠道,每个渠道都要统计用户量,你就扔给我一个包,真的好吗?额,这个等一下,马上处理。统计渠道好搞,应用中都集成了友盟,只需要在下面的配置里写上渠道名,打个包,再修改渠道号打包,重复四十次就能搞定了。

<meta-data    android:name="UMENG_CHANNEL"    android:value="360" />

当然我不会这么傻手动打包四十次,好歹也是计算机科班出身的码农,虽然我确实不知道该怎么办,但是我可以问百度啊(这事可以问百度,渠道和友盟都是国情嘛)。很快找到解决方案:

productFlavors 
{        
    360{}
    yingyongbao{}
    wandoujia{}
    xiaomi{}
    ......      
}
productFlavors.all { flavor ->    
     flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE:name]
}
buildTypes {        
    debug {            
        ......
    }        
    release {            
        buildConfigField "boolean", 
        minifyEnabled true            
        zipAlignEnabled true            
        shrinkResources true            
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'            
        signingConfig signingConfigs.release            
        applicationVariants.all { variant ->                
                 variant.outputs.each { output ->                    
                         def outputFile = output.outputFile                    
                         if (outputFile != null && outputFile.name.endsWith('.apk')) { 
                              //MyApp_xiaomi_2016-10-18_v6.2.0.apk                       
                                def fileName = "MyApp_${variant.productFlavors[0].name}_${releaseTime()}_v${defaultConfig.versionName}.apk"                       
                             output.outputFile = new File(outputFile.parent, fileName) 
                      }                
               } 
        } 
     }    
}

果不其然,问题完美解决,但是现在真的没办法淡定的继续写开发了,这里一坨一坨的东西不把它弄清楚,相信后面的日子会很难过,那么我们就开始研究一下这些东西吧。

1. Gradle For Android

Google在推出AS的时候就说了采用Gradle替代Ant来构建项目,不难猜出,上面我们写的就是Gradle“代码”了,那我们再来看一下Gradle到底是什么东西。很快我们找到了它的官方用户手册—https://docs.gradle.org/current/userguide/userguide.html, 里面它是这样自我介绍的:“a build system that we think is a quantum leap for build technology in the Java (JVM) world”,它谦虚的表示自己是Java世界中编译技术的一项巨大突破的一个编译系统,使用了Groovy作为编译脚本,定义了大量的领域模型(domain model)。嗯,还不是很懂它在讲什么,那么我们先把文档看一遍吧。。。纳尼,竟然72节,有点看不下去,并且看标题很多跟Android没关系,还是先学会怎么写点简单的Android配置吧。还好Android官方文档里面有一章介绍怎么用Gradle配置工程(https://developer.android.com/studio/build/index.html), Gradle官网上也有也有一个模块专门介绍Gradle在Android中的应用(https://gradle.org/getting-started-android-build/#build-master), 并且提供了一本电子书和一个讲解视频,那就赶紧先上车吧。

1.1 Gradle Wrapper

当构建一个项目时,往往要需要对应的工具支持,如果本地没有安装或者本地安装的版本和项目要求的不一致时,就会比较麻烦。Gradle引入了Gradle Wrapper很好的解决了这个问题。我们先看一下Gradle Wrapper的组成部分:
- gradlew (Unix Shell script)
- gradlew.bat (Windows batch file)
- gradle/wrapper/gradle-wrapper.jar(Wrapper JAR)
- gradle/wrapper/gradle-wrapper.properties(Wrapper properties)

看起来是不是很眼熟,去看一下上面创建的Android项目,可以看到项目根目录就有这几个文件,gradlew和gradlew.bat分别是Unix系和Windows系操作系统下的命令,打开gradle-wrapper.properties,可以看到有下面的一行配置:

distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-all.zip

这个即本项目需要的gradle版本号。平时执行Gradle命令任务时,使用的是

gradle <task>

但是以后你可以使用(Mac上,windows上类似) :

./gradlew <task>

它会先看当前是否已经安装gradle并且当前指定的gradle版本本地已经存在,如果不是的话,它就先自动下载对应的gradle版本然后在执行task。如果想改变当前项目对应的gradle版本,可以直接编辑gradle-wrapper.properties文件或者在AS中打开module setting,选择”Project”选项,在右边可以直接编辑。也可以使用下面两种方式:

gradle wrapper --gradle-version 2.14

task wrapper(type: Wrapper) { 
    gradleVersion = ' 2.14  '
}
1.2 Gradle 项目结构

Gradle所有的工作就是基于projects和tasks,我们可以先暂时不用理解什么是projects和tasks。每一个Gradle构建都包含一个或多个project,而每一个project就是一个待编译的工程,它通常包含一系列的task。Gradle要求每一个project在它根目录下都要有一个build.gradle,官方称一个build.gradle文件为”编译脚本”,它定义了一个project和它的tasks。在继续之前,我们可以先写个小例子熟悉一下,创建一个文件build.gradle,打开并且输入一下代码:

task taskX(dependsOn: 'taskY') << { 
    println 'taskX'
}
task taskY << { 
    println 'taskY'
}

在同级目录输入如下命令看下输出

gradle taskX

上面就是一个简易的project。如果一个项目里面有多个project怎么办?平时开发时经常会把一个项目拆分成多个子项目。这种情况Gradle中称作Multi-Projects Build,一个Multi-Projects Build由一个根project和一个或多个子project组成,这些子project也 可以包含自己的子project,它的组织结构如下:

root/
   build.gradle
   settings.gradle
   subpro1/
       build.gradle   
  subpro2/
      build.gradle

我们可以看到每个project都要对应一个build.gradle,这个我们上面已经讲过了,但是这里在根目录多出来一个settings.gradle。这个就是Multi-Projects Build的奥妙所在,这个settings.gradle主要用来配置这个Multi-Projects Build包含哪些子project。如果你有多子工程的Android项目,打开看看gradle的结构是不是跟上面一样。当然,如果你不想把subpro1和subpro2放到root目录下也没关系,只需要在setting.gradle中指定子project的目录即可,参考目录结构和setting配置:

project/
    root/
        build.gradle
        settings.gradle
        app/
            build.gradle    
    subpro1/
        build.gradle
    subpro2
        build.gradle


//setting.gradle
include ':app', ':subpro1', ':subpro2'
def projectTreeRootDir = new File("../");
project(":subpro1").projectDir = new File(projectTreeRootDir, "subpro1");
project(":subpro2").projectDir = new File(projectTreeRootDir, "subpro2");

如果你重来没有使用过Multi-Projects Build项目,建议你尝试一下怎么为当前项目添加一个子Module,对的,在Android Studio中每个子项目叫做Module,以后你项目大了,肯定有必要把它拆成多个Module。创建过程很简单,在Project视图下,在当前项目根目录上面右键,”new”->”Module”->”Android Library” (或者”Phone & Tablat Module”),这里就不贴图了。

1.3 Gradle Recipes For Android

前戏了这么久,该进入正文了,我们打开自己的Android项目,挨个研究一下里面的Gradle配置吧。

settings.gradle:

它位于根目录下,用来配置构建一个应用时都需要编译那些module,所以你项目中的所以子project都要在这里配置,通常如下:

include ':app', ':submodule1', ':submodule2'
Top-level build.gradle:

它位于根目录下,用来配置此项目下所有module都应用的设置。下面是常见的一个例子以及说明。

/**
 buildscript{}块配置Gradle自己的仓库(repositories)和依赖(dependencies),
 如下面所示,Gradle如果想要能编译Android项目,需要依赖谷歌提供的一个gradle插件 
 (Gradle Plugin),它里面包含了一些编译需要的指令。
*/  
buildscript {   

   /**
    repositories{}配置了Gradle查找和下载依赖的仓库,通常它默认配置了JCenter、
    Maven Central 和 Ivy等远程仓库,你也可以配置自己的本地仓库和私人远程仓库。
   */
   repositories {        
        jcenter()    
   }

   /**
    dependencies {} 配置了Gradle编译项目需要的依赖,这里制定了依赖2.0.0版本
    的Gradle Plugin
   */
   dependencies {        
        classpath 'com.android.tools.build:gradle:2.0.0'    
    }
}

/**
 allprojects {}配置你项目中所有module都使用的仓库(repositories)和依赖
 (dependencies)。*/
allprojects {   
    repositories {       
        jcenter()   
    }
}
Module-level build.gradle

也就是每个子工程的build.gradle,通常位于//目录下面,主要设定当前module的配置信息。同样,我们也根据下面的例子解释:

/** 
 在当前工程中为Gradle使用Android插件,可以支持使用android{}配置Android专有的
 编译选项,插件为 com.android.application 表示可运行Android项目,如果为一个aar库
 时应该应用com.android.library */

apply plugin: 'com.android.application'

/**android{} 配置所有Android编译相关的选项*/
android {
    compileSdkVersion 23  
    buildToolsVersion "23.0.3"

    /**
     默认的编译变量和设置,可以动态的覆盖AndroidManifest.xml里面的属性
    */
    defaultConfig {    
       applicationId 'com.example.myapp'    
       minSdkVersion 14    
       targetSdkVersion 23    
       versionCode 1    
       versionName "1.0"  
    }

    /**
      编译类型,默认有debug和release,主要设置打包、混淆相关参数。
    */
    buildTypes {         
        release {        
           minifyEnabled true 
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }  
    }

    /**
     产品配置,可以设置多个产品选项,覆盖defaultConfig{}里面的值。
     直观点讲就是可以一下打多个包,每个包有不同的设置。
    */
    productFlavors {    
        free {      
           applicationId 'com.example.myapp.free'    
        }    
       paid {      
           applicationId 'com.example.myapp.paid'    
       }  
    }

  /**
   splits{}可以配置编译不同的APK,每个包只包含针对特定屏幕密度或ABI的代码和资源
  */
  splits {    
     density {      
        enable false       
        exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"    
     }  
  }
}

上面写了貌似挺详细了,但有感觉啥用没有,很多东西还是一知半解,前面提到的问题—-这里面到底都支持什么参数?还是没有解决。还好我找到了Android Gradle DSL 我们选择左边的“AppExtension”,右边的“ Properties”可以看到android{}块支持的所以配置字段和解释,我们可以沿着这个根找到所以其他相关字段的配置,例如buildTypes里面的每种type支持哪些字段,查找到的截图如下:

Paste_Image.png

另外,我们发现左边还有一个“LibraryExtension”,估计不说你也能猜到了,它和前面提到的“AppExtension”分别对应com.android.application和com.android.library。属性值太多了,这里就不挨个解(翻)释(译)了。

Gradle Properties Files

这里主要指根目录下gradle.properties和local.properties两个文件。前者主要是指项目范围内的Gradle配置,例如Gradle进程堆栈大小。后者主要配置一些本地SDK路径,一般IDE会自动生成,所以最好不要编辑和提交到版本控制系统里(svn, git)。

2. In-Depth Study Of Gradle

看完上面的东西,应该已经可以翻着文档配置下Android构建脚本了,但是想要在构建时配置写高级的东东,发现前面的知识还是不够用,那我们接下来就深入点看看Gradle的知识吧。

2.1 Task

Task是指编译脚本中的一个独立的编译单元,代表了一些要执行的动作和行为,它是project的组成元素,可以包含多个action(block), 在上面的例子中我们已经演示过怎么写一个task, task有两个函数doFirst和doLast,表示最先执行和最后执行的action。下面我们写一个例子

task mytask 

task task2 {
    println "test2"
}

task task3 << {
    println "task3"
}
mytask.doFirst {
    println "do first"
}

mytask.doLast {
    println "do last"
}

task task2 {…}这种写法是表示创建task2后返回前,先执行block的内容。而 task task3 << {…}是doLast的一种简写形式。通过命令 “gradle taskName”可以执行一个task,如下命令可以看到当前所以的task:

gradle tasks
gradle tasks --all

而我们之前的例子中可以看到tasks之前是可以存在依赖关系的,所以整个项目构建就可以通过这些tasks来完成了。

2.2 Build Lifecycle

构建主要分三个阶段:初始化、配置和执行。在初始化阶段,主要确定哪些project参与构建,并且创建一个Project对象。配置阶段,主要是解析每一个project的脚本文件,确定所有的task并且根据他们的依赖关系创建一个有向图,最后一个阶段就是执行这些tasks。而我们在这些阶段之间,可以插入一些hook来完成一些特殊的需求。下面是几个例子:

preBuild.dependsOn 'dfqin'
task dfqin << {    
    println "do after dfqin task"
}
tasks.getByName("preBuild"){    
    it.doLast {        
        println "$project.name:  after preBuild"    
    }    
    it.doFirst {        
        println "$project.name: before preBuild"    
    }
}
project.afterEvaluate {    
    println "after evaluate"
}
2.3 Gradle Build Language(DSL)

Gradle 是一种可配置脚本,主要体现在它可以定义一些SB( script blocks),SB类似于一个函数调用,block作为参数传递给调用者来完成特定的配置工作,即它可以称作“领域描述语言”。我们可以看下官方文档

Paste_Image.png

Paste_Image.png

上面的截图中的解释看懂了吧?我就不解释了———你如果看懂了,给我解释一下,因为我没看懂:( 好了,不懂也得死磕,它讲到,Gradle是可配置脚本,当脚本执行后,它会配置(生成)一个特定类型的对象。脚本也分类型,有”Build script”类型的脚本,有”Init script”类型的脚本,有”Settings script”脚本,执行不同类型的脚本会生成不同的对象,如上三种类型脚本分别生成Project、Gradle和Settings对象。下面讲到常用的一些Build script可以由一些语句(方法调用、属性赋值和变量定义)和SB(script block)构成,我们在上面的截图中看到了一些熟悉的东西,就是上面所说的SB,以buildscript{}为例,我们去项目中看一下,发现竟然可以按command进入到源码,截图如下:

Paste_Image.png

我们可以看到,它是Project接口的一个方法,现在我可以这样理解,我们要创建一个Project类型的对象,这个对象的方法实现就是依靠我们的SB,系统后面调用这个对象的方法时,就是执行了我们的SB,通过这种方式,我们实现了对构建项目的配置。嗯,现在不管你懂不懂,反正我是懂了,以后再看到如下的脚本,我就知道它是一个SB,是可以执行的一个方法,大括号中间的东西是一个block,作为参数传递给方法的。关于这个block,我们可以叫做闭包,js、swift中都有,我们这里是groovy的闭包,三言两语解释不清,我也没能力解释清楚:`( 就理解成它是一段可以执行的代码好了。这样看,它的确比那些靠配置xml构建的工具强大一些(也难学一些)。

buildscript {    
    repositories {        
        maven {            
             url uri('./repo')        
        }        
        jcenter()    
    }    
    dependencies {        
        classpath 'com.android.tools.build:gradle:2.2.1'        
    }
}

那如何知道buildscript这个SB里面会有repositories和dependencies这两个SB呢?我们可以看下文档,buildscript这个SB是回调给ScriptHandler对象的,而这个对象中我们可以找到对应的两个方法。以后再“写”脚本时,网上没有可以参考(抄)的案例时,我们就可以这样翻着文档来实现了。

Paste_Image.png

2.4 Gradle Plugin

这两年热更新比较火爆,各厂和一些大牛纷纷开源了自己的热更新方案,去研究这些开源方案,发现大家几乎都定制了自己的Gradle插件,项目在使用它们时一句“apply xxx”风轻云淡的就搞定了。那到底什么是Gradle插件呢?我们在官网看他们讲到,Gradle的核心功能提供的东西其实很少,各种有用的特征例如编译Java代码都是由插件完成的。插件可以添加新的task、配置等,也能扩展其他的插件,下面我们尝试使用Android Studio写一个插件:

  • 1、 新建项目。新建一个Android项目,里面默认会有一个名称为app的module,我们会在次项目里面创建一个插件,并在app里面引用我们创建的插件。
  • 2、创建插件module。在工程中新建一个子module, 类型为Android Library,这里的module名称就是插件项目名,这里我们命名为myplugin。
  • 3、初始化插件module项目结构。因为AS默认没有groovy项目模板的,我们需要手动构建项目结构,把myplugin项目内的东西全删了,只留build.gradle,此文件内容也清空。然后创建目录src/main/groovy,groovy会被识别成groovy源码目录,然后我们在创建src/main/resources/META-INF/gradle-plugins目录。目前myplugin已经被我们改造成gradle插件项目结构了。
  • 4、创建插件实现文件,这里我们创建一个名字为MyPlugin.groovy的文件并且放到对应的包名目录中。下面代码中我们创建了一个名为”printTask”的task,项目中如果引用了这个插件,就能调用此task,这里是groovy语言实现的 ,这样的话能做的事就比较多了。
package com.dfqin.plugin

import org.gradle.api.Plugin
import org.gradle.api.Project

public class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
       project.task('printTask') << {
            println "this is a plugin task"
        }
    }
} 
  • 5、创建属性文件。我们在src/main/resources/META-INF/gradle-plugins目录下创建dfqin.plugin.properties文件,文件名 就是对外发布的插件名,在其他项目中使用此插件时需要声明如下:
apply plugin: 'dfqin.plugin'

打开dfqin.plugin.properties文件,输入如下配置:

implementation-class=com.dfqin.plugin.MyPlugin

这里我们把插件指向了我们上面groovy实现的类,使用插件时就能找到这个类了。

  • 6、配置插件module的gradle文件。打开myplugin下面的build.gradle,输入以下代码:
apply plugin: 'groovy'
apply plugin: 'maven'

dependencies {
    compile gradleApi()
    compile localGroovy()
}

repositories {
    mavenCentral()
}

///********** 分割线 ************///

group='com.mygroup'
version='1.0.1'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: uri('../repo'))
        }
    }
}

这里用斜线做了一个分割,上面的部分是插件的gradle配置文件,用来编译生成插件时使用。而分割线下面的是配置发布插件到maven仓库的。这里我们发布到当前工程的目录里。这里的group和version对应maven坐标的groupId和version,而modulename即我们这里的myplugin对于坐标的artifactId。按照上面的配置,我们可以通过com.mygroup:myplugin:1.0.1来找到我们的插件。下面我们看一下现在的项目结构图:

Paste_Image.png

  • 7、发布插件到本地仓库。我们只需要运行我们前面写的task uploadArchives即可。在命令行下面运行下面命令或者直接在AS的gradle视图里面找到此task双击运行。等执行结束,在项目根目录应该可以看到一个repo的目录,我们在里面可以找到生成的plugin插件。
./gradlew task uploadArchives  

上传插件的task

生成插件到本地仓库

  • 8、使用插件。这个就跟平时使用插件一样了,首先配置maven仓库地址,我们默认都配置了jcenter,这里因为我们的插件在本地仓库,所以要加上一个本地仓库,然后在项目的gradle文件中使用插件。项目根目录的build.gradle文件中配置如下:

buildscript {
    repositories {
        maven {
            url uri('./repo')
        }
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.1'
        classpath 'com.mygroup:myplugin:1.0.1'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

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

再在app module的build.gradle中添加

apply plugin: 'dfqin.plugin'

这时候我们就可以运行我们再插件中定义的printTask了,一个最简单的插件即完成了。运行插件中的task结果如下

Paste_Image.png

注意:因为目前的插件和使用插件的module app在一个项目中,所以当你编辑脚本执行uploadArchives有时会报错,但真正的错误并不一定是插件的错误,有可能是app module中的错误,而生成插件时所有的gradle脚本都会执行。demo已放到github上面,地址:https://github.com/dfqin/GradlePluginDemo

3. 后记

最早是因为要在小组里面分享gradle,想写篇文章整理下知识点吧,后面发现需要讲的内容比较多,加上有时项目忙,所以文章写得断断续续,整片文章连贯性也并不好。目前gradle相关的知识点基本覆盖掉了,只是比较粗略,从宏观上介绍了整体轮廓,没有多少能直接拿到项目中使用的东西,但是根据上面内容应该可以找到解决问题的方法。
部分参考文章:
http://blog.csdn.net/sbsujjbcy/article/details/50782830
http://blog.csdn.net/innost/article/details/48228651#comments
https://segmentfault.com/a/1190000004229002

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Summary Gradle in Action is a comprehensive guide to end-to-end project automation with Gradle. Starting with the basics, this practical, easy-to-read book discusses how to build a full-fledged, real-world project. Along the way, it touches on advanced topics like testing, continuous integration, and monitoring code quality. You’ll also explore tasks like setting up your target environment and deploying your software. About the Technology Gradle is a general-purpose build automation tool. It extends the usage patterns established by its forerunners, Ant and Maven, and allows builds that are expressive, maintainable, and easy to understand. Using a flexible Groovy-based DSL, Gradle provides declarative and extendable language elements that let you model your project’s needs the way you want. About the Book Gradle in Action is a comprehensive guide to end-to-end project automation with Gradle. Starting with the basics, this practical, easy-to-read book discusses how to establish an effective build process for a full-fledged, real-world project. Along the way, it covers advanced topics like testing, continuous integration, and monitoring code quality. You’ll also explore tasks like setting up your target environment and deploying your software. The book assumes a basic background in Java, but no knowledge of Groovy. Purchase of the print book includes a free eBook in PDF, Kindle, and ePub formats from Manning Publications. Whats Inside A comprehensive guide to Gradle Practical, real-world examples Transitioning from Ant and Maven In-depth plugin development Continuous delivery with Gradle About the Author Benjamin Muschko is a member of the Gradleware engineering team and the author of several popular Gradle plugins. Table of Contents Part 1: Introducing Gradle Chapter 1. Introduction to project automation Chapter 2. Next-generation builds with Gradle Chapter 3. Building a Gradle project by example Part 2: Mastering the fundamentals Chapter 4. Build script essentials Chapter 5. Dependency management Chapter 6. Multiproject builds Chapter 7. Testing with Gradle Chapter 8. Extending Gradle Chapter 9. Integration and migration Part 3: From build to deployment Chapter 10. IDE support and tooling Chapter 11. Building polyglot projects Chapter 12. Code quality management and monitoring Chapter 13. Continuous integration Chapter 14. Artifact assembly and publishing Chapter 15. Infrastructure provisioning and deployment Appendix A. Driving the command line Appendix B. Groovy for Gradle users Book Details Title: Gradle in Action Author: Benjamin Muschko Length: 480 pages Edition: 1 Language: English Publisher: Manning Publications Publication Date: 2014-03-09 ISBN-10: 1617291307 ISBN-13: 9781617291302
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值