升级依赖项版本

升级依赖项后,您可以使用其最新功能、修复程序和改进。如需升级依赖项,您需要了解 Gradle 如何解析您请求的版本、所涉及的风险以及您可以采取哪些措施来缓解这些风险。

考虑您的升级策略

任何升级最重要的一步都是风险分析。请确定您对升级的每个依赖项的接受程度。定义升级策略时需要考虑许多因素,包括:

构建库

您是否在构建供用户下载并在设备上运行的应用?或者,您是否要构建一个库来帮助其他开发者构建应用?

如果您正在构建应用,您的关注点应该是让应用保持最新且稳定。

如果您正在构建库,则应重点关注其他开发者的应用。您的升级会影响使用方。如果您升级某个依赖项,该版本就会成为 Gradle 依赖项解析的候选项,可能会破坏应用对该依赖项的使用。

首先,尽可能减少库的依赖项。依赖项越少,对使用方的依赖项解析的影响就越小。

请务必遵循语义版本控制,以帮助指明您所做的更改类型。例如,AndroidX 遵循语义版本控制,并添加了预发布版本控制方案。请尽量避免升级到 major 版本,以免破坏使用方。

不妨考虑为您的库创建候选版本 (RC),以供用户尽早测试。

如需详细了解如何确保库的应用二进制接口 (ABI) 兼容,请参阅面向库作者的向后兼容性准则。使用集成测试和二进制兼容性验证器等工具,确保您的 ABI 更改与预期的版本更改一致。

如果您在 patch 中发布了针对较低版本库的修复程序,那么除非使用方需要使用新功能,否则无需将库升级到下一个 majorminor 版本。避免在这些升级中升级传递依赖项。

如果库升级需要进行可能对使用方造成特别大影响的破坏性更改,请考虑将其作为新工件发布,以便旧版和新版可以共存,并允许更渐进地进行发布。

注意:如果升级到其中一个依赖项包含重大 API 更改,您可能需要在 majorminor 版本中对其进行升级,并进行必要的更改。如果您不这样做,库的用户可能会这样做,导致库与该依赖项之间不兼容。即使您的媒体库没有变化,也可能发生此情况。您可以发布一个新版本,只是为了升级该依赖项。

发布周期

您发布应用或库的频率如何?

开发和发布周期更短

  • 升级时间所剩无几。
  • 您可能会很快落后。
  • 频繁进行小规模升级可以减轻工作负担。
  • 如果库升级出现问题,您可以更快地回滚该升级。
  • DependabotRenovate 等工具可以减轻工作量,但请务必分析结果以检查是否存在风险。

延长开发和发布周期

  • 有更多时间进行升级和测试。
  • 在您的周期内,更高版本的依赖项更有可能发布。
  • 回滚升级和发布应用或库需要更长时间。

及时了解最新功能

您更倾向于使用最新的功能和 API,还是仅在需要某项功能或修复某个 bug 时才升级?

请考虑频繁升级的利弊。将来的升级将会更轻松(需要集成的更改更少),但是您将更频繁地承担升级风险。

测试升级到预发布(Alpha 版、Beta 版、候选版本)库版本有助于在稳定版本发布时做好准备。

新建依赖项

如果您要添加新的依赖项,不妨考虑采用严格的审核流程,对该库进行全面的风险评估,以确保已对其进行适当的评估。不允许在未经审核的情况下添加新依赖项。

专门的团队

您有专门的构建团队吗?您的软件工程师是否负责维护 build?在工程师使用新版本之前,专门的团队通常会花费更多时间来分析升级风险和测试新版本,以确保 build 正常运行。

升级类型

有些升级比其他升级更重要。想想哪些对您来说最重要。

构建工具升级(例如 Gradle 和 Gradle 插件)通常对用户的影响较小,并且大部分风险都存在于 build 内部。build 本身有助于验证这些更改。库和 SDK 升级更难以验证,并且对用户的风险更高。

Android Gradle 插件 (AGP) - 用于构建 Android 应用或库的工具。这是您可以进行的最关键的升级,因为它通常包含或启用性能改进、bug 修复、新的 lint 规则以及对新 Android 平台版本的支持。

