Gradle学习(八)——复合构建

原创 2017年12月26日 19:59:56

转载请注明出处:http://blog.csdn.net/lastsweetop/article/details/78905882

简介

复合构建是一个包含了其他构建的构建,很多时候和多项目构建非常相似,但是它包含的不是完整的项目,而是完整的构建。组合构建可以做到以下两点:

  • 和比较独立的开发进行组合构建,比如修复一个项目中引用的lib库
  • 把非常大的工程切成几个小块,各个小块直接是可以独立工作的

复合构建比多项目构建中的小项目更具备独立性,复合构建中的构建可以被称为“被包含的构建”,被包含的构建和复合构建或者其他被包含的构建之间不会共享任何配置信息,每个被包含的构建都会独立的配置和执行。

被包含构建和其他构建之间通过dependency substitution来关联,如果被包含的构建和其他构建之间满足依赖关系,那么他们之间的依赖将被替换为工程依赖。默认情况下,Gradle会去替换被包含构建需要满足的依赖关系,但是有时候默认值不一定正确,那就需要显示的指明替换。除了通过替换为项目依赖来解决这种情况外,复合构建还可以直接定义依赖于被包含构建的任务,但是被包含构建是无法这样做的。

定义

下面这个例子中两个gradle构建是分开独立开发,我们会展示如何用各种不同的方式把它们做成复合构建。其中my-utils包含两个子项目string-utils和number-utils,分别会产生两个jar包,供my-app调用,但是my-app并不会直接声明是依赖于my-utils项目,而仅仅声明了依赖于它产出的两个jar包。

目录树如下:

.
├── my-app
│   ├── build.gradle
│   ├── my-app.iml
│   ├── settings.gradle
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── lastsweetop
│                       └── myapp
│                           └── Main.java
└── my-utils
    ├── my-utils.iml
    ├── number-utils
    │   ├── build.gradle
    │   └── src
    │       └── main
    │           └── java
    │               └── com
    │                   └── lastsweetop
    │                       └── number
    │                           └── NumberUtils.java
    ├── settings.gradle
    └── string-utils
        ├── build.gradle
        └── src
            └── main
                └── java
                    └── com
                        └── lastsweetop
                            └── string
                                └── StringUtils.java

my-app里的build.gradle配置如下:

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'


group 'com.lastsweetop'
version '1.0'
mainClassName='com.lastsweetop.myapp.Main'

dependencies {
    compile 'com.lastsweetop:string-utils:1.0'
    compile 'com.lastsweetop:number-utils:1.0'
}

repositories {
    jcenter()
}

通过--include-build定义复合构建

在我们第一种方法中,IDE都会提示错误的,因为它不知道去哪找这两个包,代码中也会提示找不到XX类,如图所示:
compositeBuild
但是通过--include-build选项把my-utils引入进来作为被包含的构建确实可以复合构建,gradle --include-build '../my-utils'的输出如下:

> Task :run
composite build


BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

通过settings.gradle定义复合构建

我们的第二种方法就会清爽好多,通过在settings.gradle文件中,用Settings.includeBuild(java.lang.Object)方法声明需要被包含的构建,被包含的构建是本地的项目目录,这是IDE就不会提示错误了,因为IDE会把被包含的包同时导入到工程中,当然所需的依赖和类也都会找到了。效果如下图:
compositeBuild2

单独定义复合构建

我们一开始的初衷是在独立的构建上做组合构建,但是第二个方法需要修改原来的构建,这使得被修改的构建不是一个标准的构建。第三个方法就是单独定义一个复合构建的项目,这我们的例子中是my-cp项目,整体的目录结构图如下:

