自动化构建工具与gradle

自动化构建工具与gradle

一、定义

我们在学习c语言的时候都知道,c语言源程序从源程序到二进制程序,经过了预处理(Preprocessing), 编译(Compilation), 汇编(Assemble), 链接(Linking)的过程,在使用gcc进行编译时只需要gcc test.c -o test就可以生成,或者复杂点,一步步生成中间代码:

gcc -e test.c -o test.i
gcc -s test.i -o test.s
gcc  -c test.s -o test.o
gcc test.o -o test

那么复杂一些的工程呢,里面有各种数不胜数的源程序、头文件,都按模块、功能分好了类,总不能手工一个个编译吧,你可能会说:“那就用makefile啊”,没错,makefile可以帮助你按照顺序编译程序或者执行一些功能,它其实就是一种自动化构建工具(Build Automation)。

Build tools are programs that automate the creation of executable applications from source code. Building incorporates compiling, linking and packaging the code into a usable or executable form. In small projects, developers will often manually invoke the build process. This is not practical for larger projects, where it is very hard to keep track of what needs to be built, in what sequence and what dependencies there are in the building process. Using an automation tool allows the build process to be more consistent.

自动化构建工具就是自动将源码生成为可执行文件的工具。

常用的组建自动化工具就有Make、Rake、Cake、MS build、AntGradle等。

原来我一直在用自动化构建工具啊。

二、它们能干什么

一般自动化构建工具有如下的feature:

  • 丰富的插件库
  • 编译管理工具
  • 源码管理工具
  • 各种可用的UI
  • 和主流IDE兼容
  • 并行测试或编译
  • 依赖管理
  • 版本冲突解决
  • 协同调试工具
  • 增量编译
  • 最小化重新编译
  • 自动事件/编译
  • 框架的自动初始化
  • 代码和资源的及时更新
  • 构建缓存、可缓存任务
  • 构建指标、性能跟踪

三、常用自动化构建工具

  • 评价最高的自动化构建工具包括: Gradle, Codeship, TeamCity, and Travis CI.
  • 其他的自动化构建工具包括: Jenkins, CircleCI, Bamboo, and Apache Maven.
评价最高的自动化构建工具

四、关于Gradle

在写安卓app时,经常因为要引入第三方库或者修改一些系统信息而修改gradle,有时候build gradle的需要很长时间,这个过程中Gradle干了写什么?

这一部分主要翻译自Łukasz Wasylkowski的文章《Understanding Android Gradle build files》,链接见文末

1.gradle是什么

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。 面向Java应用为主。当前其支持的语言限于Java、Groovy和Scala,计划未来将支持更多的语言。

2.Groovy

  1. 语法

    gradle文件使用groovy脚本语言编写的,它的语法很容易理解,但需要注意以下几点:

    • 调用函数时有一个或多个参数不需要括号。

      def printAge(String name, int age) {
          print("$name is $age years old")
      }
      
      def printEmptyLine() {
          println()
      }
      printAge "John", 24 // Will print "John is 24 years old"
      printEmptyLine() // Will print empty line
      
    • 最后一个参数是closure时(lambda),可以写在括号外面。

      def callWithParam(String param, Closure<String> closure) {
          closure(param)
      }
      
      callWithParam("param", { println it }) // Will print "param"
      callWithParam("param") { println it } // Will print "param"
      callWithParam "param", { println it } // Will print "param"
      
    • 当参数中有定义map的元素时,它们将会被转化为一个map作为第一个元素,其他参数排在map参数之后。

      def printPersonInfo(Map<String, Object> person) {
          println("${person.name} is ${person.age} years old")
      }
      
      def printJobInfo(Map<String, Object> job, String employeeName) {
          println("$employeeName works as ${job.title} at ${job.company}")
      }
      
      printPersonInfo name: "John", age: 24
      printJobInfo "John", title: "Android developer", company: "Tooploox"
      
  2. closures

    闭包是开放的、匿名的、可以执行的代码块,它们有参数、返回值,它们可以被分配给某个对象。

    class WriterOne {
        def printText(str) {
            println "Printed in One: $str"
        }
    }
    
    class WriterTwo {
        def printText(str) {
            println "Printed in Two: $str"
        }
    }
    
    def printClosure = {
        printText "I come from a closure"
    }
    
    printClosure.delegate = new WriterOne()
    printClosure() // will print "Printed in One: I come from a closure
    printClosure.delegate = new WriterTwo()
    printClosure() // will print "Printed in Two: I come from a closure
    