Gradle - 升级 AGP 或其他 Gradle 插件时,通常需要升级 Gradle。

其他 Gradle 插件 - 有时,Gradle 的插件 API 会发生变化。升级 Gradle 时,请检查您使用的插件是否有升级。

Kotlin 和 Java - 某些库和插件要求使用最低版本的 Kotlin 或 Java,或者您想利用新的语言功能、API 或性能改进。

Android 平台 - Play 商店要求定期升级 Android SDK。您应当尽快测试新版 Android SDK。某些 SDK 升级需要对应用进行更改,例如需要获取新权限或使用新 API。

- 您是否希望根据库与整体架构的接近程度来确定库的优先级?

  • 与平台和架构相关的库(如 AndroidX)经常会变更,以利用新功能或帮助抽象化平台中的变更。每次升级 Android 平台或其他与架构相关的库时,至少要升级这些库。
  • 其他库升级可能会分散或延迟,除非您需要新功能或特定问题修复。

Android Studio - 及时更新 Android Studio,即可使用底层 IntelliJ IDEA 平台和工具中的最新功能和 bug 修复,从而与最新的 Android SDK 搭配使用。

可用工具

有许多工具和插件可帮助您进行升级。DependabotRenovate 等工具会自动升级 build 中的库版本,但请务必分析结果以检查风险。

针对特定类型的升级的策略

升级某些类型的依赖项可能会产生级联效应,需要升级其他类型的依赖项。我们在工具和库之间的相互依赖关系中讨论了 build 元素之间的关系。

build 依赖项及其关系
图 1.建立关系。

升级每种类型的组件时,请考虑升级对 build 中的其他组件有何影响。

Android Gradle 插件 (AGP)

Android Studio 包含一个 AGP 升级助理,可协助您完成这些任务。

如果您使用助理或手动执行升级,请考虑以下事项:

查看 AGP 版本说明

Gradle 升级到至少所列版本。

Android Studio 升级到支持所选 AGP 版本的版本。

使用支持您要使用的 Android SDK 的 Android Studio 和 AGP 版本。

检查与 SDK Build Tools、NDK 和 JDK 的兼容性。

如果您开发的 Gradle 插件(供内部或公开使用)会扩展或使用 AGP 中的数据,请检查您是否需要升级该插件。有时,AGP 会废弃并随后移除 API,导致与之前的插件不兼容。

Kotlin 编译器、语言和运行时

如需了解已知问题和不兼容性,请参阅 Kotlin 版本说明

如果您使用 Jetpack Compose:

  • 如果新 Kotlin 版本低于 2.0.0:
    • 找到兼容的 Compose 编译器插件
    • 在出现 kotlinCompilerExtensionVersion 的任何模块的 build.gradle.kts 中升级 kotlinCompilerExtensionVersion
  • 如果新的 Kotlin 版本为 2.0.0 或更高版本:

如果您使用 Kotlin Symbol Processing (KSP),请参阅 KSP 快速入门了解设置,并参阅 KSP 版本了解可用版本。请注意,您必须使用与 Kotlin 版本匹配的 KSP 版本。例如,如果您使用的是 Kotlin 2.0.21,则可以使用以 2.0.21 开头的任何 KSP 插件版本,例如 2.0.21-1.0.25。您通常不需要升级 KSP 处理器(例如 Room 编译器,它在 build 文件中显示为 ksp 依赖项);KSP 插件会抽象出大部分编译器 API,并且处理器使用的 KSP API 是稳定的。

升级您使用的所有其他 Kotlin 编译器插件。Kotlin 编译器插件 API 在各个版本之间经常发生变化,并且插件必须使用兼容的 API。如果编译器插件中列出了该插件,您必须使用与 Kotlin 编译器相同的版本。对于任何其他编译插件,请参阅其文档以了解适当的映射。

请注意,如果编译器插件未与 Kotlin 编译器本身一起维护,则通常会因等待编译器插件 API 稳定而延迟发布。在升级 Kotlin 之前,请检查您使用的所有编译器插件是否有匹配的升级版本。

