手把手讲解 Android开发中Gradle编程一条龙攻略(1)

前言

手把手讲解系列文章,是我写给各位看官,也是写给我自己的。
文章可能过分详细,但是这是为了帮助到尽量多的人,毕竟工作5,6年,不能老吸血,也到了回馈开源的时候.
这个系列的文章:
1、用通俗易懂的讲解方式,讲解一门技术的实用价值
2、详细书写源码的追踪,源码截图,绘制类的结构图,尽量详细地解释原理的探索过程
3、提供Github 的 可运行的Demo工程,但是我所提供代码,更多是提供思路,抛砖引玉,请酌情cv
4、集合整理原理探索过程中的一些坑,或者demo的运行过程中的注意事项
5、用gif图,最直观地展示demo运行效果

如果觉得细节太细,直接跳过看结论即可。
本人能力有限,如若发现描述不当之处,欢迎留言批评指正。

学到老活到老,路漫漫其修远兮。与众君共勉 !


正文大纲

1. gradle是什么
2. groovy语言的特性以及它和java的关系
3. 为什么你的apk打包这么慢
4. 如何利用gradle编程解决工作中的实际问题
5. gradle的高级用法(gradle多渠道快速打包插件)


正文

1. gradle 是什么?

先看看来自百度百科的解释:

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

Gradle是一个基于JVM的构建工具,是一款通用灵活的构建工具,支持maven, Ivy仓库,支持传递性依赖管理,而不需要远程仓库或者是pom.xml和ivy.xml配置文件,基于Groovy,build脚本使用Groovy编写。

大家懂的,百度百科就是把简单的一个东西解释得一般人看不懂。那么来看看上面一段话中的重点。
Gradle 是基于Jvm的项目自动化构建工具 ,可以使用java groovy kotlin 和 scala语言进行编程。 它是DSL 特定领域语言,它是专门用来构建项目的.

再解读并且扩展一下:

  1. Gradle是一个工具,用于构建项目,在androidStudio的工程目录中的体现,就是 帮我们把 Android工程中的java源码文件,资源文件,依赖包,普通配置文件等,经过一系列步骤, 最终生成一个 或者多个apk文件,有了apk文件,才能到 应用市场去发布。
  2. Gradle是一个编程框架Groovy是该框架常用的编程语言,既然它是语言,那么就可以进行程序逻辑的编写,编写之后,会被编译成字节码,交给JVM运行。
  3. 项目构建工具,除了gradle之外,还有 antmaven,只不过很少使用,已经渐渐转gradle.

GradleandroidStudio项目中存在的痕迹如下图(这是一个新建的project):

image.png

上面图中,上图中,我标记了1-6,现在来一一解释:

1. Gradle- Wrapper

gradle的包装盒,里面有gradle的jar包,还有properties属性. Jar包包含的是.class文件,这也就解释了为什么gradle的代码是基于JVM的,可以预见,这个jar包内肯定包含了gradle编译之后生成的java类,各种api. 然而,事实也证明我的猜想没有错。

反编译.png

Jar包之外,还有一个.properties.
properties.png

这里是gradle的一些配置信息,比较重要的是最后一条,distributionUrl 它代表了gradle工具包的下载路径.

2. 外部的build.gradle

它是全局范围的构建配置.

3. setting.gradle

image.png

但是这里不仅仅可以定义要编译的module,还可以进行插件化编程。

4. gradle.properties

gradle的全局配置
image.png

5. gradlew 和 gradlew.bat

这两个,是不同平台下的可执行文件,前者是 .sh格式,希尔文件,linux下的可执行文件。后者是 window下的批处理命令。

6. module内部的build.gradle

综上所述

Gradle是贯穿了整个android工程的构建工具,几乎随处可见gradle的身影,作为高级开发者,如果只知道android的java代码,写写xml,而不懂得gradle编程的话,开发中遇到某些问题(特别是架构方面的问题),很可能不知所措。


2. groovy语言的特性以及它和java的关系

Gradle的常用编程语言有java,groovy,kotlin,scala等,但是最常见的,谷歌默认的构建语言,还是groovy.
那么, 了解groovy语言的特性是绕过不去的。
但是精(熟)通(练)Java的开发者, groovy和java都是基于jvm,都是编译成字节码来运行在jvm中,我们在有java老底的基础上,不需要逐字逐句去学习语法,而只需要总结出groovy和java语法上比较相异的部分,则可以轻松掌握它。

先给出Groovy语法的官网:
https://www.w3cschool.cn/groovy/groovy_basic_syntax.html
大部分语法,我们作为java开发者都能看懂,但是以下这些,则需要动一下脑子。

1.语句结束的逗号可以省略

