升级依赖项可让您访问其最新功能、bug 修复和改进。要升级依赖项,您需要了解 Gradle 如何解析您请求的版本、涉及的风险以及您可以采取的缓解这些风险的步骤。
考虑您的升级策略
任何升级最重要的步骤是风险分析。确定您对每个升级的依赖项的满意度。定义升级策略时有许多注意事项,包括:
构建库 |
您正在构建用户下载并在设备上运行的应用吗?还是在构建一个辅助其他开发者构建应用的库? 如果您正在构建应用程序,您的重点应该是保持应用程序的最新和稳定。 如果您正在构建库,您的重点应该是其他开发者的应用。您的升级会影响您的消费者。如果您升级了某个依赖项,该版本将成为 Gradle 依赖项解析的候选版本,这可能会破坏应用程序对该依赖项的使用。 首先 - 尽可能减少您的库的依赖项。您拥有的依赖项越少,对您的消费者的依赖项解析的影响就越小。 请务必遵循语义化版本控制,以帮助指示您正在进行的更改类型。例如,AndroidX 遵循语义化版本控制并添加了预发布版本控制方案。尽量避免进行 考虑为用户创建库的发布候选版 (RC) 以进行早期测试。 有关如何保持库的应用程序二进制接口 (ABI) 兼容性的详细信息,请参阅库作者的向后兼容性指南。使用集成测试和工具(如二进制兼容性验证器)确保您的 ABI 更改与您预期的版本更改相符。 如果您在库的较低版本的 如果您的库升级需要可能对您的消费者特别痛苦的破坏性更改,请考虑将其作为新工件发布,以便旧版本和新版本可以共存,并允许更逐步的推出。 注意:如果您的某个依赖项的升级包含重大 API 更改,您可能希望在 |
发布周期 |
您多久发布一次您的应用程序或库? 更短的开发和发布周期
更长的开发和发布周期
|
跟上最新功能 |
您是喜欢使用最新的可用功能和 API,还是只在需要某个功能或 bug 修复时才升级? 考虑频繁升级的权衡。未来的升级更容易(需要集成的更改更少),但您更频繁地承担升级风险。 测试库的预发布(alpha、beta、发布候选)版本升级有助于在稳定版本可用时做好准备。 |
新依赖项 |
如果您要添加新依赖项,请考虑进行严格的审查流程,检查该库的所有风险标准,以确保它们已得到适当评估。不允许未经审查添加新依赖项。 |
专属团队 |
您是否有专属的构建团队?您的软件工程师是否维护构建?专属团队通常可以花更多时间分析升级风险并测试新版本,以确保构建在工程师使用新版本之前正常工作。 |
升级类型 |
有些升级比其他升级更重要。考虑哪些对您最重要。 构建工具升级,例如 Gradle 和 Gradle 插件,通常对您的用户影响较小,并且大部分风险在您的构建内部。构建本身有助于验证这些更改。库和 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。 库 — 您是否想根据库与整体架构的接近程度来确定优先级?
Android Studio — 保持 Android Studio 更新,您可以访问底层 IntelliJ IDEA 平台中的最新功能和错误修复,以及使用最新 Android SDK 的工具。 |
可用工具 |
如果您使用有助于自动化依赖项升级的插件或工具,请务必分析结果以检查风险。 |
特定类型升级的策略
升级某些类型的依赖项可能会产生连锁反应,需要升级其他类型的依赖项。我们将在工具和库相互依赖关系中讨论构建元素之间的关系。
升级每种组件时,请考虑升级对构建中其他组件的影响。
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 Symbol Processing (KSP),请参阅 KSP 快速入门进行设置,并参阅 KSP 版本了解可用版本。请注意,您必须使用与 Kotlin 版本匹配的 KSP 版本。例如,如果您使用的是 Kotlin 2.0.21,则可以使用以 2.0.21 开头的任何 KSP 插件版本,例如 2.0.21-1.0.25。您通常不需要升级 KSP 处理器(例如 Room 编译器,它在您的构建文件中显示为 升级您正在使用的所有其他 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 编译器版本有时需要其他更改。 |
库 |
库是构建中最常升级的依赖项。您会在 Android Studio 编辑器中看到可用的升级。 某些库指定使用该库所需的最低 一些库还指定了使用的最低 Kotlin 版本。更新构建文件中的 Kotlin 版本,使其至少达到指定版本。 |
Gradle |
有时,新版本的 Gradle 会弃用现有 API,并在未来的版本中移除这些 API。如果您开发 Gradle 插件,请尽快升级您的插件,特别是当该插件是公共插件时。 某些 Gradle 升级需要找到您使用的插件的新版本。请注意,这些插件在开发中可能会滞后,因为它们需要升级以匹配最新的 Gradle 插件 API。 要升级 Gradle
|
Gradle 插件 |
升级后的 Gradle 插件有时会使用新的或更改的 Gradle API,这反过来又需要升级 Gradle 或可能更改其在构建文件中的配置。无论哪种情况,您都会看到构建警告或错误,以表明不兼容性。 每当升级插件时,请升级 Gradle。 |
Android SDK |
Android Studio 包含一个Android SDK 升级助手,可以帮助完成这些任务。 如果您使用助手或手动执行升级,请考虑以下事项: 每个 Android SDK 版本都包含新功能和 API、错误修复和行为更改。Play 商店要求更新您的 升级 Android SDK 之前,请仔细阅读发布说明。请密切关注行为变更部分,其中包括:
行为更改部分可能很长,但请密切关注,因为它通常包含您需要对应用程序进行的重大更改。 您必须升级 为了在开发过程中利用新的 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 使用称为desugaring的过程为较低的 Android SDK 版本提供兼容性。 Android SDK 发布说明指定了支持的 Java 级别和潜在问题。其中一些问题也可能影响 Kotlin 源代码,因为 Kotlin 可以访问相同的 Java API。即使您没有 Java 源代码,也请务必密切关注发布说明行为变更部分中出现的 JDK API 部分。 JDK 用法在您的构建脚本中多个地方指定。有关详细信息,请参阅Android 构建中的 Java 版本。 |
升级分析
升级依赖项可能会带来风险,表现为 API 和行为更改、使用新要求、新安全问题,甚至许可证更改。例如,您需要
- 更改代码以适应 API 更改吗?
- 添加新的权限检查?
- 为行为变更创建额外的测试或修改现有测试?
请考虑您已升级的依赖项是否也升级了其依赖项的版本。这可能会迅速演变成大量的更改。
如果您使用有助于自动化依赖项升级的插件或工具,请注意它们不会为您进行任何分析;它们只会升级到最新的库版本。不要假设这些类型的自动升级后一切都会正常工作。
成功升级的关键是升级分析
- 确定升级前后的依赖项差异。
- 检查每个更改并确定所涉及的风险。
- 缓解风险,或接受/拒绝更改。
确定依赖项差异
升级分析的第一步是确定您的依赖项如何变化。利用版本控制系统 (VCS,例如 Git) 和 Dependency Guard 插件,可以快速查看更改。您的目标是创建之前和之后的快照并进行比较。
设置并创建您的第一个基线
在开始升级之前,请确保您的项目成功构建。
理想情况下,尽可能多地解决警告,或者创建基线来跟踪您已经看到的警告。
Lint
- 通过添加以下内容将警告视为错误
android { // ... lint { warningsAsErrors = true } }
到每个模块的
build.gradle.kts
中。- 或者,如果您有许多现有警告,请创建Android lint 基线。随着时间的推移,请务必清理现有警告(或抑制您不关心的警告)
Kotlin 编译器:启用
-Werror
将所有警告视为错误。请参阅如何定义选项。其他工具:如果您使用其他支持基线跟踪的静态分析工具,请设置其基线。
警告基线使您更容易看到由于升级依赖项而引入的新警告。您可以使用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
来更新您的警告基线。如果您使用了其他工具来捕获警告基线,请解决新警告并更新它们的基线。
运行 ./gradlew dependencyGuard
以更新您的基线报告。然后运行您的 VCS diff 以查看非库更改。它很可能包含比您想象的更多的库升级。
分析风险
一旦您了解了发生了什么变化,请考虑每个升级库的可能风险。这有助于将您的测试或对更改的深入调查集中起来。定义一组要为您的项目分析的风险,以确保分析的一致性。
一些考虑因素
主版本跳跃 |
主版本号是否更改了? 当您看到这种情况时,在考虑以下任何因素时,请特别注意受影响的库。 如果您的代码使用任何实验性 API(通常需要您通过注解或构建文件规范选择启用),即使是次要版本或补丁版本更改(例如从 1.2.3 升级到 1.3.1 或 1.2.3 升级到 1.2.5),也可能会带来额外的风险。 |
不稳定 API |
某些库版本可能包含不稳定 API。这些 API 通常是正在开发中的,或者依赖于另一个不稳定 API。 虽然通常仅限于预览版,例如 alpha、dev 或实验版,但有些库包含标记为实验性或不稳定的 API。 如果可能,请避免使用此类 API。如果您需要使用它们,请务必记录您的使用情况,并注意后续版本中的更改或移除。 |
动态行为 |
某些库根据外部因素表现不同。例如,与服务器通信的库取决于该服务器的更改。
|
清单合并 |
以 Android Archive (AAR) 形式发布的库可以包含合并到您的应用程序中的资源和清单。这些可以添加新的权限和 Android 组件,例如活动或广播接收器,这些组件间接运行。 |
运行时更新 |
某些库使用的功能可以在应用程序的控制之外进行更新。库可能会使用 Play Services,它独立于 Android SDK 进行升级。其他库可能会绑定到独立更新的外部应用程序中的服务(通常使用 AIDL)。 |
您跳过了多少个版本? |
您等待升级库的时间越长,潜在风险就越大。如果您看到版本发生显著变化,例如从 1.2.3 到 1.34.5,请特别注意此库。 |
迁移指南 |
检查库是否有迁移指南。这可以显著减少您的风险分析和缓解规划。 请注意,此类指南的存在是表明开发者已关注兼容性并考虑了您的升级缓解措施的一个好迹象。 |
发布说明 |
查看每个已更改库的发布说明(如果提供)。查找破坏性更改或新要求的指示,例如添加权限。 |
README 文件 |
某些库的 README 文件会指出潜在风险,特别是当库不提供发布说明时。查找“已知问题”,特别是已知的安全问题。 |
检查已知漏洞 |
Play SDK 索引跟踪许多流行 SDK 的漏洞。Play Console 会报告您是否使用了具有已知漏洞的列出的 SDK。在 Android Studio 中编辑构建文件时,IDE 会检查 SDK 索引并标记使用易受攻击的库版本的情况。 美国国家标准与技术研究院 (NIST) 维护着一个大型国家漏洞数据库 (NVD)。Dependency Check Gradle 插件根据 NVD 检查您使用的依赖项。 要使用 Dependency Check,请请求 NVD API 密钥,设置 Gradle 插件,然后运行 |
版本冲突 |
版本解析是否符合预期?查找冲突,特别是主版本差异。有关如何查找冲突的详细信息,请参阅Gradle 依赖项解析。特别是,在 如果可能,请与依赖项的作者合作以解决其依赖项冲突。如果您的公司允许,请对库贡献更改(上游),以帮助提高库的兼容性。 |
检查许可证 |
升级库时,请注意许可证的变化。库本身可能会更改为与您的应用程序或库不再兼容的许可证。新的传递依赖项也可能引入不兼容的许可证。有关如何检查您的依赖项当前许可证集的详细信息,请参阅验证许可证。 |
维护和 |
对于具有公共仓库的库
|
开源与闭源 |
如果一个库是开源的,那么调试问题会比闭源更容易,无论是您代码中的问题还是库代码中的问题。 最大限度地减少闭源依赖项,并在评估期间进行额外审查。是否有适合您用例的良好替代方案?闭源库有哪些服务级别协议可用?如果您选择使用闭源依赖项,请准备好编写额外的测试用例以帮助限制风险。 |
运行构建
构建您的项目。查找新的错误或警告。如果您能确定是哪个库导致了它们,请将其记录为升级该库的风险。
如果您看到任何新的弃用警告,请将它们作为该库产生的具体风险添加。这些可以在后续版本中移除。如果您想继续使用该库,请投入时间从使用弃用 API 转换为其替代品,或者记录这些弃用,以便密切关注这些函数以及它们是否在后续被移除。
使用 Lint 检测 API 问题
Android lint 可以捕获您应用程序中的许多问题,包括一些因依赖项或 Android SDK 版本更改而导致的问题。例如,如果您升级了 compileSdk
并使用其新的 API,lint 会报告那些在旧 SDK 版本中不可用的 API。
Lint 在 Android Studio 编辑器中运行,在您进行更改时报告问题。但它通常不会作为 Studio 构建的一部分或在您运行命令行构建时运行,除非您使用 build
或 lint
目标。
如果您使用持续集成 (CI),请在 CI 构建(或至少在夜间构建)期间运行 gradlew build
或 gradlew lint
,以捕获这些类型的错误。
如果您不使用 CI,请务必至少偶尔运行 gradlew lint
。
特别注意 lint 错误和警告。一些库随附自己的 lint 检查,有助于确保正确使用其 API。库的一些新版本包含新的 lint 警告和错误,导致您在构建时出现新报告。
缓解风险
在确定升级风险后,决定您希望如何缓解它们:
- 接受一些现有风险。有些风险足够低,可以接受,特别是在升级时间和资源有限的情况下。
- 彻底拒绝一些风险。有些升级可能感觉风险太大,特别是如果您此时缓解它们的时间或资源有限。如果您需要分类,请关注那些对于您遇到的错误或需要的新功能而言必需的升级。
- 缓解剩余风险
- 考虑将您的升级分批进行,分成更小、独立的更改集。这可以降低总体风险并允许部分回滚。
- 详细调查更改。
- 测试您的应用以检查意外更改。根据需要添加新测试以增强对升级的信心。
- 当发现可疑之处时,查看源代码(如果可用)。
- 在您的源代码或构建中进行必要的更改。
记录您的决策。如果升级的风险在运行应用程序时成为问题,您的风险分析文档可以减少必要的错误分析。
验证许可证
库开发者许可其库供您使用。您必须遵守许可证条款,否则无法使用该库。某些许可证非常宽松,通常只要求注明库的出处,并向最终用户展示其许可证文本。有些被认为是传染性的;如果您使用这些库,您必须将相同的许可证应用于您的应用程序或库。
许可证可能随任何版本更改。无论何时升级,您都应该验证您使用的依赖项的许可证与您的应用程序或库兼容。
如果许可证不兼容(或已更改为不再兼容),您不能使用该版本的库。您可以:
- 联系库所有者,请求继续使用现有许可证或双重许可,以继续允许旧许可证。
- 与您的法务团队合作,确定您是否可以将许可证更改为兼容。
- 找到一个具有兼容许可证的另一个库,并根据需要修改您的应用程序。
- 分叉库的最后一个兼容版本(如果该许可证允许派生且更改不具有追溯性)并进行您自己的更改。