当前位置: 首页 > article >正文

一文了解Gradle 依赖管理(五)- 依赖管理缓存依赖

文章目录

  • 1. 版本目录 (Version Catalogs)
      • 1. 版本目录的概念与优势
      • 2. 主要优势
      • 3. 基本配置
      • 4. 使用版本目录
      • 5.使用外部版本目录文件
      • 6.实际项目中的版本目录最佳实践
  • 2. 依赖锁定(Dependency Locking)
      • 1. 依赖锁定的概念与重要性
      • 2. 主要优势
      • 3. 如何启用依赖锁定
      • 4. 生成锁定文件
      • 5. 更新锁定依赖
      • 6. 依赖锁定与版本目录结合使用
  • 3. 依赖缓存与离线构建
      • 1. Gradle 的依赖缓存机制
      • 2. 配置缓存位置
      • 3. 启用构建缓存
      • 4. 离线模式构建
      • 5. 依赖缓存的最佳实践

1. 版本目录 (Version Catalogs)

版本目录是 Gradle 7.0 引入的一项功能,它提供了一种集中管理依赖版本和依赖组的强大方式,尤其适合多模块项目。

1. 版本目录的概念与优势

版本目录是一种将依赖定义从构建脚本中抽离出来的机制,使依赖管理更加结构化、集中化,并支持更好的 IDE 支持。

2. 主要优势

1. 集中管理:在一个地方定义所有依赖版本和依赖组
2. 类型安全:提供类型安全的依赖访问,减少拼写错误
3. IDE 支持:更好的自动完成和导航支持
4. 依赖分组:按逻辑组织依赖
5. 版本控制:轻松更新和跟踪依赖版本变化

3. 基本配置

版本目录通常在 settings.gradlesettings.gradle.kts 文件中定义:

// 在settings.gradle中
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            // 定义版本
            version('kotlin', '1.6.10')
            version('coroutines', '1.6.0')
            
            // 定义库
            library('kotlin-stdlib', 'org.jetbrains.kotlin', 'kotlin-stdlib').versionRef('kotlin')
            library('kotlin-reflect', 'org.jetbrains.kotlin', 'kotlin-reflect').versionRef('kotlin')
            library('coroutines-core', 'org.jetbrains.kotlinx', 'kotlinx-coroutines-core').versionRef('coroutines')
            
            // 定义依赖组(bundle)
            bundle('kotlin-bundle', ['kotlin-stdlib', 'kotlin-reflect'])
            
            // 定义插件
            plugin('kotlin-android', 'org.jetbrains.kotlin.android').versionRef('kotlin')
        }
    }
}

在 Kotlin DSL 中(settings.gradle.kts):

dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            version("kotlin", "1.6.10")
            version("coroutines", "1.6.0")
            
            library("kotlin-stdlib", "org.jetbrains.kotlin", "kotlin-stdlib").versionRef("kotlin")
            library("kotlin-reflect", "org.jetbrains.kotlin", "kotlin-reflect").versionRef("kotlin")
            library("coroutines-core", "org.jetbrains.kotlinx", "kotlinx-coroutines-core").versionRef("coroutines")
            
            bundle("kotlin-bundle", listOf("kotlin-stdlib", "kotlin-reflect"))
            
            plugin("kotlin-android", "org.jetbrains.kotlin.android").versionRef("kotlin")
        }
    }
}

4. 使用版本目录

一旦定义了版本目录,我们就可以在构建脚本中使用它们:

plugins {
    id(libs.plugins.kotlin.android.get().pluginId)
}

dependencies {
    implementation(libs.kotlin.stdlib)
    implementation(libs.coroutines.core)
    implementation(libs.bundles.kotlin.bundle)
}

5.使用外部版本目录文件

对于更复杂的项目,您可以将版本目录定义移动到专用的 TOML 文件中, 当然这也是Android官方推荐的做法,在新的AS项目中,默认就是使用的 TOML文件:

# libs.versions.toml
[versions]
kotlin = "1.6.10"
coroutines = "1.6.0"
retrofit = "2.9.0"
okhttp = "4.9.3"
room = "2.4.1"

[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
retrofit-core = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }

[bundles]
kotlin = ["kotlin-stdlib", "kotlin-reflect"]
coroutines = ["coroutines-core", "coroutines-android"]
retrofit = ["retrofit-core", "retrofit-gson", "okhttp-core", "okhttp-logging"]
room = ["room-runtime"]

[plugins]
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }

然后在 settings.gradle 中引用这个文件:

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from(files("libs.versions.toml"))
        }
    }
}

6.实际项目中的版本目录最佳实践

1. 按功能或技术栈分组:将依赖按照功能或技术栈分组,例如 networkuidatabase 等。
2. 使用有意义的别名:为依赖创建直观的别名,如 retrofit 而不是 squareup-retrofit
3. 充分利用版本引用:避免重复的版本号声明,使用版本引用确保相关库使用相同版本。
4. 创建有用的 bundle:将常一起使用的依赖组合成 bundle,简化依赖声明。
5. 保持 TOML 文件的良好组织:使用注释和分组保持文件可读性。

例如以下:

# 网络相关依赖
[libraries.retrofit]
module = "com.squareup.retrofit2:retrofit"
version = "2.9.0"

# 注释说明特殊用途的依赖
[libraries.leak-canary]
module = "com.squareup.leakcanary:leakcanary-android"
version = "2.8.1"
# 仅在 debug 构建中使用

2. 依赖锁定(Dependency Locking)

依赖锁定是确保构建可重复性的重要技术,特别是当项目使用动态版本或版本范围时。

1. 依赖锁定的概念与重要性