最后,在某些情况下,Kotlin 语言会发生变化,这时您需要更新代码。这种情况通常发生在您尝试试用实验性功能时。如果您的代码在升级 Kotlin 编译器后无法正确构建,请查看 Kotlin 版本说明,了解是否有语言变更或运行时库损坏。

Kotlin 编译器插件

如果您需要升级 Kotlin 编译器插件,请升级到正在使用的 Kotlin 的匹配版本。

大多数 Kotlin 编译器插件使用与 Kotlin 编译器相同的版本,或者从所需的 Kotlin 编译器版本开始。例如,如果插件版本为 2.0.21-1.0.25,则必须使用 Kotlin 编译器 2.0.21 版。

更改 Kotlin 编译器版本有时需要进行其他更改

库是 build 中升级最频繁的依赖项。您会在 Android Studio 编辑器中或使用某些依赖项工具和插件时看到可用的升级。

某些库会指定使用该库所需的最低 compileSdkminSdk。如果您使用的 compileSdk 不至少达到指定值,您的 build 将会失败。不过,应用的 minSdk 会自动设置为库依赖项和 build 文件中指定的所有 minSdk 值中的最大值。

某些库还会指定最低 Kotlin 版本。将 build 文件中的 Kotlin 版本更新为至少为指定版本。

Gradle

有时,新版 Gradle 会废弃现有 API,并在未来的版本中移除这些 API。如果您开发了 Gradle 插件,请尽快升级该插件,尤其是公开插件。

某些 Gradle 升级需要找到您使用的插件的新版本。请注意,这些插件在开发时可能会出现延迟,因为它们需要升级以匹配最新的 Gradle 插件 API。

如需升级 Gradle,请执行以下操作:

  • 阅读您要使用的版本的版本说明
  • 升级 gradle/wrapper/gradle-wrapper.properties 中的 Gradle 版本。
  • 运行 ./gradlew wrapper --gradle-version latest 以升级 Gradle 封装容器 jar 和脚本。
  • 升级 Gradle 插件。
  • 升级用于运行 Gradle 的 JDK

Gradle 插件

升级后的 Gradle 插件有时会使用新的或经过更改的 Gradle API,这反过来又需要升级 Gradle,或者可能需要更改 build 文件中的配置。无论是哪种情况,您都会看到构建警告或错误,以指明不兼容。

每次升级插件时,请升级 Gradle。

Android SDK

Android Studio 包含一个 Android SDK 升级助理,可帮助您完成这些任务。

如果您使用助理或手动执行升级,请考虑以下事项:

Android SDK 的每个版本都包含新功能和 API、bug 修复和行为变更。Play 商店要求您更新 targetSdk,但建议您在截止日期之前更新 targetSdk,以便有更多时间进行必要的更改。

在升级 Android SDK 之前,请仔细阅读版本说明。请密切关注“行为变更”部分,其中包括:

  • 您需要在安装或运行时请求的新权限。
  • 已废弃的 API 及其替代 API。
  • API 或行为的重大更改。
  • 新的 Kotlin 或 Java API,这可能会影响您的代码。

“行为变更”部分可能会很长,但请注意,其中通常包含您需要对应用进行的关键更改。

您必须升级 targetSdk,才能满足 Play 商店要求。升级 compileSdk 是可选的,升级后您可以使用新 API。请注意,某些库(例如 AndroidX)具有最低 compileSdk 要求。

如需在开发期间利用新的 SDK 功能并确保 build 期间的兼容性,请升级 Android Gradle 插件 (AGP) 和 Android Studio。其中包括适用于新 SDK 的全新工具和经过改进的工具。请参阅特定 Android API 级别所要求的最低工具版本

升级 Android SDK 时,请升级您使用的所有 AndroidX 库。AndroidX 通常使用新的和更新的 API,以便在各种 Android SDK 版本之间实现更好的兼容性和性能。

Android Studio

通常,您可以随时升级 Android Studio。您可能会看到提示您升级 AGP升级 Android SDK 的消息。我们强烈建议您进行这些升级,但这并非强制要求。