3.关于gradle

  1. 脚本文件

    Gradle主要用到三个脚本文件:

    • build.gradle文件中的build 脚本 . 它们针对Project对象执行;
    • settings.gradle 文件中的settings 脚本, 针对Settings对象执行;
    • init 脚本 用于全局设置(针对 Gradle实例执行)
  2. projects

    gradle中含有一个或多个project,project有task组成,至少存在一个root project,它的里面可能还有subproject。按照惯例,root project主要提供了project布局、通用设置、插件路径。

4.创建一个基于gradle的Android工程项目

一般的安卓目录如下:

├── settings.gradle # [1]
├── build.gradle # [2]
├── gradle
│ └── wrapper
└── app
├── gradle.properties # [3]
├── build.gradle # [4]
└── src

[1]这是root project的设置文件,针对setting对象执行

[2]Root project的build设置

[3]App project的的配置文件,针对appSettings

[4]App project’的build设置

1.创建一个gradle项目

新建一个example文件夹,cd到其目录,然后执行gradle projects,就会发现已经新建好一个gradle project了。

执行结果

2.设置projects层次结构

如果我们想要一个和默认的安卓项目相似的结构,我们需要一个setting.gradle文件,它配置了实例和project实例的层次。

setting.gradle文件中使用 void include(String[] projectPaths) 方法可以添加一个project,我们用它来添加一个app的subproject。

echo "include ':app'" > settings.gradle
gradle projects
执行结果

3构建Android subproject

现在我们将设置root project的build.gradle文件。

我们可以通过apply方法将com.android.application导入到appproject中。

void apply(Closure closure)
void apply(Map<String, ?> options)
void apply(Action<? super ObjectConfigurationAction> action)

mkdir app
echo apply plugin: 'com.android.application' > app/build.gradle
gradle app:tasks

但是输出了错误信息:

出错信息

错误之处找不到'com.android.application'的位置,这很容易理解,因为我们没有为它指定路径,我们在root或subproject的build.gradle中通过添加buildscript来设置路径。

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
    }
}
出错信息

继续出错,没有指定buildToolsVersion版本,在app的build.gradle添加如下代码,然后运行:

android {
   buildToolsVersion "25.0.1"
   compileSdkVersion 25
}

android方法定义了buildToolsVersion and compileSdkVersion 两个方法。

出错信息

又有报错了,提示找不到Android SDK,需要在local.properties中定义或者添加环境变量。

我们就在root下新建一个local.properties并写入SDK的路径,然后运行:

echo sdk.dir=C\:\\Users\\getia\\AppData\\Local\\Android\\Sdk> local.properties
gradle app:tasks
1544179544125.png

又又报错了,这次是AndroidManifest.xml,我们在app/src/main目录下新建AndroidManifest.xml文件并向其中添加以下语句,再次运行:

mkdir app\src
mkdir app\src\main
echo apply plugin: 'com.android.application' > app/src/main/AndroidManifest.xml;
gradle app:tasks
成功了

终于成功了,我流下了没有技术的眼泪。

4.添加依赖(Dependencies)

dependencies {
    compile 'io.reactivex.rxjava2:rxjava:2.0.4'
    testCompile 'junit:junit:4.12'
    annotationProcessor 'org.parceler:parceler:1.1.6'
}

Dependencies是一个特殊的代码块,如果你查看Dependencies的文档DependencyHandler ,你会发现根本就没有compile 或者testCompile方法。因为它使用了groovy语言的另一种特性methodMissing,它在没有找到对应方法名或参数表时调用:当调用了一个没有定义的方法,如果它的参数大于1个并且这个名字的方法被配置(*)过,那么就根据它的参数数目和类型,调用doAdd方法。

(*) 每一个插件都可以给 dependencies handler添加配置. 比如 java 插件 定义列 compile, compileClasspath, testCompile 和一些其他配置。Android 插件annotationProcessor <variant>Compile, <variant>TestCompile 等配置。

doAdd 方法是私有的, i它可以被 公有方法add调用。 所以我们可以这么来重写Dependencies代码块(*) :

dependencies {
    add('compile', 'io.reactivex.rxjava2:rxjava:2.0.4')
    add('testCompile', 'junit:junit:4.12')
    add('annotationProcessor', 'org.parceler:parceler:1.1.6')

(*) 一般情况下不要这么做

参考文献

https://www.techopedia.com/definition/16359/build-tool

https://www.trustradius.com/build-automation

https://medium.com/@wasyl/understanding-android-gradle-build-files-e4b45b73cc4c

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容