Android—Gradle教程(三)
前言
在上一篇中,主要讲解了Gradle核心模型以及初步了解Gradle插件。在这一篇中,主要对Gradle依赖管理进行详解:
1、依赖管理
所谓的依赖管理:在大多数情况下,项目都要依赖lib形式的可重用功能,还有很多项目可能被切分成多个单独的子工程来构成模块系统。依赖管理是一种可以让项目自动化的定义、解析,及使用依赖的技术。
而Gradle提供了强大的依赖管理支持,并且也实现了现代软件项目的各种典型场景,如下图所示:
如图所示
Gradle在编译构建的时候,先是从对应(本地、远程)资源库里面拿到对应的资源,所以这里就要对Gradle资源库进行详解:
2、Gradle资源库
在Gradle中存储模块的地方就叫做资源库:
- 定义了资源库之后,Gradle就知道怎么样查找和检索模块。资源库有两种方式:本地库和远程库
- 在运行时,如果相应的任务需要,那么Gradle就需要定位依赖的声明,依赖可能需要从远程库下载,也可能从本地库检索或者是在多项目构建中的其他项目。这个过程就叫做依赖解析
- 一旦解析,解析机制就会存储依赖的底层文件作为本地缓存,之后的构建会重用这些文件,而不用再到远程库下载
- 模块还能提供一些其他的元数据,元数据是描述模块更详细信息的数据,比如在资源库中的坐标,项目的信息等。(group, name, version)
刚刚说到,资源的下载是根据开发者对应Gradle定位依赖声明而下载的,那么Gradle依赖添加有哪些方式呢?
3、Gradle依赖仓库
添加依赖仓库:
- 在项目build.gradle中使用allprojects{}对所有的工程进行配置,使用repositories{}添加依赖仓库;
- google():添加一个在 Google 的 Maven 存储库中查找依赖项的存储库;
- mavenCenteral():添加一个在 Maven 中央存储库中查找依赖项的存储库;
- jcenter()添加一个在 Bintray 的 JCenter 存储库中查找依赖项的存储库;
- 注意jecnter即将关闭,改用mavenCentral。如果有自己发布在jcenter的依赖库,需要迁移到mavenCentral。AS高版本中也默认的将jcenter()改成了mavenCenteral()。
- mavenLocal():添加一个在本地 Maven 缓存中查找依赖项的存储库;
- maven{}:指定某个maven仓库的地址,使用url(path)方法来添加;
- ivy{}:指定某个ivy仓库地址,使用url(path)方法来添加。
说了那么多,贴个代码看看:
// 对所有的工程进行配置
allprojects {// 为工程添加依赖仓库repositories {google() // google maven仓库mavenCentral() // maven 中央仓库//jcenter() // Warning: this repository is going to shut down soonmavenLocal() // 本地maven仓库
// maven {// //url "http://xxxx" // 从xxx去获取library
// }
// ivy {// //url "http://xxxx" // 从xxx去获取library
// }}
}
相信大多数读者对这段代码熟悉都不能在熟悉了,也不过多叙述,直接进入下个专题:Gradle依赖范围
4、Gradle依赖范围
- 在Gradle构建脚本中开发者可以把依赖定义到不同的范围中,比如编译源码或者执行测试。在Gradle中依赖的范围叫依赖项配置
- Gradle插件内置了几种方式的依赖项配置:
- implementation、api、compileOnly、runtimeOnly、annotationProcessor、lintChecks、lintPublish …
- apk/compile/provided已被废弃。
- 在build.gradle中使用dependencies{}添加依赖项配置。
4.1 Gradle不同依赖方式的作用
这里太多了,我就直接截图官方的了:感兴趣的可以去看看官方文档
这些都是官方原生依赖配置,当然你也可以通过自定义依赖:
4.2 Gradle自定义依赖配置项
app下bulid.gradle
...略
configurations {abc {//可在这实现依赖前后的逻辑println "abc"}
}// 依赖项配置
dependencies {abc "org.jetbrains.kotlin:kotlin-stdlib:1.5.10"...略
}
运行效果
Starting Gradle Daemon...
Gradle Daemon started in 2 s 539 ms> Configure project :app
abcBUILD SUCCESSFUL in 34m 9s
这个很少用,除特殊情况外几乎用不到,直接简单过一下。
直接到本篇重点,依赖传递:
5、Gradle依赖传递
依赖传递:就是通过不同的依赖方式有着不一样的传递关系。那么怎么来查看对应的依赖项?
5.1 查看模块依赖项
要想查看整个项目的依赖传递关系,使用命令:
- gradlew app:dependencies --configuration releaseRuntimeClasspath
- x.x.x (*) 该依赖已经有了,将不再重复依赖
- x.x.x -> x.x.x 该依赖的版本被箭头所指的版本代替
- x.x.x -> x.x.x(*) 该依赖的版本被箭头所指的版本代替,并且该依赖已经有了,不再重复依赖
现在来撸码验证下:
dependencies {abc "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"//implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"implementation 'androidx.core:core-ktx:1.3.1'//这种方式和下面那种相同,androidx.core:core-ktx:1.3.1 分为 // group: 'androidx.core', name: 'core-ktx', version: '1.3.1'implementation group: 'androidx.core', name: 'core-ktx', version: '1.3.1'implementation'androidx.appcompat:appcompat:1.2.0'implementation 'androidx.appcompat:appcompat:1.1.0'implementation 'androidx.appcompat:appcompat:1.+'...略}
注意这里,我特意将 androidx.appcompat:appcompat
依赖了不同版本,其中1.+
表示最新,执行以下上面那个命令看看效果:
+--- androidx.appcompat:appcompat:1.2.0 -> 1.4.0-rc01
| +--- androidx.annotation:annotation:1.3.0-rc01
| +--- androidx.core:core:1.7.0 (*)
| +--- androidx.cursoradapter:cursoradapter:1.0.0
| ....略
| ....略
| \--- androidx.annotation:annotation:1.1.0 -> 1.3.0-rc01
+--- androidx.appcompat:appcompat:1.1.0 -> 1.4.0-rc01 (*)
+--- androidx.appcompat:appcompat:1.+ -> 1.4.0-rc01 (*)
从这个运行效果可知:
- Gradle依赖管理进行了优化
- 如果项目存在同一个依赖库的多个版本,默认选择最高版本
- Gradle会自动排除重复的依赖
- Gradle默认支持依赖传递
既然Gradle依赖给我们做了优化,那为什么我们还是会遇到依赖冲突的问题?
- 当引入一个第三方库,该库中也依赖了Android支持库,且支持库的版本和当前版本不一致。这种情况下,Gradle会自动选择最高的版本,导致不兼容的问题。
- 如果同时依赖一个group下的全量库,又依赖了这个group其中一个分库,如果这两个库版本不统一,就导致了依赖冲突问题。最典型的就是support-v4的24.2.0版本开始的分库导致的问题
- androidx包和support包的冲突问题
这个问题在之前经常出现,当你依赖A,A又依赖B,此时你依赖了C,而C没有依赖A而是直接依赖了B,当双方的B版本不同时,就会出现依赖冲突问题。
笔者用了以前最经典的support-v7、support-v4包,来举例,可惜的冲突问题复现不出来了,一看依赖树,gradle已经帮我们全转成androidx了。
+--- com.android.support:appcompat-v7:20.0.0 -> androidx.appcompat:appcompat:1.2.0 (*)
+--- com.android.support.constraint:constraint-layout:1.1.3 -> androidx.constraintlayout:constraintlayout:2.0.1 (*)
+--- com.android.support:support-v4:23.0.0 -> androidx.legacy:legacy-support-v4:1.0.0
虽然系统资源包gradle已经帮我们解决好了,但为了防止以后因为非系统资源包而出现的依赖冲突问题,仔细斟酌了下,还是将解决方案说一下,毕竟多会一点也不是坏事,还是要做到未雨绸缪。
5.2 解决依赖冲突的方式
5.2.1 排除传递依赖项
就以implementation ("androidx.room:room-runtime:2.3.0")
这个举例,我们通过依赖树看看这个依赖子下有哪些:
+--- androidx.room:room-runtime:2.3.0
| +--- androidx.room:room-common:2.3.0
| | \--- androidx.annotation:annotation:1.1.0 -> 1.3.0-rc01
| +--- androidx.sqlite:sqlite-framework:2.1.0
| | +--- androidx.annotation:annotation:1.0.0 -> 1.3.0-rc01
| | \--- androidx.sqlite:sqlite:2.1.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.3.0-rc01
| +--- androidx.sqlite:sqlite:2.1.0 (*)
| +--- androidx.arch.core:core-runtime:2.0.1 -> 2.1.0 (*)
| \--- androidx.annotation:annotation-experimental:1.1.0
我们可以看到androidx.room:room-runtime
这个依赖树里面结构为:
- androidx.room:room-common:2.3.0
- androidx.annotation:annotation:1.1.0
- androidx.sqlite:sqlite-framework:2.1.0
- androidx.annotation:annotation:1.0.0
- androidx.sqlite:sqlite:2.1.0
- androidx.annotation:annotation:1.0.0
- androidx.sqlite:sqlite:2.1.0 (*)
- androidx.arch.core:core-runtime:2.0.1
通过这个结构能清楚的认识到,每一个依赖具体依赖了哪些子依赖,子依赖的下一层又依赖了哪些子依赖,甚至还会有多重子依赖。
这里我们看到不同的子依赖依赖了不同版本的annotation:annotation
依赖,我们先假设annotation:annotation
依赖并没有转成1.3.0-rc01
,那么编译肯定会出现依赖冲突的问题,那么可以如下方式解决该问题。
implementation ("androidx.room:room-runtime:2.3.0"){exclude group:'androidx.annotation', module: 'annotation'}
// implementation group: 'androidx.annotation', name: 'annotation', version: '1.0.0' 等同于implementation("androidx.annotation:annotation:1.0.0")
在Groovy代码里面,额外创建了一个闭包,在闭包里面通过exclude
关键字指定了要删除room-runtime
里面对应的annotation
依赖。随后在外部将annotation
进行单独依赖,再次看看依赖树:
+--- androidx.room:room-runtime:2.3.0
| +--- androidx.room:room-common:2.3.0
| +--- androidx.sqlite:sqlite-framework:2.1.0
| | \--- androidx.sqlite:sqlite:2.1.0
| +--- androidx.sqlite:sqlite:2.1.0
| +--- androidx.arch.core:core-runtime:2.0.1 -> 2.1.0 (*)
| \--- androidx.annotation:annotation-experimental:1.1.0
+--- androidx.annotation:annotation:1.0.0 -> 1.3.0-rc01
我们发现annotation:annotation
有且仅有一个了。
那么如果出现多个依赖库都依赖了annotation:annotation
并且版本都不一样该怎么办?
5.2.2 Froce强制指定
// 强制指定版本
configurations.all {resolutionStrategy {force 'androidx.annotation:annotation:1.0.0'}
}
// 依赖项配置
dependencies {...略implementation ("androidx.room:room-runtime:2.3.0")//{// exclude group:'androidx.annotation', module: 'annotation'
// }
// implementation group: 'androidx.annotation', name: 'annotation', version: '1.0.0' 等同于
// implementation("androidx.annotation:annotation:1.0.0")
}
这里我们看到,在dependencies
使用了 force
强制将annotation:annotation
指定为 1.0.0
,现在来看看效果:
+--- androidx.room:room-runtime:2.3.0
| +--- androidx.room:room-common:2.3.0
| | \--- androidx.annotation:annotation:1.1.0 -> 1.0.0
| +--- androidx.sqlite:sqlite-framework:2.1.0
| | +--- androidx.annotation:annotation:1.0.0
| | \--- androidx.sqlite:sqlite:2.1.0
| | \--- androidx.annotation:annotation:1.0.0
| +--- androidx.sqlite:sqlite:2.1.0 (*)
| +--- androidx.arch.core:core-runtime:2.0.1 -> 2.1.0 (*)
| \--- androidx.annotation:annotation-experimental:1.1.0
我们通过这句代码annotation:annotation:1.1.0 -> 1.0.0
可以看到就算依赖了高版本的 1.1.0 也会被强制变成为 1.0.0。
6、总结
这一篇文字很多,但是内容比较少,相信读者看完本篇后还是会有所收获。
Android—Gradle教程(三)相关推荐
- Android Gradle(三)Groovy快速入门指南
本文首发于微信公众号「刘望舒」 原文链接:Groovy快速入门看这篇就够了 前言 在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我 ...
- android Gradle 教程
发现一个官方翻译后的gradle教程:http://avatarqing.github.io/Gradle-Plugin-User-Guide-Chinese-Verision/index.html
- Android入门教程三十六之BaseAdapter优化
上一节中我们学习了如何来使用一个ListView以及自定义一个简单的BaseAdapter,我们从代码 中可以看出比较重要的两个方法:getCount()和getView(),界面上有多少列就会调用多 ...
- Android初级教程三个Dialog对话框小案例
这里把三个对话框形式写在一个项目程序里面,用三个按钮控制显示什么样式的对话框. 先看布局文件代码: <LinearLayout xmlns:android="http://schema ...
- Android入门教程三之使用Eclipse+ADT+SDK开发安卓APP
前言: 1.这里我们有两条路可以选,直接使用封装好的用于开发Android的ADT Bundle,或者自己进行配置 因为谷歌已经放弃了ADT的更新,官网上也取消的下载链接,这里提供谷歌放弃更新前最新版 ...
- Android基础教程(三)之------ Activity 窗口切换
首先在layout里建2个xml文件 分别有按钮1和按钮2 JAVA代码: 1.public class Activity01 extends Activity { public void onCr ...
- Android学习教程三分钟学会安卓开发
1.创建页面(activity_main是默认主页面) 可拖拽控件,点击下方text切换到代码 下图红框中的是控件的默认id 2.创建activity class(与layout一一对应) 在清单文件 ...
- Android开发实战三之导入现有Android工程项目
选择Create project from existing sample 打开Eclipse环境后,在左上方的菜单上选择[File->New->Project],会弹出[New Proj ...
- android真实项目教程(三)——首页初点缀_by_CJJ
大家晚上好,CJJ不好,前天打球,把右手弄脱臼了...搞得我现在只能一只手敲代码...那效率,我给自己跪了 ...写了好久,才写了那么一丁点...明明还有好多要说的...也只能等手好了再继续吧...呵 ...
- android groovy方法,Android Gradle从入门到精通(三)Groovy快速入门指南
前言 在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我们接着来学习Groovy的基础,要想学好Gradle,Groovy是必须要掌 ...
最新文章
- python实现洗牌算法_为什么渔民耶茨最有用的洗牌算法?
- 【c语言】数组逆序排列
- JQueryEasyUI学习笔记(十四)tree
- mysql show schema_快速入门 · xiaoboluo768/mysql-system-schema Wiki · GitHub
- Python IDLE入门
- 二叉树的直径—leetcode543
- 利用逆矩阵解线性方程组_机器人学导论---第四章 操作臂逆运动学(一)4.1-4.11...
- 最大连续和问题【四种不同的算法】
- upnp协议和dlna源码理解与修改
- C#网络编程示例(note)
- 计算机系统-电路设计09-计数器的内部电路实现
- bugku 杂项 流量分析(cnss)
- 团队管理35-管理方法论积累
- 使用阿里云邮件推送服务发送验证码
- Sobel边缘检测算子的本质
- 记一下怎样关闭windows defender安全中心
- 本题要求编写程序,先将输入的一系列整数中的最小值与第一个数交换,然后将最大值与最后一个数交换,最后输出交换后的序列
- Adobe PS常用快捷键
- POC原型开发:巡店 一期结果
- 关于在袁教授blog中的”呛袁教授“的争论
热门文章
- Syong :静态代理模式
- 基于stm32的自动调速风扇
- 压缩文件密码暴力破解——cRARk使用方法
- Topaz Adjust AI Mac
- 瑞星网络版防病毒软件For Linux通过银河麒麟产品兼容性测试
- Excel 数据透视表小技巧之 05 如何计算重复项,一个包含重复的邮政编码列表,需要每个邮政编码有多少个实例(教程含数据)
- 你的优势在哪?开宝马的学渣教会我的事
- c++第二课 输出自定义字符图形
- 编译 libstring.so lib库 libstring.c libstring.h makefile
- qq连连看java版_java仿QQ连连看游戏