如果您以后想要使用 Android Studio 升级 AGP 或 Android SDK,可以在 Tools 菜单中找到以下选项:

Java

如果您的 Android 应用中有 Java 源代码,您可能需要利用较新的 Java API。

每个 Android SDK 版本都支持部分 Java API 和语言功能。AGP 使用名为“脱糖”的过程提供与较低 Android SDK 版本的兼容性。

Android SDK 版本说明会说明支持哪个 Java 级别以及可能存在的问题。其中一些问题也可能会影响 Kotlin 源代码,因为 Kotlin 可以访问相同的 Java API。请务必密切关注发行说明的“行为变更”部分中显示的 JDK API 部分,即使您没有 Java 源代码也是如此。

JDK 用法在 build 脚本的多个位置指定。如需了解详情,请参阅 Android build 中的 Java 版本

升级分析

升级依赖项可能会引入 API 和行为变更、新的使用要求、新的安全问题,甚至许可变更等形式的风险。例如,您是否需要:

  • 是否应针对 API 更改更改代码?
  • 添加新的权限检查?
  • 创建其他测试或修改现有测试以查看行为变化?

假设您升级的依赖项已升级其依赖项的版本。这可能会快速扩展为大量更改。

如果您使用 RenovateDependabot 等工具自动执行升级,请注意,这些工具不会为您执行任何分析;它们只会升级到最新的库版本。不要假定在进行这类自动升级后一切都会正常运行

升级成功的关键是分析升级情况:

  1. 确定升级前后依赖项的差异。
  2. 检查各项更改并确定相关风险。
  3. 降低风险,或接受或拒绝更改。

确定依赖项差异

升级分析的第一步是确定依赖项的变化方式。利用版本控制(VCS,如 Git)和 Dependency Guard 插件,您可以快速查看更改。您的目标是创建快照,并对它们进行比较。

设置和创建您的第一个基准

在开始升级之前,请确保您的项目已构建成功。

理想情况下,应解决尽可能多的警告,或创建基准以跟踪您已看到的警告。

借助这些警告基准,您可以更轻松地查看升级依赖项时引入的新警告。

通过设置和运行 Dependency Guard 来创建依赖项基准。在您的 gradle/libs.versions.toml 版本目录中,添加以下内容:

[versions]
dependencyGuard = "0.5.0"

[plugins]
dependency-guard = { id = "com.dropbox.dependency-guard", version.ref = "dependencyGuard" }

并将以下代码添加到应用的 build 文件中:

Kotlin

plugins {
    alias(libs.plugins.dependency.guard)
}

dependencyGuard {
    configuration("releaseRuntimeClasspath")
}

Groovy

plugins {
    alias(libs.plugins.dependency.guard)
}

dependencyGuard {
    configuration('releaseRuntimeClasspath')
}

releaseRuntimeClasspath 配置可能是目标配置,但如果您想使用其他配置,请在 build 文件中不列出任何配置的情况下运行 ./gradlew dependencyGuard,以查看所有可用配置。

设置完成后,运行 ./gradlew dependencyGuard 以在 app/dependencies/releaseRuntimeClasspath.txt 中生成报告。这是您的基准报告。 将其提交到您的版本控制系统 (VCS) 即可保存。

请注意,Dependency Guard 仅会捕获库依赖项列表。您的 build 文件中还有其他依赖项,例如 Android SDK 和 JDK 版本。在依赖项发生更改之前提交到 VCS 后,VCS 差异也会突出显示这些更改。

升级并与基准进行比较

获得基准后,升级您要测试的依赖项和其他 build 更改。此时请勿升级源代码或资源。

运行 ./gradlew lint 可查看新的 lint 警告或错误。解决所有重要问题,然后运行 ./gradlew lint -Dlint.baselines.continue=true 更新警告基准。如果您使用其他工具(例如 Kotlin 警告基准Kotlin 警告基准生成器)捕获警告基准,请解决新警告并更新其基准。

运行 ./gradlew dependencyGuard 以更新基准报告。然后,运行 VCS 差异来查看非库更改。它可能包含比您想象的要多的库升级。