但是你要加上也不会报错,建议能省就省吧

2. 导包

Groovy的导包方式和java一样:import java.lang.*,但是.gradle内会有默认导包。每一个xxx.gradle文件,都能
不用导包而直接使用以下包的类。

import java.lang.* 
import java.util.* 
import java.io.* 
import java.net.* 
import groovy.lang.* 
import groovy.util.* 
import java.math.BigInteger 
import java.math.BigDecimal

3. 定义变量

除了java所支持的 String a = "aaa" ,之外,它还可以def a = "aaaa"

    String s = "aaaaa"
    def s2 = "ssssss"

4. 循环

    for (int i in 1..10) {//用for in 遍历 1到10(包含头尾)
        println i
    }

    def dd= [1,2,3,4,5]//for in  遍历数组
    for(d in dd){
        println d
    }

    def map = ["ken":21,"ju":12,"aaaaa":223] // for in 遍历 map
    for(d in map){
        println d
    }

另外,如果是简单的多次执行同一段代码,还可以这么写(这个涉及到闭包,后面解释):

    10.times {
        variable -> println variable
    }

5.文件IO

除了可以使用java的标准io流去进行文件读写之外,还使用Groovy可以进行文件的IO读写操作,后者更加简单.比如

    new File("test.txt").eachLine { line -> println "line $line" } //读取每一行
    //读取文件全部内容
    File f = new File("test.txt")
    println "文件全部内容 \n$f.text"

    //把helloWorld字符串写入到test.txt文件
    new File("test.txt").withWriter('utf-8', {
        writer -> writer.writeLine("hello world")
    })

总之一句话,Groovy提供的 File类,可以进行简单的文件操作,足够满足我们平时的gradle编程IO流操作,其他更多api可以翻阅 https://www.w3cschool.cn/groovy/groovy_file_io.html

6. 闭包

导致有些人看不懂.gradle文件的原因就是 闭包, 这个是java中不存在的概念(拉姆达表达式类似闭包,但是不是闭包).可以大致理解 为: 闭包==匿名代码块

    //闭包测试
    def clo = { println("无参闭包") }//无参闭包
    clo()

    def clo1 = { a -> println("1个参数的闭包:" + a) }
    clo1("参数")


    def clo2 = { a, b, c -> println("多个参数的闭包 $a $b $c") }
    clo2(1,2,3)

闭包也可以作为参数传递给一个方法:

task test() {
    //闭包测试
    def clo = { println("无参闭包") }//无参闭包
    def clo1 = { a -> println("1个参数的闭包:" + a) }
    def clo2 = { a, b,c -> println("多个参数的闭包 $a $b $c") }

    //闭包作为参数
    testClo(clo)
    testClo1(clo1)
    testClo2(clo2)
}

void testClo(Closure clo) {
    println("=======开始测试闭包0咯=======")
    clo()
}

void testClo1(Closure clo) {
    println("=======开始测试闭包1咯=======")
    clo("哈哈哈")
}

void testClo2(Closure clo) {
    println("=======开始测试闭包2咯=======")
    clo("啊1", 2, 3)
}
集合/映射+闭包
task test() {
    def list = [1, 2, 3, 4, 5]
    list.each { a -> println(a) }//指明形参名
    list.each { println(it) } //使用默认的形参名it

    def map = ["zhou": 22, "li": 30, "han": 40]
    map.each { a -> println(a) }//指明形参名
    map.each { a -> println(a.key + "- "+ a.value) }//指明形参名
    map.each { println(it.key + "- "+ it.value) } //使用默认的形参名it
}

7. 省略小括号

除了闭包之外,groovy对于小括号的省略写法也是阻碍我们看懂gradle文件的原因。那么groovy在什么情况下可以省略小括号呢?

1. 所有的顶级表达式的括号可以省略
2. 当闭包作为顶级表达式的最后一个参数的时候,小括号可以省略

但是,当函数嵌套调用的时候,如果函数是无参的,这个时候小括号不可省略.

什么意思?小括号的省略往往和闭包 / 方法调用有关,我们拿实际案例来说:

