Androidなどのプロジェクトでプロジェクト全体の定数を定義するときに、以下のような構造体っぽい定義を使っていました。
buildscript {
def versionMajor = 1
def versionMinor = 0
def versionPatch = 0
ext {
pj = [
versions : [
name: "${versionMajor}.${versionMinor}.${versionPatch}",
code: versionMajor * 10000 + versionMinor * 100 + versionPatch
],
groupId : "com.example",
siteUrl : "https://github.com/example/example",
githubUrl : "https://github.com/example/example",
scmConnection: "scm:git:https://github.com/example/example.git"
]
}
}
これをKTSに移植しようと思ったけど、やり方が分からず右往左往しました。
結論から言うと、等価な定義をすることはできるが、Null安全でも型安全でもなく、補完も効かないものなので、
buildSrcに定数クラスを作った方が良いということになります。
ktsに置けるextと等価な記述
gradleではext以下に定義しておくと、配下のモジュールから読み出せるグローバル変数のように扱えました。
これをKTSでやるには、by extraを使って定義します。
kotlinを導入したときに必ずついてくる、kotlin_version
では
定義
val kotlin_version: String by extra("1.3.72")
利用
val kotlin_version: String by project
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
のように使います。Groovy DSLでは利用側は暗黙的に使えましたが、kotlinでは宣言が必要なのでちょっと不便ですね。
構造体はMap
冒頭にだした、構造体っぽい定義の実態はMapです。
同様の定義をするなら以下のように書きます。
val pj: Map<String, Any> by extra { mapOf(
"versions" to mapOf(
"name" to "${versionMajor}.${versionMinor}.${versionPatch}",
"code" to versionMajor * 10000 + versionMinor * 100 + versionPatch
),
"groupId" to "com.example",
"siteUrl" to "https://github.com/example/example",
"githubUrl" to "https://github.com/example/example",
"scmConnection" to "scm:git:https://github.com/example/example.git"
)}
利用箇所では以下のように使います。
val pj: Map<String, Any> by project
groupId = pj["groupId"] as String
正直言うと微妙すぎますね。
Mapなのでgetの戻り値はNullableだし、Valueの型も統一しなければAnyになるし、keyはStringだしで、Null安全でも、型安全でもなく、補完も効きません。
buildSrcを使おう
ということで、Groovy DSLのような定義をKTSで実装するのは諦めて、buildSrcを使って、定数クラスを作ってしまうのが良いと思います。
buildSrcを作るにはプロジェクト配下にbuildSrcディレクトリを作り、以下のような内容のbuild.gradle.ktsファイルを突っ込みます。
plugins {
`kotlin-dsl`
}
定数クラスを作るだけの場合は不要だと思いますが、buildSrc内でkotlinの拡張関数とかを使いたい場合は、kotlinプラグインやstdlibも組み込みます。
あとは、buildSrc/src/main/java
以下に適当にパッケージをつくり、クラスを作成します。
パッケージ名やクラス名は何でも良いですが、Gradleスクリプトの中で現れる名前は避けましょう。
私は散々悩んだあげく、buildというパッケージの下に、ProjectPropertiesというクラスを作りました。
package build
object ProjectProperties {
const val groupId: String = "com.example"
private const val versionMajor: Int = 1
private const val versionMinor: Int = 0
private const val versionPatch: Int = 0
const val versionName: String = "$versionMajor.$versionMinor.$versionPatch"
const val versionCode: Int = versionMajor * 10000 + versionMinor * 100 + versionPatch
object Url {
const val site: String = "https://github.com/example/example"
const val github: String = "https://github.com/example/example"
const val scm: String = "scm:git:https://github.com/example/example.git"
}
}
利用するときはimportの記述が必要ですが、自由に使えるようになります。
Null安全で型安全に使えます。
group = ProjectProperties.groupId
version = ProjectProperties.versionName
以上です。