GradleのVersion catalogでAndroidアプリのライブラリを管理する

oidy
MIXI DEVELOPERS
Published in
16 min readDec 23, 2021

KARASTAのAndroidエンジニアをしているoidyです。

マルチモジュール構成のAndroidアプリを開発する際、どのようにライブラリのバージョンを一元化するかが一つの課題になります。

依存関係をモジュール間で共有する手法として、GradleのextbuildSrcを使う方法がよく見られます。

この記事では、Gradle v7.0からfeature previewとして導入されているVersion catalogを使って依存関係を管理する方法を紹介します。

アプリのマルチモジュール化に関しては以前の投稿も是非ご覧ください。

従来の方法

extで管理する

プロジェクトのbuild.gradleextブロックで依存関係を管理する例を示します。

buildscript {
ext.versions = [
app : [
versionCode: 1,
versionName: "1.0.0"
],
android : [
compileSdk: 31,
targetSdk : 31,
minSdk : 21,
gradle : "7.0.0"
],
kotlin : [
gradle : "1.6.10",
coroutines: "1.5.2"
],
androidx: [
core : "1.7.0",
lifecycle: "2.4.0"
]
]
ext.libs = [
kotlin : [
coroutines: "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.kotlin.coroutines"
],
androidx: [
core: "androidx.core:core-ktx:$versions.androidx.core",
lifecycle: [
liveData : "androidx.lifecycle:lifecycle-livedata-ktx:$versions.androidx.lifecycle",
viewModel: "androidx.lifecycle:lifecycle-viewmodel-ktx:$versions.androidx.lifecycle"
]
]
]
ext.gradlePlugins = [
android: "com.android.tools.build:gradle:$versions.android.gradle",
kotlin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin.gradle"
]
repositories {
google()
mavenCentral()
}
dependencies {
classpath gradlePlugins.android
classpath gradlePlugins.kotlin
}
}

モジュールのbuild.gradleからは以下のように参照できます。

android {
compileSdk versions.android.compileSdk

defaultConfig {
minSdk versions.android.minSdk
targetSdk versions.android.targetSdk
versionCode versions.app.versionCode
versionName versions.app.versionName
}
}

dependencies {
implementation libs.kotlin.coroutines
implementation libs.androidx.core
implementation libs.androidx.lifecycle.liveData
implementation libs.androidx.lifecycle.viewModel
}

buildSrcで管理する

Gradle Kotlin DSLを導入しているプロジェクトではbuildSrcでライブラリを管理していることが多いと思います。

上記のextと同等の依存関係を定義するためのbuildSrcの記述を以下に示します。

object Versions {
object App {
const val versionCode = 1
const val versionName = "1.0.0"
}

object Android {
const val compileSdk = 31
const val targetSdk = 31
const val minSdk = 21
const val gradle = "7.0.0"
}

object Kotlin {
const val gradle = "1.6.10"
const val coroutines = "1.5.2"
}

object AndroidX {
const val core = "1.7.0"
const val lifecycle = "2.4.0"
}
}

object Libs {
object Kotlin {
const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.Kotlin.coroutines}"
}

object AndroidX {
const val core = "androidx.core:core-ktx:${Versions.AndroidX.core}"

object Lifecycle {
const val liveData = "androidx.lifecycle:lifecycle-livedata-ktx:${Versions.AndroidX.lifecycle}"
const val viewModel = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.AndroidX.lifecycle}"
}
}
}

object GradlePlugins {
const val android = "com.android.tools.build:gradle:${Versions.Android.gradle}"
const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.gradle}"
}

モジュールのbuild.gradleからは以下のように参照できます。

android {
compileSdk Versions.Android.compileSdk

defaultConfig {
minSdk Versions.Android.minSdk
targetSdk Versions.Android.targetSdk
versionCode Versions.App.versionCode
versionName Versions.App.versionName
}
}

dependencies {
implementation Libs.Kotlin.coroutines
implementation Libs.AndroidX.core
implementation Libs.AndroidX.Lifecycle.liveData
implementation Libs.AndroidX.Lifecycle.viewModel
}

Version catalogを使う

Version catalogは現時点(Gradle v7.3.2)でfeature previewです。
settings.gradleに以下の行を追加するとVersion catalogが使えるようになります。

enableFeaturePreview("VERSION_CATALOGS")

次に、プロジェクトのgradle/の下にlibs.versions.tomlという名前のファイルを置きます。
tomlファイルの内容は以下のようになります。

[versions]
app-versionCode = "1"
app-versionName = "1.0.0"

android-compileSdk = "31"
android-targetSdk = "31"
android-minSdk = "21"
android-gradle = "7.0.0"

