[Gradle7.0] A new way of relying on unified management, learn about it~

foreword

With the continuous development of the project, there are more and more dependencies in the project, and sometimes there may be hundreds of them. At this time, it is necessary to have a unified management of project dependencies. We generally have the following requirements:

  1. Project dependencies are managed uniformly and configured in a separate file
  2. ModuleUnified version numbers of dependencies in different
  3. Unified version numbers of dependencies in different projects

In response to these needs, there are already some solutions:

  1. Optimizing Gradle Dependency Management with Loops
  2. Using buildSrc to manage Gradle dependencies
  3. Use includeBuild to uniformly configure dependency versions

The above solution supports the Moduleunified version number between different projects. At the same time, if it needs to be shared between projects, it can also be made into a Gradleplug-in and released to the remote end, which can basically meet our needs.
However Gradle7.0, a new feature has been introduced, using a Catalogunified dependency version, it The following features are supported:

  1. Visible to all module, unified management moduleof all dependencies
  2. Support for declarative dependencies bundles, i.e. dependencies that are always used together can be grouped together
  3. Supports the separation of version numbers and dependency names, and can share version numbers among multiple dependencies
  4. Support libs.versions.tomlfor configuring dependencies in separate files
  5. Support for sharing dependencies between projects

useVersion Catalog

Note that Catalogit is still an incubating feature, if you want to use it, you need settings.gradleto add the following to it:

enableFeaturePreview('VERSION_CATALOGS')
复制代码

It can also be seen from the naming that it Version Catalogis actually a version of the directory. We can select the dependencies we need from the directory to use. We can use the dependencies declared in the
following waysCatalog

dependencies {
    implementation(libs.retrofit)
    implementation(libs.groovy.core)
}
复制代码

In this case, libsa directory retrofitrepresenting the dependencies available in that directory. Version CatalogHas many advantages over declaring dependencies directly in the build script :

  • 对于每个catalog,Gradle都会生成类型安全的访问器,以便你在IDE中可以自动补全.(注:目前在build.gradle中还不能自动补全,可能是指kts或者开发中?)
  • 声明在catalog中的依赖对所有module可见,当修改版本号时,可以统一管理统一修改
  • catalog支持声明一个依赖bundles,即一些总是一起使用的依赖的组合
  • catalog支持版本号与依赖名分离,可以在多个依赖间共享版本号

声明Version Catalog

Version Catalog可以在settings.gradle(.kts)文件中声明。

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            alias('retrofit').to('com.squareup.retrofit2:retrofit:2.9.0')
            alias('groovy-core').to('org.codehaus.groovy:groovy:3.0.5')
            alias('groovy-json').to('org.codehaus.groovy:groovy-json:3.0.5')
            alias('groovy-nio').to('org.codehaus.groovy:groovy-nio:3.0.5')
            alias('commons-lang3').to('org.apache.commons', 'commons-lang3').version {
                strictly '[3.8, 4.0['
                prefer '3.9'
            }
        }
    }
}
复制代码

别名必须由一系列以破折号(-,推荐)、下划线 (_) 或点 (.) 分隔的标识符组成。
标识符本身必须由ascii字符组成,最好是小写,最后是数字。

值得注意的是,groovy-core会被映射成libs.groovy.core
如果你想避免映射可以使用大小写来区分,比如groovyCore会被处理成libs.groovyCore

具有相同版本号的依赖

在上面的示例中,我们可以看到三个groovy依赖具有相同的版本号,我们可以把它们统一起来

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            version('groovy', '3.0.5')
            version('compilesdk', '30')
            version('targetsdk', '30')
            alias('groovy-core').to('org.codehaus.groovy', 'groovy').versionRef('groovy')
            alias('groovy-json').to('org.codehaus.groovy', 'groovy-json').versionRef('groovy')
            alias('groovy-nio').to('org.codehaus.groovy', 'groovy-nio').versionRef('groovy')
            alias('commons-lang3').to('org.apache.commons', 'commons-lang3').version {
                strictly '[3.8, 4.0['
                prefer '3.9'
            }
        }
    }
}
复制代码

除了在依赖中,我们同样可以在build.gradle中获取版本,比如可以用来指定compileSdk

android {
    compileSdk libs.versions.compilesdk.get().toInteger()


    defaultConfig {
        applicationId "com.zj.gradlecatalog"
        minSdk 21
        targetSdk libs.versions.targetsdk.get().toInteger()
    }
}
复制代码

如上,可以使用catalog统一compileSdk,targetSdk,minSdk的版本号

依赖bundles

因为在不同的项目中经常系统地一起使用某些依赖项,所以Catalog提供了bundle(依赖包)的概念。依赖包基本上是几个依赖项打包的别名。
例如,你可以这样使用一个依赖包,而不是像上面那样声明 3 个单独的依赖项:

dependencies {
    implementation libs.bundles.groovy
}
复制代码

groovy依赖包声明如下:

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            version('groovy', '3.0.5')
            version('checkstyle', '8.37')
            alias('groovy-core').to('org.codehaus.groovy', 'groovy').versionRef('groovy')
            alias('groovy-json').to('org.codehaus.groovy', 'groovy-json').versionRef('groovy')
            alias('groovy-nio').to('org.codehaus.groovy', 'groovy-nio').versionRef('groovy')
            alias('commons-lang3').to('org.apache.commons', 'commons-lang3').version {
                strictly '[3.8, 4.0['
                prefer '3.9'
            }
            bundle('groovy', ['groovy-core', 'groovy-json', 'groovy-nio'])
        }
    }
}
复制代码

