17
5

More than 1 year has passed since last update.

Android + Gradle 探訪 - 後編: buildSrc や Version Catalog

Last updated at Posted at 2022-03-03

vercat.png

最近は Gradle の構成を Groovy ではなく KTS (一連の Gradle の Kotlin DSL) で書いたり
buildSrc や Version Catalog に依存をまとめるのがナウそうですが,
Android Studio で作成した新規プロジェクトはシンプルな Groovy で記述されています.

Kotlin DSL などについて まったくわかっていないので (Groovy もだけど),
この機会に Empty Compose Activity Project を題材にして,
最近の Gradle の構成や記述について調べようと思いました.

:point_down: 前編:

モジュール共通の定義

さて,前回の ext の節で書いたように,KTS の移行とは関係はないのですが
最近ではマルチモジュールでも共通で参照できるように
依存するライブラリの記述をまとめておくやりかたがよく使われているようです.
(要出典)

ここで紹介するのは,
ひとつは buildSrc に定義をまとめておいて参照するやりかた.
もうひとつは Gradle の Version Catalog として定義をまとめて参照するやりかたです.

buildSrc

buildSrc というディレクトリをつくりまして,
ここにプロジェクトで共通の定数・処理を置くと,
いろんなモジュールで使えて便利だねということです.

つまり,ライブラリのバージョンであるとか,
そういった定数をまとめておくのがパターンになっているということです.

なので,今回はそのパターンで buildSrc に定数を定義しましょう.

KotlinConf 2018 の公演でいうと,
26:55 〜 buildSrc での管理について紹介されています:

buildSrc/build.gradle.kts

まず buildSrc というディレクトリをつくります.
その中に build.gradle.kts をまず置きます:

buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}

repositories {
    mavenCentral()
}

同じく Kotlin DSL として記述できるようにしておきます.

ファイル作成後,リラックスして待っていると
.gradle ディレクトリができていて,なにやら構成されたことがわかります:

myproj20220302_–buildSrc_build_gradle_kts__myproj20220302.png

バージョンを定義する

次に buildSrc/src/main/kotlin というフォルダをつくり,
そこに Deps.kt を配置して,
このファイルにライブラリの依存についての定数をまとめることにします.

buildSrc/src/main/kotlin/Deps.kt
package dependencies

object Versions {
    object AndroidX {
        const val compose = "1.0.1"
    }
}

dependencies パッケージに Versions.AndroidX.compose という階層で,
Jetpack Compose まわりのライブラリのバージョンについて定義してみます.

そうすると,app/build.gradle.ktsimport して,
そのまま使うことができるわけです:

app/build.gradle.kts
import dependencies.Versions

android {
    composeOptions {
        kotlinCompilerExtensionVersion = Versions.AndroidX.compose
    }
}

dependencies {
    implementation("androidx.core:core-ktx:1.7.0")
    implementation("androidx.compose.ui:ui:${Versions.AndroidX.compose}")
    implementation("androidx.compose.material:material:${Versions.AndroidX.compose}")
    implementation("androidx.compose.ui:ui-tooling-preview:${Versions.AndroidX.compose}")
    // 以下略…
}

依存ライブラリを定義する

さらに,ライブラリの定義ごと定数としてまとめることを考えます:

buildSrc/src/main/kotlin/Dependencies.kt
package dependencies

object Versions {
    object AndroidX {
        const val compose = "1.0.1"
    }
}

object Deps {
    object AndroidX {
        const val coreKtx = "androidx.core:core-ktx:1.7.0"
        const val composeUi = "androidx.compose.ui:ui:${Versions.AndroidX.compose}"
        const val composeMaterial = "androidx.compose.material:material:${Versions.AndroidX.compose}"
        const val composeUiToolingPreview = "androidx.compose.ui:ui-tooling-preview:${Versions.AndroidX.compose}"
        const val lifecycleRuntimeKtx = "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
        const val activityCompose = "androidx.activity:activity-compose:1.3.1"
    }
    // 以下略…
}

書き方は自由ですが,このような階層でまとめたとしましょう.
そうすると,app/build.gradle.kts はこのように書けることになります:

app/build.gradle.kts
import dependencies.Deps

