现代 Android 依赖管理 catalog(二)

527 阅读4分钟

实现 Catalog 管理中的一些问题及解决办法

在 Android 项目中使用 Gradle 版本目录(Catalog)管理依赖时,常因语法规则或配置细节导致构建错误。本文结合实际案例,总结常见问题及解决办法,助力高效配置 libs.versions.toml

一、非法顶级元素错误:[versionGroups]

问题现象

Invalid TOML catalog definition: unknown top level elements [versionGroups]

原因分析

Gradle 的 TOML 版本目录仅支持 versionslibrariespluginsbundlesmetadata 作为顶级元素,versionGroups 是构建脚本(如 build.gradle.kts)的配置,不可用于 TOML 文件。

解决办法

直接移除 [versionGroups] 区块,版本分组逻辑可通过其他合法方式实现(如在依赖声明中统一版本引用)。

二、platform 关键字不兼容错误

问题现象

On library declaration 'androidx-compose-ui' expected to find any of 'group', 'module', 'name', or 'version' but found unexpected key 'platform'

原因分析

使用 platform 关联 BOM 时,需同时明确依赖的坐标(group/namemodule),且 Gradle 不允许在依赖声明中同时使用 platformversion.ref

解决办法

1. 简化依赖声明(推荐)

移除 platform 关键字,通过 build.gradle 引入 BOM,依赖声明仅保留 groupname(版本由 BOM 自动管理):

# libs.versions.toml
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }  # 仅保留坐标,无版本和 platform

2. build.gradle 中正确引用 BOM

dependencies {
    implementation(platform(libs.androidx.compose.bom))  # 集中声明 BOM
    implementation(libs.androidx.compose.ui)  # 无需重复声明版本
}

三、TOML 语法格式错误

问题现象

Unexpected end of line, expected a-z, A-Z, 0-9, }, ', or "

原因分析

多行对象格式中存在多余逗号、括号不匹配或缩进错误(TOML 不允许对象最后一个元素后有逗号)。

解决办法

1. 使用单行格式声明依赖

# 错误(多行格式易出错)
androidx-compose-ui = { 
  group = "androidx.compose.ui", 
  name = "ui", 
  version.ref = "composeBom"  # 最后一个元素后不能有逗号
}
​
# 正确(单行格式,无多余逗号)
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "composeBom" }

2. 利用 IDE 格式化工具

通过 Android Studio 的 Ctrl + Alt + L 自动修复 TOML 格式,确保括号、逗号匹配。

四、BOM 依赖版本管理混乱

问题现象

依赖版本未按 BOM 统一管理,出现版本冲突。

解决办法

1. 集中管理 BOM 版本

[versions] 中定义 BOM 版本,所有相关依赖无需单独声明版本:

[versions]
composeBom = "2024.04.00"  # 统一 BOM 版本[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }

2. 独立版本依赖单独处理

非 BOM 管理的依赖(如 Material3),直接声明版本:

androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version = "1.3.0" }

五、依赖无法下载

镜像源检查

  • 首先检查镜像源:settings.gradle.kts

    pluginManagement {
        repositories {
            gradlePluginPortal()
            maven { url = uri("https://mirrors.cloud.tencent.com/gradle-plugin") }
            maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
            maven { url = uri("https://developer.huawei.com/repo/") }
            maven{ url = uri("https://maven.aliyun.com/nexus/content/groups/public/")  }
            maven{ url = uri("https://maven.aliyun.com/nexus/content/repositories/jcenter")  }
    ​
            google()
            mavenCentral()
        }
    }
    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            maven { url = uri("https://mirrors.cloud.tencent.com/maven") }
            maven { url = uri("https://maven.aliyun.com/repository/public") }
            maven { url = uri("https://developer.huawei.com/repo/") }
    ​
            maven{ url = uri("https://maven.aliyun.com/nexus/content/groups/public/")  }
            maven{ url = uri("https://maven.aliyun.com/nexus/content/repositories/jcenter")  }
    ​
            google()
            mavenCentral()
            maven { url = uri("https://jitpack.io") }
        }
    }
    ​
    ​
    rootProject.name = "NextThing"
    include(":app")
    ​
    

开启魔法

  • 实在不行,启动魔法,然后为Android Studio进行代理配置

    • 配置代理:

      image.png

    • 配置好后,点击检查:键入所需的网址噻

      image.png

    • 成功:

      image.png

六、奇怪的问题

依赖传递

  • 问题现象

    1. 版本冲突错误

      Conflict on version 'xxx' between the following dependencies: ...
      
    1. 未声明的依赖: 全局搜索找不到某个版本号,但 Gradle 报告该版本被引入。
    1. 依赖解析失败
    Could not resolve all files for configuration ':app:debugRuntimeClasspath'.
    
  • 问题本质

    • 依赖传递是指当您引入一个库时,该库自身依赖的其他库会被自动引入。例如:

      your-app -> libraryA:1.0.0 -> libraryB:2.0.0
      
    • 即使没有直接声明 libraryB,它也会通过 libraryA 被传递引入。
  • 常见原因

    • 传递依赖版本冲突:多个库依赖同一库的不同版本,例如:

      libraryA:1.0.0 -> libraryC:2.0.0
      libraryB:2.0.0 -> libraryC:3.0.0
      
  • Gradle 默认会选择最新版本,但可能导致兼容性问题。

    • 强制版本声明

      • catalogbuild.gradle 中使用 forceresolutionStrategy 强制指定版本,覆盖传递依赖。
    • BOM(Bill of Materials)干扰

      • 使用 BOM 管理依赖版本时,可能与传递依赖版本冲突。
  • 可以使用工具查看项目的依赖树进行辅助定位:

    image.png

Android Studio 会限制AGP 版本

image.png

七、最佳实践总结

  1. 合法顶级元素:仅使用 versionslibrariesplugins 三大核心区块(按需添加 bundles/metadata)。

  2. BOM 正确用法:

    • build.gradle 中通过 platform(libs.xxx.bom) 引入 BOM。
    • 依赖声明仅需 groupname,版本由 BOM 自动同步。
  3. 格式严谨性:

    • 优先使用单行格式声明依赖,避免多行逗号错误。
    • 借助 TOML 在线验证工具 排查语法问题。
  4. 版本集中控制:所有依赖版本在 [versions] 中统一定义,通过 version.ref 引用,避免硬编码。