current position:Home>[gradle 7.0] rely on a new way of unified management. Learn about it~

[gradle 7.0] rely on a new way of unified management. Learn about it~

2022-01-27 04:17:49 RicardoMJiang

Preface

With the development of the project , There are more and more dependencies in the project , Sometimes there may be hundreds , At this time, it is necessary to make a unified management of project dependency , We usually have the following needs :

  1. The project relies on unified management , Configure... In a separate file
  2. Different Module The dependent version numbers in are unified
  3. The dependent version numbers in different projects are unified

For these needs , At present, there are actually some plans :

  1. Use loop optimization Gradle Dependency management
  2. Use buildSrc management Gradle rely on
  3. Use includeBuild Unified configuration depends on version

The above scheme supports different Module Uniform version number between , At the same time, if you need to share between projects , It can also be made Gradle The plug-in is published to the remote , It can basically meet our needs
however Gradle7.0 There's a new feature coming out , Use Catalog Unified dependency version , It supports the following features :

  1. For all module so , It can manage all module Dependence
  2. Support declaration dependency bundles, That is, dependencies that are always used together can be grouped together
  3. Support the separation of version number and dependency name , You can share version numbers among multiple dependencies
  4. Support in separate libs.versions.toml Configure dependencies in the file
  5. Support the sharing of dependencies between projects

Use Version Catalog

Be careful ,Catalog It's still a hatching feature , If you want to use , Need to be in settings.gradle To add the following :

enableFeaturePreview('VERSION_CATALOGS')
 Copy code 

We can also see from the naming ,Version Catalog In fact, it is a version of the directory , We can select the dependencies we need from the directory
We can use Catalog The dependency declared in

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

under these circumstances ,libs Is a directory ,retrofit Represents the dependencies available in the directory . Compared with declaring dependencies directly in the build script ,Version Catalog It has many advantages :

  • For each catalog,Gradle Will generate type safe accessors , So that you can IDE It can automatically complete .( notes : Currently in build.gradle It can't be completed automatically in , Maybe it means kts Or in development ?)
  • The statement in catalog The dependency in is for all module so , When modifying the version number , It can be managed and modified uniformly
  • catalog Support declaring a dependency bundles, That is, a combination of dependencies that are always used together
  • catalog Support the separation of version number and dependency name , You can share version numbers among multiple dependencies

Statement Version Catalog

Version Catalog Can be in settings.gradle(.kts) Declaration in the document .

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 code 

The alias must consist of a series of dashes (-, recommend )、 Underline (_) Or point (.) Composed of separated identifiers .
The identifier itself must consist of ascii Character composition , Lowercase is preferred , Finally, the numbers .

It is worth noting that ,groovy-core Will be mapped to libs.groovy.core
If you want to avoid mapping, you can use case to distinguish , such as groovyCore Will be treated as libs.groovyCore

Dependencies with the same version number

In the example above , We can see three groovy Dependencies have the same version number , 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 code 

Except in dependence , We can also be in build.gradle Get version in , For example, it can be used 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 code 

Above , have access to catalog Unified compileSdk,targetSdk,minSdk Version number of

rely on bundles

Because some dependencies are often used together systematically in different projects , therefore Catalog Provides bundle( Dependency package ) The concept of . A dependency package is basically an alias for packaging several dependencies .
for example , You can use a dependency package like this , Instead of declaring as above 3 A separate dependency :

dependencies {
    implementation libs.bundles.groovy
}
 Copy code 

groovy The dependent package is 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 code 

As shown above : add to groovy Dependent packages are equivalent to adding all dependencies under dependent packages

The plug-in version

except Library outside ,Catalog It also supports declaring plug-in versions .
because library By their groupartifact and version Express , but Gradle Plugins are made up only of their id and version identification .
therefore , The plug-in needs to be declared separately :

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

Then you can go to plugins Use... Under the block

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

Configure... In a separate file Catalog

In addition to the settings.gradle In a statement Catalog Outside , It can also be configured through a separate file Catalog
If built at the root gradle Found... In the catalog libs.versions.toml file , The contents of the file will be used to automatically declare a Catalog

TOML The documents are mainly made up of 4 Component composition :

  • [versions] The part is used to declare the version that can be referenced by the dependency
  • [libraries] Part is used to declare Library Another name for
  • [bundles] Part is used to declare dependent packages
  • [plugins] Part is used to declare the plug-in

As shown below :

[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 code 

As shown above , Dependency can be defined as a string , Can also be module And version Separate from
among versions Can be defined as a string , It can also be defined as a range , Details can be found at rich-version

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

Share between projects Catalog

Catalog It can not only manage dependencies uniformly within the project , It can also be shared among projects
For example, we need to develop a dependency specification within the team , Different projects in different groups need to share these dependencies , This is a very common requirement

Through file sharing

Catalog Support from Toml File import dependency , This allows us to implement shared dependencies by specifying file paths
As shown below , We are settins.gradle The configuration in is as follows :

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

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

dependencyResolutionManagement {
    versionCatalogs {
        //  Make a statement 'testLibs' Catalog ,  from 'test-libs.versions.toml' In file 
        testLibs {
            from(files('gradle/test-libs.versions.toml'))
        }
    }
}
 Copy code 

Publish plug-ins to realize sharing

Although import from local file Catalog Very convenient , But it doesn't solve the problem of sharing among organizations or external consumers Catalog The problem of .
We may also pass Catalog Plug-ins to publish directories , In this way, users can directly introduce this plug-in

Gradle Provides a Catalog plug-in unit , It provides a statement and then publishes Catalog The ability of .

1. First introduce two plug-ins

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

then , This plug-in will expose the... That can be used to declare directories catalog Expand

2. Define Directory

After the plug-in is introduced above , You can use catalog Extension definition Directory

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

And then you can go through maven-publish Plug-ins to publish directories

3. Publishing directory

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

Let's define groupId,artifactId,version,from You can release
We post it here to mavenLocal, You can also configure and publish to your own maven
All the code published above can be seen :Catalog Release relevant code

4. Use directory

Because we have posted to mavenLocal, Introduce... Into the warehouse mavenLocal You can use plug-ins

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

enableFeaturePreview('VERSION_CATALOGS')
dependencyResolutionManagement {
    versionCatalogs {
        libs {
            from("com.zj.catalog:catalog:1.0.0")
            //  We can also override catalog Medium groovy edition 
            version("groovy", "3.0.6")
        }
    }
}
 Copy code 

The plug-in has been successfully introduced as above , You can use catalog Dependence in
This completes the sharing of dependent projects , All the codes used above are visible :Catalog Use relevant codes

summary

Sharing dependencies between projects is a common requirement , Although we can also implement it through custom plug-ins , But it's not convenient enough
Gradle The official finally launched Catalog, Let us easily realize the sharing of dependencies ,Catalog It has the following characteristics :

  1. For all module so , It can manage all module Dependence
  2. Support declaration dependency bundles, That is, dependencies that are always used together can be grouped together
  3. Support the separation of version number and dependency name , You can share version numbers among multiple dependencies
  4. Support in separate libs.versions.toml Configure dependencies in the file
  5. Support the sharing of dependencies between projects

All relevant codes in this article

Catalog Release relevant code
Catalog Use relevant codes

Reference material

Sharing dependency versions between projects

copyright notice
author[RicardoMJiang],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/01/202201270417423228.html

Random recommended