分析风险

了解更改内容后,请考虑每个升级的库可能存在的风险。这有助于您集中测试或更深入地调查更改。定义一组要针对您的项目进行分析的风险,以确保分析结果一致。

一些注意事项:

主要版本升级

主要版本号是否发生了变化?

语义版本控制中,第一个数字称为主要版本。例如,如果某个库的版本从 1.2.3 升级到 2.0.1,则表明其主要版本已发生变化。这通常表示库开发者在版本之间进行了不兼容的更改,例如移除或更改 API 的某些部分。

看到这种情况时,在查看以下任一注意事项时,请特别注意受影响的库。

如果您的代码使用了任何实验性 API(通常需要您使用注解或构建文件规范选择启用),那么即使是次要或补丁版本更改(例如从 1.2.3 升级到 1.3.1,或者从 1.2.3 升级到 1.2.5)也可能带来额外的风险。

不稳定 API

某些库版本可能包含不稳定的 API。这些 API 通常是开发中的 API 或依赖于其他不稳定的 API。

虽然通常仅限于预览版(例如 Alpha 版、开发者版或实验性版本),但有些库包含标记为实验性或不稳定的 API。

请尽可能避免使用此类 API。如果您需要使用这些功能,请务必记录您的使用情况,并留意后续版本中的更改或移除情况。

动态行为

某些库的行为会因外部因素而异。例如,与服务器通信的库会依赖于该服务器中的更改。

  • 该库是否需要与特定服务器版本匹配?
  • 该库能否连接到不同版本的服务器?
  • 是否有其他外部因素影响了库的正常行为?

清单合并

以 Android 归档文件 (AAR) 形式发布的库可以包含合并到应用中的资源和清单。这些文件可以添加新的权限和间接运行的 Android 组件(例如 activity 或广播接收器)。

运行时更新

某些库使用可在应用控制之外更新的功能。库可能会使用 Play 服务,而 Play 服务的升级与 Android SDK 无关。其他库可能会绑定到独立更新的外部应用中的服务(通常使用 AIDL)。

您要跳过多少个版本?

您越晚升级库,潜在风险就越大。如果您发现某个版本发生了显著变化(例如,从 1.2.3 更改为 1.34.5),请特别注意该库。

迁移指南

检查该库是否有迁移指南。这可以显著减少风险分析和风险缓解规划的工作量。

请注意,提供此类指南很有力地表明开发者已注重兼容性并考虑了升级缓解措施。

版本说明

请参阅每个发生更改的库的版本说明(如果有)。查找可能存在的重大更改或新要求(例如添加的权限)的迹象。

自述文件

某些库的自述文件会说明潜在风险,尤其是在库未提供版本说明的情况下。查找_已知问题_,尤其是已知安全问题。

检查已知漏洞

Play SDK 索引会跟踪许多热门 SDK 的漏洞。Play 管理中心会报告您是否使用了列出的存在已知漏洞的 SDK 之一。在 Android Studio 中修改 build 文件时,IDE 会检查 SDK 索引,并标记使用易受攻击的库版本。

美国国家标准与技术研究院 (NIST) 维护着一个庞大的国家漏洞数据库 (NVD)依赖项检查 Gradle 插件会根据 NVD 检查您使用的依赖项。

如需使用 Dependency Check,请请求 NVD API 密钥设置 Gradle 插件,然后运行 ./gradlew dependencyCheckAnalyze。请注意,运行这可能需要很长时间。

版本冲突

版本是否按预期解析?查找冲突,尤其是主要版本差异。如需详细了解如何查找冲突,请参阅 Gradle 依赖项解析。尤其要在 ./gradlew app:dependencies 报告中搜索 ->

请尽可能与依赖项的作者合作,解除其依赖项之间的冲突。如果贵公司允许,请向上游贡献库的更改,以帮助提升库的兼容性。

检查许可

升级库时,请留意许可是否发生了变化。库本身可能会更改为不再与您的应用或库兼容的许可。新的传递依赖项还可能会引入不兼容的许可。如需详细了解如何检查依赖项中的当前许可,请参阅验证许可

