升级依赖项版本

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

考虑您的升级策略

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

构建库

您是在构建用户下载并在设备上运行的应用程序?还是在构建库以帮助其他开发者构建其应用程序?

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

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

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

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

考虑为用户创建库的候选发布版本 (RC) 以进行早期测试。

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

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

如果您的库升级需要进行重大更改,可能会给您的使用者带来很大的困扰,请考虑将其作为新的构件发布,以便旧版本和新版本可以共存,并允许更渐进的推广。

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

发布周期

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

较短的开发和发布周期

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

较长的开发和发布周期

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

跟上最新功能

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

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

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

新的依赖项

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

专用团队

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

升级类型

有些升级比其他升级更重要。考虑一下哪些对您最重要。

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

Android Gradle 插件 (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 插件 (AGP)

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

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

查看AGP 发行说明

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

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

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

检查与 SDK 构建工具、NDK 和 JDK 的兼容性。

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

Kotlin 编译器、语言和运行时

查看Kotlin 发行说明以了解已知问题和不兼容性。

如果您使用 Jetpack Compose

如果您使用 Kotlin 符号处理 (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源代码。请务必仔细阅读发行说明的行为更改部分中出现的JDK API部分,即使您没有Java源代码。

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" }

并将以下内容添加到您的应用程序的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只捕获库依赖项的列表。您的构建文件中还有其他依赖项,例如Android SDK和JDK版本。在依赖项更改之前提交到您的VCS,可以让您的VCS差异也突出显示这些更改。

升级并与您的基线进行比较

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

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

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

分析风险

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

一些注意事项

主要版本升级

主要版本号是否已更改?

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

当您看到此情况时,在查看以下任何注意事项时,请特别注意受影响的库。

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

非稳定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中编辑build文件时,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 警告和错误,导致在构建时出现新的报告。

降低风险

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

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

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

验证许可证

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

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

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

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