依赖锁定将依赖图"冻结"在特定的时间点,记录解析的确切版本,确保后续构建使用相同的依赖版本,即使新版本发布。

2. 主要优势

  1. 构建可重现性:确保相同的源代码总是使用相同的依赖版本构建
  2. 防止意外升级:避免自动获取新发布的库版本
  3. 行为一致性:减少"在我的机器上能运行"问题
  4. 安全性:在审核新版本之前防止引入新依赖

3. 如何启用依赖锁定

settings.gradle 或特定项目的 build.gradle 中启用依赖锁定:

// 为所有配置启用依赖锁定
dependencyLocking {
    lockAllConfigurations()
}

// 或者为特定配置启用
configurations.compileClasspath {
    resolutionStrategy.activateDependencyLocking()
}

4. 生成锁定文件

一旦启用了依赖锁定,您需要生成锁定文件:

# 为所有配置生成锁定文件
./gradlew dependencies --write-locks

# 为特定项目生成锁定文件
./gradlew :app:dependencies --write-locks

这将在 gradle/dependency-locks 目录下创建锁定文件,每个配置一个文件。

5. 更新锁定依赖

当需要有意更新依赖版本时:

# 更新所有依赖锁
./gradlew dependencies --update-locks "com.squareup.retrofit2:*"

# 或者完全刷新所有锁
./gradlew dependencies --write-locks

6. 依赖锁定与版本目录结合使用

依赖锁定和版本目录可以很好地结合使用,这种组合确保您既有集中的版本管理,又有确切的依赖锁定,提供最大的可重复性和控制。

  • 版本目录:声明您期望的依赖版本(理想状态)
  • 依赖锁定:记录实际解析的版本(实际状态)
// 在build.gradle中
dependencies {
    implementation libs.retrofit.core // 从版本目录
}

dependencyLocking {
    lockAllConfigurations()
}

这里可能稍微难理解,我用个例子简单来描述一下。

假设我们开发的App中, Retrofit 2.9.0 依赖 OkHttp 4.9.0,但我们在版本目录中指定了更新的 OkHttp 4.9.3,

当没有依赖锁定时:

  • 第一个开发者构建项目时会使用 OkHttp 4.9.3
  • 下一个开发者几周后构建项目,可能 OkHttp 已更新到 4.9.5,他将使用 4.9.5

开启依赖锁定后:

  • 所有开发者都会使用锁定文件中的精确版本 OkHttp 4.9.3
  • 即使 OkHttp 发布了 4.9.5 版本,除非我们显式更新锁定文件,否则团队仍会使用 4.9.3

现在假设我们的目录版本中更新了Gson:

[versions]
# 更新了版本
gson = "2.9.0" # 从 2.8.5 更新

有了依赖锁定:

  1. 即使版本目录更新了,项目仍会使用锁定文件中的 2.8.5
  2. 团队可以讨论并决定何时更新锁定文件
  3. 当团队准备好时,可以显式更新锁定:
./gradlew dependencies --update-locks "com.google.gson*:*"

3. 依赖缓存与离线构建

有效管理依赖缓存可以显著提高构建性能,特别是在团队环境或 CI/CD 管道中。

1. Gradle 的依赖缓存机制

Gradle 在本地缓存所有下载的依赖,默认位置是用户主目录下的 .gradle/caches 目录。

2. 配置缓存位置

我们可以自定义缓存位置, 在 gradle.properties中:

# gradle.properties
org.gradle.caching=true
org.gradle.caching.debug=false
org.gradle.cache.dir=/custom/cache/directory

3. 启用构建缓存

构建缓存可以在配置中启用:

# settings.gradle
buildCache {
    local {
        enabled = true
    }
}

4. 离线模式构建

离线模式强制 Gradle 只使用缓存的依赖:

# 命令行参数
./gradlew build --offline

# 或在 gradle.properties 中永久设置
org.gradle.offline=true

5. 依赖缓存的最佳实践

1. 共享缓存:考虑在团队之间或 CI 系统中共享缓存目录,减少重复下载

2. 定期清理:定期清理缓存,删除不再使用的依赖版本

./gradlew cleanBuildCache

3. 预热缓存:在 CI 构建前或开发环境设置中预热缓存

./gradlew downloadDependencies

4. 缓存备份:备份关键依赖的缓存,防止远程仓库不可用

5. 使用镜像或私有仓库:设置本地镜像或私有依赖仓库,减少外部依赖.


http://www.kler.cn/a/600036.html

相关文章:

  • 算法 | 麻雀搜索算法原理,公式,改进算法综述,应用场景及matlab完整代码
  • 气膜馆的奥秘:空气支撑的科技建筑—轻空间
  • 数据结构--分块查找
  • 如何使用go的template模版
  • Rust+WebAssembly:开启浏览器3D渲染新时代
  • 华为OD机试2025A卷 - 游戏分组/王者荣耀(Java Python JS C++ C )
  • 基于Python卷积神经网络(CNN)的mnist手写数字识别
  • JVM常见概念之条件移动
  • git安装教程
  • Java 基础入门代码示例解析
  • idea底部图标不小心关了,怎么重新打开?
  • Leetcode—15. 三数之和(哈希表—基础算法)
  • Java多线程与高并发专题——使用 Future 有哪些注意点?Future 产生新的线程了吗?
  • 内网渗透-隧道通信
  • Python技术栈与数据可视化创意实践详解(三)
  • 【进阶编程】跨平台的 UI 框架
  • JVM 02
  • STM32G030移植RT-Thread
  • 学一个前端 UI 框架,要学些什么内容?
  • 当人类关系重构:从“相互需要”到“鹅卵石化”——生成式人工智能(GAI)认证的角色与影响