buildscript {
    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

上面这段,如果按照java的语言习惯,根本读不通,但是,如果我们把括号补全以下,变成这样:

buildscript({
    repositories({
        google()
        jcenter()

    })
    dependencies({
        classpath ('com.android.tools.build:gradle:3.4.1')

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    })
})

解读以上补全过程,通过代码阅读,我发现,buildscript / repositories /google/jcenter/dependencies / classpath 其实都是 一个一个的"方法名",方法自然是会带上小括号,小括号里面就会装着参数,而参数类型恰恰就是 闭包Closure
最后一个classpath比较特殊,他的参数类型是Object[]
比如

void buildscript(Closure configureClosure);
void repositories(Closure configureClosure);

补全了小括号,我们就能以java的阅读习惯去阅读gradle文件。
再举一个例子(如果上面的能读懂,那么下面的这一段代码应该能读懂了):

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 15
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

补全括号之后,

android({
    compileSdkVersion(29)
    buildToolsVersion("29.0.2")
    defaultConfig({
        applicationId("com.example.myapplication")
        minSdkVersion(15)
        targetSdkVersion(29)
        versionCode(1)
        versionName("1.0")
        testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner")
    })
    buildTypes({
        release({
            minifyEnabled(false)
            proguardFiles(getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro')
        })
    })

})

那么什么时候不可以省略小括号呢?也举个例子:

image.png

无参函数调用的时候,括号不可省略。有参数的函数,可以省略。

总结

从一个java老司机的眼光去看 groovy,其实java和groovy差别就是以上这些(其他一些 groovy 语法并不是不重要,而是java开发者一眼就能看明白,没必要拿出来占字数),掌握起来并不难,就一句话:

gradle/ groovy 编程,在函数调用时往往会省略小括号,如果省略了小括号再添上闭包参数,看上去就比较诡异了。但是,补全了小括号,理解了闭包之后,读写gradle/groovy将不会再有障碍。


3. 为什么你的apk打包这么慢

你们有没有经历过 用as新建一个project,然后半天不能构建成功的窘境?如果有,那么恭喜你,你的电脑网络被墙了,gradle插件包服务器并不在国内,如果网络被墙,那么下载不动,你的项目构建就很慢。

解决方案1

image.png

还记不记得这里的wrapper / gradle-wrapper.properties 这里有一个关键配置,
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
https\://services.gradle.org 是协议和主机
/distributions/ 是路径
gradle-5.1.1-all.zip 则是插件包的名字
这里的gradle-5.1.1-all.zip插件包,包含了源文件和可执行文件,其实我们构建项目,并不需要源文件,所以,我们可以试着把这里的-all 改成 -bin,变成下面这样:
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
也许可以加快下载速度,有利于你的项目编译。

解决方案2

承接方案1,distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 这个插件包,最后下载到了我们的本地,window系统下,一般都在:

image.png
MAC系统应该也在对应的用户目录,我没有mac电脑,就不截图了.

我们可以手动通过别的下载软件把这个包,下载到上图的目录下 (C:\Users\adminstrator\.gradle\wrapper\dists),然后在gradle-wrapper.properties中设置对应的版本即可,这样也能免除你在编译的时候去浪费时间了。 而且这些包应该也能复用,以后拷贝出去,给其他项目来用,也能节约时间。

解决方案3

除了gradle插件包下载慢之外,很多第三方依赖库都是来自北美大陆,我们去下载,依然可能被墙。一定有人经历过jcenter下的包下半天没动静的情况了。这个如何解决
使用国内镜像去替换
举个例子,如下图,jcenter下了半天没动静。

image.png
那么,你改成这样:
image.png

jcenter()的后面加上{ url 'https://maven.aliyun.com/repository/jcenter' }
aliyun的镜像地址为:https://maven.aliyun.com/mvn/view
image.png

如果发现其他的依赖库下的依赖包下载不动,同理。
除了阿里云之外,还有其他公司发布国内镜像,使用方法同理。

那么如果你想玩点骚操作,你想先去国内仓库去找,然后再去国外仓库去找。也可以实现,方法为:

image.png

当给同一个仓库设置多个地址的时候,系统按照从上到下的书写顺序去查找,找到为止,查到最后还找不到,那就GG了,没法编译。

解决方案4

存在一种情况,即使你按照前面3步去做了,编译依然很慢,这是为何?很可能是因为:

image.png

这里的加号,意思是:你这次所下载的依赖包,自动去查找网络上的最新版
如果每一次编译,都要去请求网络,然后下载最新版,势必会拖慢编译速度。
加号,谷歌设计出来应该是为了提供使用最新包的简易写法,但是这个并不是一个好习惯。试想,你引用的第三方依赖包 发生了api变化,很可能让你的引用代码出现bug。

解决方案5

如果上面的方案都不能解决你编译慢的问题,比如你的项目引用了大量的依赖包,down下来一个新的项目,首次编译都要花费大量的时间。这个时候,可以:使用本地私库 常用的私库有 artifact 等。
至于私库搭建,相信网上有很多攻略,我就不在这里浪费篇幅了。


未完待续...

结语

全文太长,截取一下吧。
下一篇(2) 将会 继续 第4节 往后讲解。


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