├── my-app
│   ├── build.gradle
│   ├── my-app.iml
│   ├── settings.gradle
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── lastsweetop
│                       └── myapp
│                           └── Main.java
├── my-cp
│   ├── build.gradle
│   ├── my-cp.iml
│   └── settings.gradle
└── my-utils
    ├── my-utils.iml
    ├── number-utils
    │   ├── build.gradle
    │   └── src
    │       └── main
    │           └── java
    │               └── com
    │                   └── lastsweetop
    │                       └── number
    │                           └── NumberUtils.java
    ├── settings.gradle
    └── string-utils
        ├── build.gradle
        └── src
            └── main
                └── java
                    └── com
                        └── lastsweetop
                            └── string
                                └── StringUtils.java

在my-cp的settings.gradle中包含两个构建,如下:

rootProject.name='my-cp'

includeBuild '../my-app'
includeBuild '../my-utils'

my-cp作为复合构建项目来执行,但是它自己并没有定义可执行的任务,如果想执行my-app里的run任务就需要在复合构建项目中的build.gradle定义,如下:

task run {
    dependsOn gradle.includedBuild('my-app').task(':run')
    group 'application'
}

我在定义clean任务时遇到一个问题,应该算是bug,及复合构建项目无法识别被包含项目的任务的父子项目归属关系,只能指定子项目的具体任务,如下:

task clean {
    dependsOn gradle.includedBuild('my-app').task(':clean'),
            gradle.includedBuild('my-utils').task(':string-utils:clean'),
            gradle.includedBuild('my-utils').task(':number-utils:clean')

}

被包含构建的限制条件

被复合构建包含的构建有一些限制条件:

  • 必须有settings.gradle文件,及时文件内容是空的
  • 本身不可以是复合构建
  • rootProject.name不能与其他被包含的构建相同
  • rootProject.name不能与复合构建的root工程相同
  • rootProject.name不能与复合构建的rootProject.name相同

组合构建的交互

一般来说,组合构建的交互和多项目构建一样,一样可以运行任务,执行测试,导入到IDE等

任务执行

不管是命令行还是IDE都可以执行复合构建中的任务,gradle会去判断那些依赖的任务需要执行,要注意的是被包含构建的任务的执行目前只能在IDE中执行,命令行中还不支持。

IDE导入

IDE的集成是组合构建最重要的一个特性,只需导入组合构建任务的root项目,其他被包含的构建项目就会自动导入,有利于同时开发多个项目。

定义由被包含构建替换的依赖

默认情况下,Gradle会设置每个被包含的构建来确定他们可以提供的依赖关系。其中的算法也非常简单:Gradle会检查被包含构建项目的group和name,当工程的依赖与${project.group}:${project.name}.匹配时,就会替换成被包含的工程。

这个过程大多数情况下交给Gradle去搞定就OK了,但是一些特别的项目还是会出错的,这种情况下就需要明确的去定义被包含构建的替换关系。比如一个单独的构建unpublished,它没有指定group,build.gradle里就一句

apply plugin: 'java'

gradle这里检查到这个被包含的构建可以替换的依赖模块为undefined:unpublished,undefined是因为没有group名,unpublished是项目的目录名称,非常明显这时无法匹配到实际的依赖的。
这时,my-app的依赖增加了一个date-utils

dependencies {
    compile 'com.lastsweetop:string-utils:1.0'
    compile 'com.lastsweetop:number-utils:1.0'
    compile 'com.lastsweetop:date-utils:1.0'
}

如何才能将date-utils和我们刚刚包含到的unpublished关联上呢?其实也很容易,只需要在复合构建导入时增加如下配置:

includeBuild('../unpublished') {
    dependencySubstitution {
        substitute module('com.lastsweetop:date-utils') with project(':')
    }
}

显示的指定了这个被包含的构建应该对应到的依赖模块的名字,至此他们的替换关系就确认了。注意project(‘:’)表示当前项目,意思就是还可以指定子项目,具体操作看你的灵活应用吧

被包含的构建必须声明替换关系的情况

