最近は Gradle の構成を Groovy ではなく KTS (一連の Gradle の Kotlin DSL) で書いたり
buildSrc
や Version Catalog に依存をまとめるのがナウそうですが,
Android Studio で作成した新規プロジェクトはシンプルな Groovy で記述されています.
Kotlin DSL などについて まったくわかっていないので (Groovy もだけど),
この機会に Empty Compose Activity
Project を題材にして,
最近の Gradle の構成や記述について調べようと思いました.
前編:
モジュール共通の定義
さて,前回の ext
の節で書いたように,KTS の移行とは関係はないのですが
最近ではマルチモジュールでも共通で参照できるように
依存するライブラリの記述をまとめておくやりかたがよく使われているようです.
(要出典)
ここで紹介するのは,
ひとつは buildSrc
に定義をまとめておいて参照するやりかた.
もうひとつは Gradle の Version Catalog として定義をまとめて参照するやりかたです.
buildSrc
buildSrc
というディレクトリをつくりまして,
ここにプロジェクトで共通の定数・処理を置くと,
いろんなモジュールで使えて便利だねということです.
つまり,ライブラリのバージョンであるとか,
そういった定数をまとめておくのがパターンになっているということです.
なので,今回はそのパターンで buildSrc
に定数を定義しましょう.
KotlinConf 2018 の公演でいうと,
26:55 〜 buildSrc
での管理について紹介されています:
buildSrc/build.gradle.kts
まず buildSrc
というディレクトリをつくります.
その中に build.gradle.kts
をまず置きます:
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}
同じく Kotlin DSL として記述できるようにしておきます.
ファイル作成後,リラックスして待っていると
.gradle
ディレクトリができていて,なにやら構成されたことがわかります:
バージョンを定義する
次に 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.kts
で import
して,
そのまま使うことができるわけです:
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}")
// 以下略…
}
依存ライブラリを定義する
さらに,ライブラリの定義ごと定数としてまとめることを考えます:
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
はこのように書けることになります:
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 を有効にします:
enableFeaturePreview("VERSION_CATALOGS")
次に,gradle/libs.versions.toml
に Compose のバージョンを定義してみます:
[versions]
compose = "1.0.1"
こうすれば Gradle 側で libs.*
として参照できるので,
複数のモジュールで共通定義のバージョンを記述することができます:
android {
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose.get()
}
}
libs.versions.compose
は org.gradle.api.provider.Provider<String>
が返ってくるので,
get()
で String
として取り出せば使うことができます.
さらに依存ライブラリの定義を追加していきます.
今回は例としてこういうかたちにしてみました (どういう構成にするかは自由です):
[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.
あたりで補完が出てきてくれます):
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 のスケルトンプロジェクトが
ナウい感じを示してくれると勝手に期待しています.