维护和
质量风险

对于具有公共代码库的库:

  • 有多少贡献者在维护该库?
  • 上次升级是什么时候?库的更改频率如何?
  • 问题积压情况(如果有)如何?快速浏览一下,了解该库的潜在问题和技术债务。
  • 单元测试对库的覆盖率如何?
  • 代码库中是否有已知的反模式?
  • 该库是否有详尽的文档?
  • 代码库中有许多 _fixme_ 注释吗?

开源与闭源

与闭源库相比,开源库的问题更容易调试,无论问题出在您的代码还是库代码中。

尽量减少使用闭源依赖项,并在评估期间对其进行额外审查。是否有适合您的用例的理想替代方案?哪些服务等级协议适用于闭源库?如果您选择使用闭源依赖项,请准备编写其他测试用例,以帮助降低风险。

运行 build

构建项目。查找新的错误或警告。如果您能够确定是哪个库导致了这些问题,请注意升级该库存在风险。

如果您看到任何新的弃用警告,请将其添加为生成这些警告的库的具体风险。这些方法可能会在后续版本中移除。如果您想继续使用该库,请抽出时间从使用已废弃的 API 转换为使用替代 API,或者记下废弃情况,以便密切关注这些函数以及它们日后是否会被移除。

使用 lint 检测 API 问题

Android lint 可以捕获应用中的许多问题,包括因更改依赖项或 Android SDK 版本而导致的问题。例如,如果您升级了 compileSdk 并使用了其新 API,lint 会报告之前 SDK 版本中不提供的 API。

lint 会在 Android Studio 编辑器中运行,并在您进行更改时报告问题。不过,除非您使用 buildlint 目标,否则它通常不会在 Studio 中的构建过程中或您运行命令行构建时运行。

如果您使用持续集成 (CI),请在 CI build 期间(或至少在每夜 build 期间)运行 gradlew buildgradlew lint,以捕获此类错误。

如果您不使用 CI,请务必至少偶尔运行 gradlew lint

请特别注意 lint 错误和警告。有些库自带 lint 检查功能,有助于确保正确使用其 API。某些库的新版本包含新的 lint 警告和错误,这会导致在构建时生成新的报告。

降低风险

确定升级风险后,确定您要如何缓解这些风险:

  • 接受某些风险。某些风险足够低,可以接受,尤其是在升级时间和资源有限的情况下。
  • 直接拒绝某些风险。有些升级可能会让人感觉风险太大,尤其是当您此时缓解它们的时间或资源有限时。如果您需要进行分类,请重点关注升级哪些版本对您遇到的 bug 或所需的新功能至关重要。
  • 降低其余风险
    • 考虑将升级分批处理为更小的独立更改组。 这样可以降低整体风险并允许部分回滚。
    • 详细调查更改。
    • 测试应用,检查是否存在意外更改。根据需要添加新测试,以增强对升级的信心。
    • 发现有疑问的内容时,请查看来源(如果有)。
    • 在源代码或 build 中进行必要的更改。

记录您的决策。如果升级带来的风险在运行应用时成为问题,记录风险分析有助于减少必要的错误分析。

验证许可

库开发者将获得相关库的许可,供您使用。您必须遵守许可条款,否则您无法使用该库。某些许可非常宽松,通常只要求提供库的归属信息,并向最终用户显示其许可文本。有些库被视为病毒式库;如果您使用这些库,则必须对您的应用或库应用相同的许可。

许可随版本变化而变化。每次升级时,您都应验证您使用的依赖项的许可是否与您的应用或库兼容。

如果许可不兼容(或已更改为不再兼容),则您无法使用该版本的库。您可以:

  • 与库所有者联系,请求继续使用现有许可或双重许可,以便继续允许使用旧许可。
  • 请与您的法律团队合作,确定您是否可以更改许可以使其兼容。
  • 找到另一个具有兼容许可的库,并根据需要修改您的应用。
  • 分叉该库的最后一个兼容版本(如果许可允许派生作品且更改不会溯及既往),然后进行您自己的更改。