很多构建通过uploadArchives任务来发布它们的产出,它们的替换关系可以使用默认的就OK了。但是有一些情况下,必须声明替换关系:

  • 发布产出时使用了archivesBaseName熟悉
  • 发布时除了默认设置外,还有其他的一些操作,同城不仅仅执行了uploadArchives任务
  • 发布时使用了MavenPom.addFilter(),有时候和项目名无法对应
  • 发布时使用了maven-publish或者ivy-publish插件,最终的产出可能与${project.group}:${project.name}不匹配
版权声明:本文为博主原创文章,未经博主允许不得转载。

Gradle强制依赖解析策略

遇到过这样一个问题: 使用第三方的插件,但是插件在定义自身依赖时,使用[version+]策略,导致永远下载最新的依赖,但是该插件所指定仓库并没有最新版本的依赖,从而导致构建失败。 ...
  • BenW1988
  • BenW1988
  • 2016年02月07日 10:12
  • 4173

Gradle学习(八)——复合构建

一个包含了其他构建的构建,很多时候和多项目构建非常相似,但是它包含的不是完整的项目,而是完整的构建。组合构建可以做到以下两点: 和比较独立的开发进行组合构建,比如修复一个项目中引用的lib库 把非常大...
  • lastsweetop
  • lastsweetop
  • 2017年12月26日 19:59
  • 398

构建工具的发展及Android Gradle快速上手

最近谷歌宣布官方不再维护Eclipse ADT了,之后将更加专注于Android Studio的功能和性能上的改进,Studio使用了Gradle编译系统,本文旨在帮助大家认识Gradle,看懂Gra...
  • yanquan345
  • yanquan345
  • 2015年07月06日 22:07
  • 1428

gradle学习(21)-在eclipse中构建java项目

1.下载gradle for eclipse插件 根据前人文章找到的链接下载的,就不多说了。下载完成后,重启eclipse。 2.创建gradle项目 创建新项目的时候会发现多了一个gr...
  • qhshiniba
  • qhshiniba
  • 2015年01月14日 20:13
  • 6099

Gradle(构建一个android项目)

Google I/O 2013发布了新的开发工具Android Studio和新的构建系统Gradle, Android Studio自不必说,这是Android IDE的未来。这篇文章就来学习下Gr...
  • dxyoo7
  • dxyoo7
  • 2014年05月08日 14:55
  • 3946

升级Gradle3.0

概述 升级 配置Gradle版本 配置Android Gradle Plugin 新的依赖配置接口 问题描述 Implementation change ABI change Android ...
  • wfeii
  • wfeii
  • 2018年01月22日 16:18
  • 47

Jenkins+Gradle实现android开发持续集成、打包

实际工作中,很多时候我们需要持续打包,或者出现某个问题后,我们需要追溯到某一个历史版本去做对照,如果手动去做这些操作的话,无疑会耽误很多时间,直接压缩了下班回家陪老婆孩子的时间,所以我们需要一个能够自...
  • byszy
  • byszy
  • 2016年05月17日 15:54
  • 3263

(一)如何使用gradle构建Android项目

今天又是个放假的日子,放假对于很多人来说,可以到处去玩,可是对于那些单身程序猿来说,很难找到一个理由去哪里玩,...
  • u013970487
  • u013970487
  • 2014年03月22日 22:16
  • 2952

AndroidStudio开发必备常识之Gradle构建

Android Studio是Google开发的一款面向Android开发者的IDE, 支持Windows、Mac、Linux等操作系统,基于流行的Java语言集成开发环境IntelliJ搭建而成。但...
  • u010213440
  • u010213440
  • 2016年05月02日 00:18
  • 4517

在AndroidStudio中自定义Gradle插件

一直都想好好学习AndroidStudio中的gradle,总感觉不懂如何在AndroidStudio中自定义gradle插件的程序员就不是个好程序员,这次上网查了一下相关资料,做了一个总结~...
  • huachao1001
  • huachao1001
  • 2016年07月02日 14:17
  • 8681
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Gradle学习(八)——复合构建
举报原因:
原因补充:

(最多只允许输入30个字)