升级依赖项版本

升级依赖项后,您可以访问其最新的功能、错误修复和改进。要升级依赖项,您需要了解 Gradle 如何解析您请求的版本、涉及的风险以及您可以采取的降低这些风险的步骤。

考虑您的升级策略

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

构建库

您是在构建用户下载并在设备上运行的应用程序?还是构建一个库来帮助其他开发人员构建他们的应用程序?

如果您正在构建应用程序,则应专注于保持应用程序的最新和稳定。

如果您正在构建库,则应专注于其他开发人员的应用程序。您的升级会影响您的使用者。如果您升级了其中一个依赖项,该版本将成为 Gradle 依赖项解析的候选对象,可能会破坏应用程序对该依赖项的使用。

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

务必遵循 语义版本控制 来帮助指示您正在进行的更改类型。例如,AndroidX 遵循语义版本控制并添加了 预发行版本控制方案。尽量避免 major 版本升级,以免破坏您的使用者。

考虑为用户创建库的候选版本 (RC) 以便尽早测试。

有关保持库的应用程序二进制接口 (ABI) 兼容性的详细信息,请参阅 库作者的向后兼容性指南。使用集成测试和 二进制兼容性验证器 等工具来确保您的 ABI 更改与您预期的版本更改相匹配。

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

如果您的库升级需要进行可能对您的使用者尤其痛苦的重大更改,请考虑将其作为新工件发布,以便旧版本和新版本可以共存并允许更渐进的推出。

注意:如果对您的依赖项之一的升级包含重大的 API 更改,您可能需要在 majorminor 版本中对其进行升级,并进行必要的更改。如果不这样做,您的库的用户可能会这样做,从而导致您的库和该依赖项之间出现不兼容的情况。即使您的库没有发生任何更改,这也可能适用。您可以只发布一个新版本来升级该依赖项。

发布周期

您多久发布一次应用程序或库?

较短的开发和发布周期

  • 升级的时间更少。
  • 您可能会很快落后。
  • 频繁的小型升级可以减轻工作量。
  • 如果库升级出现问题,您可以更快地回滚该升级。
  • 诸如 DependabotRenovate 之类的工具可以减轻工作量,但请务必分析结果以检查风险。

较长的开发和发布周期

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

跟上最新功能

您是偏好使用最新的可用功能和API,还是只在需要新功能或修复bug时才进行升级?

考虑频繁升级的权衡。未来的升级更容易(需要集成的更改更少),但您也更频繁地承担升级风险。

测试库的预发布(alpha、beta、候选发布)版本的升级可以帮助您在稳定版本可用时做好准备。

新的依赖项

如果您要添加新的依赖项,请考虑一个严格的审查流程,该流程会检查该库的所有风险标准,以确保已对其进行了正确的评估。不允许在未经审查的情况下添加新的依赖项。

专用团队

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

升级类型

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

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

Android Gradle Plugin (AGP) — 用于构建 Android 应用程序或库的工具。这是您可以进行的最关键的升级,因为它通常包含或启用性能改进、错误修复、新的 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 平台中的最新功能和错误修复以及与最新的 Android SDK 合作的工具。

可用的工具

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

特定类型升级的策略

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

Build dependencies and their relationships
图 1. 构建关系。

升级每种类型的组件时,请考虑升级如何影响构建中的其他组件。

Android Gradle Plugin (AGP)

Android Studio 包含一个 AGP 升级助手,可以帮助完成这些任务。

如果您使用助手或手动执行升级,请考虑以下几点

查看 AGP 发行说明

升级 Gradle 至至少列出的版本。

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

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

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

如果您开发扩展或使用 AGP 数据的 Gradle 插件(用于内部或公共用途),请检查是否需要升级您的插件。有时 AGP 会弃用并在以后删除 API,从而导致与以前的插件不兼容。

Kotlin 编译器、语言和运行时

查看 Kotlin 发行说明 中已知的 issue 和不兼容性。

如果您使用 Jetpack Compose