如上所示:添加groovy依赖包等同于添加依赖包下的所有依赖项

插件版本

除了Library之外,Catalog还支持声明插件版本。
因为library由它们的groupartifactversion表示,但Gradle插件仅由它们的idversion标识。
因此,插件需要单独声明:

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            alias('jmh').toPluginId('me.champeau.jmh').version('0.6.5')
        }
    }
}
复制代码

然后可以在plugins块下面使用

plugins {
    id 'java-library'
    id 'checkstyle'
    // 使用声明的插件
    alias(libs.plugins.jmh)
}
复制代码

在单独文件中配置Catalog

除了在settings.gradle中声明Catalog外,也可以通过一个单独的文件来配置Catalog
如果在根构建的gradle目录中找到了libs.versions.toml文件,则将使用该文件的内容自动声明一个Catalog

TOML文件主要由4个部分组成:

  • [versions] 部分用于声明可以被依赖项引用的版本
  • [libraries] 部分用于声明Library的别名
  • [bundles] 部分用于声明依赖包
  • [plugins] 部分用于声明插件

如下所示:

[versions]
groovy = "3.0.5"
checkstyle = "8.37"
compilesdk = "30"
targetsdk = "30"

[libraries]
retrofit = "com.squareup.retrofit2:retrofit:2.9.0"
groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" }
groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" }
groovy-nio = { module = "org.codehaus.groovy:groovy-nio", version.ref = "groovy" }
commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer="3.9" } }

[bundles]
groovy = ["groovy-core", "groovy-json", "groovy-nio"]

[plugins]
jmh = { id = "me.champeau.jmh", version = "0.6.5" }
复制代码

如上所示,依赖可以定义成一个字符串,也可以将moduleversion分离开来
其中versions可以定义成一个字符串,也可以定义成一个范围,详情可参见rich-version

[versions]
my-lib = { strictly = "[1.0, 2.0[", prefer = "1.2" }
复制代码

在项目间共享Catalog

Catalog不仅可以在项目内统一管理依赖,同样可以实现在项目间共享
例如我们需要在团队内制定一个依赖规范,不同组的不同项目需要共享这些依赖,这是个很常见的需求

通过文件共享

Catalog支持通过从Toml文件引入依赖,这就让我们可以通过指定文件路径来实现共享依赖
如下所示,我们在settins.gradle中配置如下:

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}
复制代码

此技术可用于声明来自不同文件的多个目录:

dependencyResolutionManagement {
    versionCatalogs {
        // 声明一个'testLibs'目录, 从'test-libs.versions.toml'文件中
        testLibs {
            from(files('gradle/test-libs.versions.toml'))
        }
    }
}
复制代码

发布插件实现共享

虽然从本地文件导入Catalog很方便,但它并没有解决在组织或外部消费者中共享Catalog的问题。
我们还可能通过Catalog插件来发布目录,这样用户直接引入这个插件即可

Gradle提供了一个Catalog插件,它提供了声明然后发布Catalog的能力。

1. 首先引入两个插件

plugins {
    id 'version-catalog'
    id 'maven-publish'
}
复制代码

然后,此插件将公开可用于声明目录的catalog扩展

2. 定义目录

上面引入插件后,即可使用catalog扩展定义目录

catalog {
    // 定义目录
    versionCatalog {
        from files('../libs.versions.toml')
    }
}
复制代码

然后可以通过maven-publish插件来发布目录

3. 发布目录

publishing {
    publications {
        maven(MavenPublication) {
            groupId = 'com.zj.catalog'
            artifactId = 'catalog'
            version = '1.0.0'
            from components.versionCatalog
        }
    }
}
复制代码

我们定义好groupId,artifactId,version,from就可以发布了
我们这里发布到mavenLocal,你也可以根据需要配置发布到自己的maven
以上发布的所有代码可见:Catalog发布相关代码

4. 使用目录

因为我们已经发布到了mavenLocal,在仓库中引入mavenLocal就可以使用插件了

# settings.gradle
dependencyResolutionManagement {
    //...
    repositories {
        mavenLocal()
        //...
    }
}

enableFeaturePreview('VERSION_CATALOGS')
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from("com.zj.catalog:catalog:1.0.0")
            // 我们也可以重写覆盖catalog中的groovy版本
            version("groovy", "3.0.6")
        }
    }
}
复制代码

如上就成功引入了插件,就可以使用catalog中的依赖了
这样就完成了依赖的项目间共享,以上使用的所有代码可见:Catalog使用相关代码

总结

项目间共享依赖是比较常见的需求,虽然我们也可以通过自定义插件实现,但还是不够方便
Gradle官方终于推出了Catalog,让我们可以方便地实现依赖的共享,Catalog主要具有以下特性:

  1. 对所有module可见,可统一管理所有module的依赖
  2. Support for declarative dependencies bundles, i.e. dependencies that are always used together can be grouped together
  3. Supports the separation of version numbers and dependency names, and can share version numbers among multiple dependencies
  4. Support libs.versions.tomlfor configuring dependencies in separate files
  5. Support for sharing dependencies between projects

All relevant code in this article

Catalog publishes related code
Catalog uses related code

References

Sharing dependency versions between projects

Guess you like

Origin juejin.im/post/6997396071055900680