dependencies {
    implementation(Deps.AndroidX.coreKtx)
    implementation(Deps.AndroidX.composeUi)
    implementation(Deps.AndroidX.composeMaterial)
    implementation(Deps.AndroidX.composeUiToolingPreview)
    implementation(Deps.AndroidX.lifecycleRuntimeKtx)
    implementation(Deps.AndroidX.activityCompose)
    // 以下略…
}

こうしておくことで,ライブラリ関係の依存が一箇所にまとまるので,
複数モジュールで構成されたプロジェクトでは,
それぞれの build.gradle.kts に定義が分散せずに
管理が楽になることが期待できますね.
(あと,頑張れば共通の Gradle の記述自体を追い出すこともできそうです)

Version Catalog

別の手法としては Gradle の Version Catalog を使うことができそうです.

ただ,Version Catalog は Gradle バージョン 7.4 より前では Feature Preview です:

そのため,使用するにはまず settings.gradle.kts で Feature Preview を有効にします:

settings.gradle.kts
enableFeaturePreview("VERSION_CATALOGS")

次に,gradle/libs.versions.toml に Compose のバージョンを定義してみます:

gradle/libs.versions.toml
[versions]
compose = "1.0.1"

こうすれば Gradle 側で libs.* として参照できるので,
複数のモジュールで共通定義のバージョンを記述することができます:

app/build.gradle.kts
android {
    composeOptions {
        kotlinCompilerExtensionVersion = libs.versions.compose.get()
    }
}

libs.versions.composeorg.gradle.api.provider.Provider<String> が返ってくるので,
get()String として取り出せば使うことができます.

さらに依存ライブラリの定義を追加していきます.
今回は例としてこういうかたちにしてみました (どういう構成にするかは自由です):

gradle/libs.versions.toml
[versions]
compose = "1.0.1"

[libraries]
androidx-core-ktx = "androidx.core:core-ktx:1.7.0"
androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "compose" }
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
androidx-lifecycle-runtime-ktx = "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
androidx-activity-compose = "androidx.activity:activity-compose:1.3.1"

junit = "junit:junit:4.13.2"
androidx-test-ext-junit = "androidx.test.ext:junit:1.1.3"
androidx-test-espresso-core = "androidx.test.espresso:espresso-core:3.4.0"
androidx-compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose" }
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }

[bundles]
base = ["androidx-core-ktx", "androidx-lifecycle-runtime-ktx"]
compose = ["androidx-compose-ui", "androidx-compose-material", "androidx-compose-ui-tooling-preview", "androidx-activity-compose"]
test-base = ["junit"]
android-test-base = ["androidx-test-ext-junit", "androidx-test-espresso-core"]
android-test-compose = ["androidx-compose-ui-test-junit4"]
debug-compose = ["androidx-compose-ui-tooling"]

直接 androidx-core-ktx = "androidx.core:core-ktx:1.7.0" のように定義したり,
共通のバージョンを使うときは androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" } のように
[versions] で定義したものを参照して書くことができます.
(ちなみに後者は TOML の Inline Table なので 1 行で書かなければいけないようです)

最後の [bundles][libraries] で定義したライブラリを
任意のグループとして名前をつけてまとめることができるので便利です.

こうすれば複数のモジュールで共通定義の依存を記述することができます
(できていれば libs. あたりで補完が出てきてくれます):

app/build.gradle.kts
dependencies {
    versionCatalogs {
        implementation(libs.bundles.androidx.base)
        implementation(libs.bundles.androidx.compose)
        testImplementation(libs.bundles.testing.base)
        testImplementation(libs.bundles.testing.androidx.compose)
        debugImplementation(libs.bundles.debug.androidx.compose)
    }
}

[bundles] に定義した依存がそのまま 1 つのエントリのように記述できるので便利ですね.

最後に

いろいろ紹介したのですが,
IDE の対応が十分ではないなどデメリットもあるということで,
プロジェクトにあったものを選択できるとよいですね.
独断と偏見では KTS + buildSrc で依存管理というプロジェクトが最近は多いのではないでしょうか.
(データはありません)

そのうち Android Studio のスケルトンプロジェクトが
ナウい感じを示してくれると勝手に期待しています.

17
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
5