如果您使用 Kotlin Symbol Processing (KSP),请参阅 KSP 快速入门 以了解设置方法,并参阅 KSP 版本 以了解可用的版本。请注意,您必须使用与 Kotlin 版本匹配的 KSP 版本。例如,如果您使用的是 Kotlin 2.0.21,您可以使用任何以 2.0.21 开头的 KSP 插件版本,例如 2.0.21-1.0.25。您通常不需要升级 KSP 处理器(例如 Room 编译器,它在您的构建文件中显示为 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,则必须使用 2.0.21 版本的 Kotlin 编译器。

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

库是构建中最常升级的依赖项。您会在 Android Studio 编辑器中看到可用的升级,或者如果您使用某些 依赖项工具和插件

某些库指定使用库所需的最小 compileSdkminSdk。如果您不使用至少指定的 compileSdk,则您的构建将失败。但是,您的应用程序的 minSdk 会自动设置为库依赖项和构建文件中指定的所有 minSdk 值中的最大值。

某些库还指定了使用的最小 Kotlin 版本。将构建文件中的 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 或可能需要更改构建文件中的配置。无论哪种情况,您都会看到构建警告或错误以指示不兼容性。

升级插件时,请务必升级 Gradle。

Android SDK

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

如果您使用助手或手动执行升级,请考虑以下几点

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

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

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

“行为更改”部分可能很长,但请密切关注,因为它通常包含您需要对应用程序进行的关键更改。

您必须升级 targetSdk 以满足 Play 商店的要求。升级 compileSdk 是可选的,可以让您访问新的 API。请注意,某些库(如 AndroidX)包含最小 compileSdk 要求。

要在开发过程中利用新的 SDK 功能并在构建过程中确保兼容性,请升级 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,可以在**工具**菜单中找到这些选项。

Java

如果您的 Android 应用程序中包含 Java 源代码,您可能希望利用更新的 Java API。

每个 Android SDK 版本都支持Java API 的子集和语言特性。AGP 通过称为反糖化的过程来提供对较低 Android SDK 版本的兼容性。

Android SDK 的发行说明指定了支持的 Java 版本以及潜在的问题。由于 Kotlin 可以访问相同的 Java API,因此其中一些问题也可能会影响 Kotlin 源代码。即使您没有 Java 源代码,也请务必密切注意发行说明的行为更改部分中出现的 JDK API 部分。

JDK 使用在构建脚本的多个位置指定。有关更多信息,请参阅Android 构建中的 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" }

并在您的应用的构建文件中添加以下内容

Kotlin

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

dependencyGuard {
    configuration("releaseRuntimeClasspath")
}

Groovy

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

dependencyGuard {
    configuration('releaseRuntimeClasspath')
}

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

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

请记住,Dependency Guard 仅捕获库依赖项的列表。您的构建文件中还有其他依赖项,例如 Android SDK 和 JDK 版本。在依赖项更改之前提交到您的 VCS 允许您的 VCS diff 也突出显示这些更改。

升级并与基线进行比较

拥有基线后,升级您想要测试的依赖项和其他构建更改。此时不要升级您的源代码或资源。

运行./gradlew lint 以查看新的 Lint 警告或错误。解决任何重要问题,然后通过运行./gradlew lint -Dlint.baselines.continue=true更新您的警告基线。如果您已使用其他工具捕获警告基线,例如Kotlin Warning BaselineKotlin Warnings Baseline Generator,请解决新的警告并更新其基线。

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

分析风险

一旦知道发生了什么变化,请考虑每个升级库的潜在风险。这有助于集中您的测试或更深入地调查更改。为您的项目定义一组要分析的风险,以确保一致的分析。

一些注意事项

主要版本升级

主要版本号是否已更改?

语义版本控制中,第一个数字称为主版本。例如,如果库的版本从 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、dev 或实验性版本,但一些库包含标记为实验性或不稳定的 API。

如果可能,请避免使用此类 API。如果您需要使用它们,请务必记录您的使用情况并注意以后版本中的更改或删除。

动态行为

某些库的行为会根据外部因素而有所不同。例如,与服务器通信的库取决于该服务器中的更改。

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

清单合并

发布为 Android Archives (AAR) 的库可以包含合并到您的应用程序中的资源和清单。这些可以添加新的权限和 Android 组件,例如间接运行的活动或广播接收器。

运行时更新

一些库使用可以在应用程序控制之外更新的功能。库可能使用 Play 服务,该服务独立于 Android SDK 进行升级。其他库可能绑定到独立更新的外部应用程序中的服务(通常使用 AIDL)。

您跳过了多少个版本?

您等待升级库的时间越长,潜在风险就越大。如果您看到版本发生重大变化,例如从 1.2.3 到 1.34.5,请特别注意此库。

迁移指南

检查库是否有迁移指南。这可以显著降低您的风险分析和缓解规划。

请注意,此类指南的存在表明开发人员已关注兼容性并考虑了您的升级缓解措施。

发行说明

查看每个更改库的发行说明(如果提供)。查找重大更改或新要求的指示,例如添加的权限。

自述文件

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

检查已知漏洞

Play SDK 指数跟踪许多流行 SDK 的漏洞。Play 管理中心报告您是否使用具有已知漏洞的列出 SDK 之一。在 Android Studio 中编辑构建文件时,IDE 会检查 SDK 指数并标记使用易受攻击的库版本。

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

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

版本冲突

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

如果可能,请与依赖项的作者合作以消除其依赖项的冲突。如果您的公司允许,请为库贡献更改(上游),以帮助提高库的兼容性。

检查许可证

升级库时查找许可证中的更改。库本身可能会更改为不再与您的应用程序或库兼容的许可证。新的传递依赖项也可能会引入不兼容的许可证。有关检查依赖项中当前许可证集的详细信息,请参阅验证许可证

维护和
质量风险

对于具有公共存储库的库

  • 有多少贡献者正在维护库?
  • 上次升级是什么时候,库多久更改一次?
  • 问题积压(如果可用)是什么样的?浏览它以了解潜在的问题和库的技术债务。
  • 单元测试对库的覆盖率如何?
  • 代码库中是否存在已知的反模式?
  • 库的文档是否完善?
  • 代码库中是否存在许多_fixme_注释?

开源与闭源

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

尽量减少闭源依赖,并在评估过程中进行额外审查。是否存在适合您用例的良好替代方案?闭源库有哪些服务级别协议?如果您选择使用闭源依赖项,请准备好编写额外的测试用例以帮助降低风险。

运行构建

构建您的项目。查找新的错误或警告。如果您能确定哪个库导致了这些错误或警告,请将其记为升级该库的风险。

如果您看到任何新的弃用警告,请将其添加为产生这些警告的库的特定风险。这些可以在以后的版本中删除。如果您想继续使用该库,请拨出时间从使用弃用的 API 转换为其替代品,或者记下弃用内容,以便关注这些函数以及它们是否会在以后被删除。

使用 lint 检测 API 问题

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

Lint 在 Android Studio 编辑器中运行,在您进行更改时报告问题。但是,除非您使用buildlint目标,否则它通常不会作为 Studio 中的构建的一部分运行,也不会在您运行命令行构建时运行。

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

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

特别注意 lint 错误和警告。一些库附带其自身的 lint 检查,有助于确保正确使用其 API。库的一些新版本包含新的 lint 警告和错误,导致在构建时出现新的报告。

降低风险

确定升级风险后,决定如何降低这些风险

  • 接受某些风险现状。一些风险足够低,可以接受,尤其是在升级时间和资源有限的情况下。
  • 彻底拒绝某些风险。某些升级可能感觉风险太大,尤其是在您目前的时间或资源有限,无法减轻这些风险的情况下。如果您需要进行分类,请关注对您遇到的错误或您需要的功能至关重要的升级。
  • 降低剩余风险
    • 考虑将升级批量处理成更小、更独立的更改集。这降低了整体风险并允许部分回滚。
    • 详细调查这些更改。
    • 测试您的应用 以检查意外更改。根据需要添加新测试以增强对升级的信心。
    • 发现可疑问题时,查看源代码(如果可用)。
    • 在您的源代码或构建中进行必要的更改。

记录您的决策。如果升级的风险在运行应用程序时成为问题,则记录您的风险分析可以减少必要的错误分析。

验证许可证

库开发者许可您使用这些库。您必须遵守许可证条款,否则您将无法使用该库。一些许可证非常宽松,通常只需要归属库并向最终用户显示其许可证文本即可。有些被认为是*病毒式*的;如果您使用这些库,则必须将相同的许可证应用于您的应用程序或库。

许可证可能会随任何版本而更改。每当您升级时,都应验证您正在使用的依赖项的许可方式是否与您的应用程序或库兼容。

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

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