kotlin = "1.6.10"
kotlin-coroutines = "1.5.2"

androidx-core = "1.7.0"
androidx-lifecycle = "2.4.0"

[libraries]
android-gradle = { module = "com.android.tools.build:gradle", version.ref = "android-gradle" }

kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlin-coroutines" }

androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-lifecycle-viewModel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
androidx-lifecycle-liveData = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" }

[versions]の下にバージョンを、[libraries]の下にライブラリを定義します。

モジュールのbuild.gradleからは以下のように参照できます。

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

defaultConfig {
minSdk libs.versions.android.minSdk.get().toInteger()
targetSdk libs.versions.android.targetSdk.get().toInteger()
versionCode libs.versions.app.versionCode.get().toInteger()
versionName libs.versions.app.versionName.get()
}
}

dependencies {
implementation libs.kotlin.coroutines
implementation libs.androidx.core
implementation libs.androidx.lifecycle.viewModel
implementation libs.androidx.lifecycle.liveData
}

Version catalogのバージョンにはStringしか定義できないため、compileSdkminSdkをVersion catalogから取得する場合はtoInteger()をする必要があります。

dependenciesブロックは前述のextを使った場合と全く同じように書けます。

複数のライブラリを1行にまとめる

「ライブラリAを使うときはライブラリBも必ず使う」といったケースがよくあります。
Androidアプリの開発においては

  • テストを書くときにRobolectricとMockitoを一緒に使う
  • Jetpack Composeを使うときにComposeのライブラリ群(material, ui-toolingなど)を一緒に使う

といった例が挙げられます。

Version catalogにはこのような複数のライブラリを1つのバンドルとしてまとめる機能があります。

バンドルを定義するには、tomlファイルに[bundles]セクションを追加します。
次の例では viewModelliveData をバンドル化しています。

[libraries]
androidx-lifecycle-viewModel = ...
androidx-lifecycle-liveData = ...
[bundles]
androidx-lifecycle = ["androidx-lifecycle-viewModel", "androidx-lifecycle-liveData"]

bundlesを参照するにはlibs.bundles.[名前]のようにします。

まとめる前dependencies {
implementation libs.androidx.lifecycle.viewModel
implementation libs.androidx.lifecycle.liveData
}
まとめた後dependencies {
implementation libs.bundles.androidx.lifecycle
}

Gradleプラグインを管理する

Android Studio Bumblebee以降では、プロジェクトを新規作成したときのbuild.gradleが少し変わりました。

repositoryの設定はbuild.gradleからsettings.gradle に移動し、Gradleプラグインはclasspathを記述する方法からpluginsブロックにIDとバージョンを指定する方法に変わっています。

plugins {
id "org.jetbrains.kotlin.android" version "1.6.10" apply false
id "com.android.application" version "7.0.0" apply false
id "com.android.library" version "7.0.0" apply false
}

このプラグインIDとバージョンをVersion catalogを使って管理するには、tomlファイルに[plugins]のセクションを追加します。

[versions]
kotlin = "1.6.10"
android-gradle = "7.0.0"
[plugins]
kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "android-gradle" }
android-library = { id = "com.android.library", version.ref = "android-gradle" }

これを参照するには alias(libs.plugins.[名前])のようにします。

plugins {
alias(libs.plugins.kotlin) apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
}

Androidアプリの開発で使われるGradleプラグインの多くはpluginsブロックでの記法に対応しています。

  • Kotlin Serialization
  • Google Services
  • Firebase Crashlytics
  • Navigation Safe Args
[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
google-services = { id = "com.google.gms.google-services", version.ref = "google-services" }
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebase-crashlytics" }
androidx-navigation = { id = "androidx.navigation.safeargs", version.ref = "androidx-navigation" }

Hiltは現時点では対応していませんが、このような方法をとればpluginsブロックに記述できます。

従来のclasspathを設定する方法でも問題なく動くので、プラグイン側の対応を待っても良いでしょう。

まとめ

Version catalogを導入するとプロジェクトで使うライブラリのバージョンを簡単に一元管理できます。

従来の方法と比較すると、buildSrcを使う方法よりも導入コストが低く、extを使う方法よりもGradle Kotlin DSLで扱いやすいといった利点があります。

バンドル化やプラグイン管理といったVersion catalogならではの便利な機能もあります。

現時点ではfeature previewですが、Gradleの標準的なライブラリの管理方法として今後広く使われていくと思われます。

参考

Sign up to discover human stories that deepen your understanding of the world.

--

--

Published in MIXI DEVELOPERS

株式会社MIXIに所属の開発者による技術知見や開発ノウハウ、カンファレンスレポートなど、開発に関する情報を共有するエンジニア・ブログです。

No responses yet

Write a response