📝

Gradle 7.0 で導入されたバージョンカタログを試してみた

2021/08/16に公開

はじめに

みなさんは Gralde で依存関係バージョンの一元化をする際、何を使っていますか?

gradle.build 内の ext や 外部ファイル(dependencies.gradle など)、BuildSrc、専用のプラグインなどなど、さまざまな方法を試してきたのではないかなと思います。自分もその一人でした。

まだ実験的機能ではありますが、Gradle 7.0 で標準的な仕組みが用意されました。

バージョンカタログという仕組みです。

開発環境

  • Android Studio Arctic Fox | 2020.3.1
  • Java 11

成果物

https://github.com/blendthink/version-catalog-demo

導入手順

詳しくは公式の以下のページをご覧ください。
https://docs.gradle.org/7.0.2/userguide/platforms.html#sub:central-declaration-of-dependencies

1. 実験的機能を有効にする

settings.gradle.ktsenableFeaturePreview("VERSION_CATALOGS") を追加します。

settings.gradle.kts
enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "Version Catalog Demo"
include(":app")

2. gradle/libs.versions.toml を追加する

TOML ファイルについては下記をご覧ください。
https://github.com/toml-lang/toml

Jetbrains の Plugin もあるので、入れておくのをお勧めします。
https://plugins.jetbrains.com/plugin/8195-toml

gradle/libs.versions.toml
[versions]
kotlin = "1.5.21"
build-gradle = "7.0.0"

androidx-coreKtx = "1.6.0"
androidx-appcompat = "1.3.1"
material = "1.4.0"

androidx-lifecycle = "2.3.1"

androidx-compose = "1.0.1"

androidx-activityCompose = "1.3.1"

junit = "4.13.2"
androidx-test-ext-junit = "1.1.3"
androidx-test-espressoCore = "3.4.0"

[libraries]
# classpath
build-gradle = { module = "com.android.tools.build:gradle", version.ref = "build-gradle" }
kotlin-kotlinGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }

# implementation
androidx-coreKtx = { module = "androidx.core:core-ktx", version.ref = "androidx-coreKtx" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
material = { module = "com.google.android.material:material", version.ref = "material" }

# implementaion
androidx-lifecycleRuntimeKtx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }

# implementation
androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "androidx-compose" }
androidx-compose-uiToolingPreview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "androidx-compose" }
androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "androidx-compose" }
# androidTestImplementation
androidx-compose-uiTestJunit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "androidx-compose" }
# debugImplementation
androidx-compose-uiTooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "androidx-compose" }

# implementation
androidx-activityCompose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }

# testImplementation
junit = { module = "junit:junit", version.ref = "junit" }

# androidTestImplementation
androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-ext-junit" }
androidx-test-espressoCore = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espressoCore" }

[bundles]
# implementation
androidx-compose = [ "androidx-compose-ui", "androidx-compose-uiToolingPreview", "androidx-compose-material" ]

3. build.gradle.kts の記述を置き換える

※ 現在、Kotlin DSL は buildscript スコープで libs オブジェクトを宣言していないため、特別な対応が必要です。
https://github.com/gradle/gradle/issues/16958

build.gradle.kts
buildscript {
    ...
    dependencies {
        // Currently version catalog does not work in the buildscript scope.
        // https://github.com/gradle/gradle/issues/16958
        val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs") as org.gradle.accessors.dm.LibrariesForLibs
        classpath(libs.build.gradle)
        classpath(libs.kotlin.kotlinGradlePlugin)
    }
}
...
app/build.gradle.kts
android {
    ...
    composeOptions {
        kotlinCompilerExtensionVersion = libs.versions.androidx.compose.get()
    }
}
...
dependencies {

    implementation(libs.androidx.coreKtx)
    implementation(libs.androidx.appcompat)
    implementation(libs.material)

    implementation(libs.androidx.lifecycleRuntimeKtx)

    implementation(libs.bundles.androidx.compose)
    androidTestImplementation(libs.androidx.compose.uiTestJunit4)
    debugImplementation(libs.androidx.compose.uiTooling)

    implementation(libs.androidx.activityCompose)

    testImplementation(libs.junit)

    androidTestImplementation(libs.androidx.test.ext.junit)
    androidTestImplementation(libs.androidx.test.espressoCore)
}

