前言
在讲述下文之前,我想说一下为什么要写这篇文章。我在刚接触android的时候(当然现在也没接触多久),当我下好了AS,建立好我第一个项目的时候,我就全然没有去理会过Gradle这个构建工具,直接开始埋头敲代码。然后在接触的过程,当我每次添加个依赖,或者说是打包apk,又或者说是最初刚构建一个项目的时候,当我看到下方的Build那里在那里转圈圈的时候,看到有一堆堆的Task,我就会在想这是在干嘛?为什么我在用一些组件的时候,需要在build.gradle里面加一句implementation ' xxx'?AS里的那些和Gradle有关的文件的内容是什么意思呢?当我开始产生越来越多的疑问时,我决定花时间去将其了解。
Gradle作为Android Studio的默认工具,我觉得作为一个初学者理解它是非常有必要的,不然你在构建项目出现问题时就会很懵逼。本文不会涉及特别高级的东西,因为我本身就很低级;所以本文只会讲解AS中常接触的和Gradle有关的东西。
一、Gradle介绍
首先我们得知道Gradle是什么。
百度百科:Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,目前也增加了基于Kotlin语言的kotlin-based DSL,抛弃了基于XML的各种繁琐配置。
要注意的是,Gradle它并不是独属于Android。Gradle本身也没有提供多少对Android程序构建的功能,至于构建所需的功能是从哪来、怎么来,下文会讲到。
Gradle是Android Studio默认的构建工具,它提高了Android的开发效率,它的作用就是管理项目中的依赖、打包、编译……那么下面就开始讲一下一些和Gradle有关的文件。
二、理解
- Wrapper
我们每次创建一个项目的时候,都会有个gradle的文件夹,里面就包含着一个wrapper文件夹。那么为什么要有这个呢?gradle是一门发展很快的语言,语言发展快,api也就会经常更新,构建语言含有丰富的插件,变化很快的话,就难以兼容以前老的版本。而wrapper就用来解决解决兼容性问题。wrapper里定义了gradle的版本。
画红线的地方就是我此时的Gradle版本
我现在的这个项目用的gradle版本是5.4.1的,那么这个版本是跟我现在的工程绑定的。若今后构建这个工程时,它都会用我所绑定的gradle版本(避免版本兼容性问题)所以wrapper的作用就是会来检查在你构建这个工程的机器上有没有5.4.1这个版本。如果有就开始构建,没有就去下载这个版本。再举个例子,假如你现在从网上下载了一个项目,而这个项目它所绑定的gradle版本是5.1.1的,而你的机器现在只有5.4.1版本的gradle,那么当这个项目在你这台机器上构建的时候,wrapper就会看你机器上有没有5.1.1版本的gradle,发现没有的话就会去到所提供的url下载这个版本。
wrapper会在这个文件夹中检查
- build.gradle
全局的build.gradle
上图我们可以这样来理解,将repositories理解成“到哪里”,depenencies理解成“下哪些”。也就是说我们在dependencies里面所要下载依赖的jar包都要去到repositories中所给你的仓库里去找---上图中的google()、jcenter(),到google和jcenter这两个仓库里面去找。google仓库和jcenter仓库中都是一些jar包和aar包。然后我们会看到在dependencies注释了一个NOTE,大致意思就是不要将你的application的依赖放在这里,它们属于单独模块中的build.gradle文件。这是什么意思呢?继续往下面看你就会知道了。
在buildscript下面还有一个与其相似的allprojects,它里面也有一个repositories,但却没了 dependencies。可能会有人会有疑问,为什么repositories还要再申明一次呢?其实这两个repositories所作用的地方是不相同的,buildscript下面的是gradle自身构建所需要的一些依赖;而allprojects下方的仓库则是给项目中的其他module去使用的,像app模块或者其他你自己新建的一些模块它们所需的依赖就是到allprojects下面所给的仓库里去找。若你想知道你的allprojects中有哪几个project,可以像下图一样点击右方的Gradle查看就好。
(Gradle采用的是领域对象模型的概念来组织构建文件,也就是针对特定领域来构建文件,而Project就是整个构建文件中所涉及的核心API之一。Project代表项目,通常一个构建文件代表一个项目;项目包含大量的属性和方法)。一个项目中build.gradle这个文件的数量是取决于你这个项目的模块个数(1个root+多个module)。一般新创建的项目都有两个。
新建的项目
第一个是我们上面已经讲了的,它是对应整个项目的,是作用于所有module的配置;而第二个就是对应其所在的模块层,上图中可以看到第二个的括号中写着【Module:app】,也就是说它是作用于app这个模块的,其描述了该模块的相关配置。如果你再新建一个模块,那么同样也会有一个作用于这个新模块的build.gradle。
新建了一个demo模块
那么现在我们就来讲一下module中的build.gradle。
apply plugin。我们知道Gradle并不是专门为Android服务,Gradle它本身是不提供对Android Stduio的任何构建功能的。但Gradle提供了插件机制,这种插件它提供里大量的任务类型、任务、属性等,而开发者只需要在build.gradle中使用 【apply plugin:插件名】 即可引入该插件包含的所有的功能。Google 为了开发 Android 应用定制了一个插件Android Plugin DSL。所以这一行指定了该构件文件应用的插件,Android项目的构建都需要使用'com.android.application'这个插件。
接下来的部分就是插件中的一些配置,比如Sdk的版本,buildTool的版本等等,这些配置我们都可以在 Android Plugin DSL Reference—官方文档[1] 中找到。项目在构建的时候,就会去识别这些参数然后执行对应的参数。
(在AS3.0之前是使用compile来做依赖方式,而在3.0后,compile被弃用了,被implementation和api取代了,至于这三者的区别,感兴趣可以自己去查一下);testImplementation是定义项目里的测试代码(test目录下的);androidTestImplementation则是定义androidTest目录下的代码。除了第一行,后面几行都需要从仓库下载jar包,而第一行所需的jar包都在libs这个目录下面。我们在开发过程中有一些组件或工具的使用,一般先是要要去官网找到这个组件的依赖,然后在这个dependencies里面去添加依赖,因为你的本地目录下并没这些组件的jar包。
看到这里,上面那个NOTE的意思也应该有些眉目了吧,application的依赖应该放在的是模块的build.gradle中,不能放到全局的build.gradle。还有就是有时候构建项目为什么要等待这么久,一直看它转圈圈,这是因为google,jcenter这些都是国外的网站,所以你每次构建项目的时候都得去外网取,当你项目很大的时候,所要下载的资源多,那肯定很慢。当然,一般第一次你构建完后,会有本地缓存。但如果是在公司,团队开发项目的时候,特别是一些新成员刚来时若要在自己的机器上运行公司中的项目的话,那么构建的时间会特别的久,很影响开发效率。还有一种比较好的、又够快的就是搭建本地仓库。不过像我这种个人开发学习的,一般就不需要这些。
- gradle.properties和local.properties
这两个文件主要是一些配置文件。local.properties放的是一些系统配置(比如sdk路径);gradle.properties这里放的是一些全局的配置文件,比如【android.useAndroidX=true】就是当前项目启用AndroidX。
- settings.gradle
这里面包含了你的子项目,也就是你项目中的module,假如刚新建好的项目那么就只包含一个'app' module;如果你新建了其他module,它也会包含在这里面。在构建的初始化阶段,settings.gradle会提供这次构建项目所要包含的哪些module。
setting.gradle文件 这里我自己新建了一个demo模块
- Task任务
Task。
那么什么是Task呢?上面说了Project是Gradle构建文件中最核心的api之一,而Task也是其中之一。Task代表Gradle要执行的一个任务,当我们运行项目的时候,会看到下面会有一堆的Task。
运行时
Task中文意思就是任务,那么也就很好理解,其实上图也就是我们“命令”Gradle需要去完成的一些任务,像打包、编译这些等等,都是通过一个个的Task来实现的。另外我们可以看到每一句后面都会有一个UP-TO-DATE,这其实是Gradle所支持的一个检查功能,它会把每次运行的结果缓存下来,当下次运行时,会检查你现在的输出结果和你刚刚的输出结果有没有变化,如果没有变更则跳过运行,这样那些没有变化的Task就不用每次都去执行了,可以提高项目运行的速度。
上面在命令那里我加了个双引号,因为命令其实有两种方式。像我这样的新手,在打包apk等操作的时候,都是是通过点击上方任务栏来实现的,但其实这些操作都是可以通过命令行实现的。网上有很多教程,这里我就不多讲了。
三、总结
以上就是我个人的一些理解,因为我自己也涉水不深,所以讲的东西也比较浅显,涉及不到什么骚操作。但我认为,在学习每一个东西,都是慢慢来的,首先你得理解,才能深入或者是熟练。就比如在开发过程中你若是觉得gradle中没有你想要的一些功能,你可以根据自己需求自定义插件。反正是会有很多骚操作,当然实现这些的前提是你得先理解。
参考
- ^Android Plugin DSL Reference https://google.github.io/android-gradle-dsl/current/