preface

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

  1. Projects rely on unified management and are configured in separate files
  2. differentModuleThe dependency version number in
  3. The version numbers of dependencies are consistent across different projects

To address these needs, there are already some solutions:

  1. Optimize Gradle dependency management with loops
  2. Manage Gradle dependencies with buildSrc
  3. Uniformly configure dependent versions using includeBuild

Gradle7.0 has released a new feature, the Catalog unified dependencies, which supports the following features:

  1. For allmoduleVisible, all can be managed uniformlymoduleThe dependence of
  2. Support declarative dependenciesbundlesThat is, dependencies that are always used together can be combined
  3. Separation of version numbers from dependency names is supported and version numbers can be shared across multiple dependencies
  4. Support in separatelibs.versions.tomlConfigure dependencies in the file
  5. Support for sharing dependencies between projects

useVersion Catalog

Note that the Catalog is still an incubation feature. To use it, add the following to settings.gradle:

enableFeaturePreview('VERSION_CATALOGS')
Copy the code

As you can see from the naming, Version Catalog is actually a Version Catalog. We can select the dependencies we want from the Catalog. We can use the dependencies declared in the Catalog in the following way

dependencies {
    implementation(libs.retrofit)
    implementation(libs.groovy.core)
}
Copy the code

In this case, liBS is a directory, and Retrofit represents the dependencies available in that directory. Version Catalog has many advantages over declaring dependencies directly in build scripts:

  • For eachcatalog.GradleWill generate type-safe accessors so that you can use themIDECan be completed automaticallybuild.gradleIs not auto-complete yetktsOr in development?)
  • The statement incatalogAll dependencies inmoduleYou can modify the version in a unified manner
  • catalogSupport for declaring a dependencybundles, a combination of dependencies that are always used together
  • catalogSeparation of version numbers from dependency names is supported and version numbers can be shared across multiple dependencies

The statementVersion Catalog

Version Catalog can be declared in settings.gradle(.kts) file.

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'}}}}Copy the code

Aliases must consist of a series of dashes (-, recommended), underscores (_), or dots (.). Delimited identifier composition. The identifier itself must consist of ASCII characters, preferably lowercase, followed by a number.

It’s worth noting that groovy-core will be mapped to libs.groovy.core and can be case sensitive if you want to avoid mapping. For example, groovyCore will be treated as libs.groovycore

Dependencies with the same version number

In the example above, we can see that all three Groovy dependencies have the same version number, and we can unify them

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'}}}}Copy the code

In addition to dependencies, you can also get versions in build.gradle to specify compileSdk, etc

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


    defaultConfig {
        applicationId "com.zj.gradlecatalog"
        minSdk 21
        targetSdk libs.versions.targetsdk.get().toInteger()
    }
}
Copy the code

As above, can use unified catalog compileSdk targetSdk, minSdk version number

Rely onbundles

Because certain dependencies are often systematically used together in different projects, Catalog provides the concept of bundles. Dependency packages are basically aliases for several dependency packages. For example, instead of declaring three separate dependencies, you could use a dependency package like this:

dependencies {
    implementation libs.bundles.groovy
}
Copy the code

Groovy dependencies are declared as follows:

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'])}}}Copy the code

As shown above: Adding a Groovy dependency package is the same as adding all the dependencies under the dependency package

The plug-in version

In addition to Library, Catalog supports declaring plug-in versions. Because libraries are represented by their groups, artifacts, and versions, Gradle plug-ins are identified only by their IDS and versions. Therefore, plug-ins need to be declared separately:

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            alias('jmh').toPluginId('me.champeau.jmh').version('0.6.5')}}}Copy the code

It can then be used under the plugins block

plugins {
    id 'java-library'
    id 'checkstyle'
    // Use declared plug-ins
    alias(libs.plugins.jmh)
}
Copy the code

Configure in a separate fileCatalog

In addition to declaring the Catalog in settings.gradle, a separate file can be used to configure the Catalog. If the libs.versions.toml file is found in the gradle directory of the root build, a Catalog will be automatically declared using the contents of that file

The TOML file consists of four main parts:

  • [versions]The section is used to declare versions that can be referenced by dependencies
  • [libraries]Part used to declareLibraryThe alias
  • [bundles]Part is used to declare dependency packages
  • [plugins]Part is used to declare plug-ins

As follows:

[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" }
Copy the code

As shown above, dependencies can be defined as a string or module can be separated from version, where versions can be defined as a string or a range, see rich-version for details

[versions]
my-lib = { strictly = "[1.0, 2.0 [", prefer = "1.2" }
Copy the code

Share between projectsCatalog

Catalog can not only manage dependencies uniformly within a project, but can also be shared between projects. For example, we need to create a dependency specification within a team, and different projects in different groups need to share these dependencies. This is a common requirement

Through File Sharing

Catalog supports importing dependencies from Toml files, which allows us to implement shared dependencies by specifying file paths as shown in settins.gradle:

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from(files(".. /gradle/libs.versions.toml"))}}}Copy the code

This technique can be used to declare multiple directories from different files:

dependencyResolutionManagement {
    versionCatalogs {
        // Declare a 'testLibs' directory from the 'test-libs.versions.toml' file
        testLibs {
            from(files('gradle/test-libs.versions.toml'))}}}Copy the code

Publish plug-ins for sharing

While it is convenient to import the Catalog from a local file, it does not solve the problem of sharing the Catalog among organizations or external consumers. It is also possible to publish the Catalog through the Catalog plug-in, which users can import directly

Gradle provides a Catalog plug-in that provides the ability to declare and then publish a Catalog.

1. Introduce two plug-ins first

plugins {
    id 'version-catalog'
    id 'maven-publish'
}
Copy the code

The plug-in then exposes the catalog extension that can be used to declare the catalog

2. Define a directory

With the plug-in introduced above, you can use the Catalog extension to define the catalog

catalog {
    // Define a directory
    versionCatalog {
        from files('.. /libs.versions.toml')}}Copy the code

Directories can then be published using the Maven-publish plug-in

3. Release catalog

publishing {
    publications {
        maven(MavenPublication) {
            groupId = 'com.zj.catalog'
            artifactId = 'catalog'
            version = '1.0.0'
            from components.versionCatalog
        }
    }
}
Copy the code

We defined the groupId, artifactId, version, the from can release we released to mavenLocal here, you can also according to need to configure the release to the maven release all of the code above is visible: the Catalog release relevant code

4. Use directories

Since we have already published to mavenLocal, we can use the plug-in by introducing mavenLocal in the repository

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

enableFeaturePreview('VERSION_CATALOGS')
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from("Com. What zj had. Catalog: the catalog: 1.0.0")
            // We can also override the Groovy version of the catalog
            version("groovy"."3.0.6")}}}Copy the code

With the successful introduction of the plug-in above, dependencies in the catalog can be used to complete inter-project sharing of dependencies. All the code used above can be seen: The catalog uses the related code

conclusion

Gradle creates a Catalog that allows you to easily share dependencies between projects. The Catalog has the following features:

  1. For allmoduleVisible, all can be managed uniformlymoduleThe dependence of
  2. Support declarative dependenciesbundlesThat is, dependencies that are always used together can be combined
  3. Separation of version numbers from dependency names is supported and version numbers can be shared across multiple dependencies
  4. Support in separatelibs.versions.tomlConfigure dependencies in the file
  5. Support for sharing dependencies between projects

All relevant code for this article

The Catalog publishes the associated code. The Catalog uses the associated code

The resources

Sharing dependency versions between projects