TOML ファイルではなく settings.gradle.kts に記述する方法

導入手順2の代わりに settings.gradle.kts を以下のようにします。

settings.gradle.kts
enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
    versionCatalogs {
        create("libs") {
            version("kotlin", "1.5.21")
            version("build-gradle", "7.0.0")

            version("androidx-coreKtx", "1.6.0")
            version("androidx-appcompat", "1.3.1")
            version("material", "1.4.0")

            version("androidx-lifecycle", "2.3.1")

            version("androidx-compose", "1.0.1")

            version("androidx-activityCompose", "1.3.1")

            version("junit", "4.13.2")
            version("androidx-test-ext-junit", "1.1.3")
            version("androidx-test-espressoCore", "3.4.0")

            // classpath
            alias("build-gradle").to("com.android.tools.build", "gradle").versionRef("build-gradle")
            alias("kotlin-kotlinGradlePlugin").to("org.jetbrains.kotlin", "kotlin-gradle-plugin").versionRef("kotlin")

            // implementation
            alias("androidx-coreKtx").to("androidx.core", "core-ktx").versionRef("androidx-coreKtx")
            alias("androidx-appcompat").to("androidx.appcompat", "appcompat").versionRef("androidx-appcompat")
            alias("material").to("com.google.android.material", "material").versionRef("material")

            // implementation
            alias("androidx-lifecycleRuntimeKtx").to("androidx.lifecycle", "lifecycle-runtime-ktx").versionRef("androidx-lifecycle")

            // implementation
            alias("androidx-compose-ui").to("androidx.compose.ui", "ui").versionRef("androidx-compose")
            alias("androidx-compose-uiToolingPreview").to("androidx.compose.ui", "ui-tooling-preview").versionRef("androidx-compose")
            alias("androidx-compose-material").to("androidx.compose.material", "material").versionRef("androidx-compose")
            // androidTestImplementation
            alias("androidx-compose-uiTestJunit4").to("androidx.compose.ui", "ui-test-junit4").versionRef("androidx-compose")
            // debugImplementation
            alias("androidx-compose-uiTooling").to("androidx.compose.ui", "ui-tooling").versionRef("androidx-compose")

            // implementation
            alias("androidx-activityCompose").to("androidx.activity", "activity-compose").versionRef("androidx-activityCompose")

            // testImplementation
            alias("junit").to("junit", "junit").versionRef("junit")

            // androidTestImplementation
            alias("androidx-test-ext-junit").to("androidx.test.ext", "junit").versionRef("androidx-test-ext-junit")
            alias("androidx-test-espressoCore").to("androidx.test.espresso", "espresso-core").versionRef("androidx-test-espressoCore")

            // implementation
            bundle("androidx-compose", listOf("androidx-compose-ui", "androidx-compose-uiToolingPreview", "androidx-compose-material"))
        }
    }
}
rootProject.name = "Version Catalog Demo"
include(":app")

どちらともサジェスト機能使えず、最新バージョンなどの警告もでないため、ファイル数を多くするのを許容するか1つのファイルに複数の記述を許容するかのどちらを選択するかですね。。

おわりに

TOML ファイルの方法と settings.gradle.kts に直接記述する方法を紹介しました。

以前の buildSrc の方法と比較すると

メリット

  • ビルドが速くなる
  • TOML ファイルの方法だと、関連するものごとに、簡単にファイル単位で分割できる

デメリット

  • 1度定義したバージョンなどの入力補完が使えない
  • 定義ジャンプが使えない

こんな感じなので、今後の IDEA の機能に期待して、新しいプロジェクトでは TOML ファイルの方法を使用していこうかなと思います。

Discussion