10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Gradle Kotlin DSL (build.gradle.kts) で構造体っぽい定数定義をしたい

Posted at

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ファイルを突っ込みます。

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

定数クラスを作るだけの場合は不要だと思いますが、buildSrc内でkotlinの拡張関数とかを使いたい場合は、kotlinプラグインやstdlibも組み込みます。

あとは、buildSrc/src/main/java 以下に適当にパッケージをつくり、クラスを作成します。
パッケージ名やクラス名は何でも良いですが、Gradleスクリプトの中で現れる名前は避けましょう。
私は散々悩んだあげく、buildというパッケージの下に、ProjectPropertiesというクラスを作りました。

ProjectProperties.kt
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安全で型安全に使えます。

build.gradle.kts
group = ProjectProperties.groupId
version = ProjectProperties.versionName

以上です。

10
7
0

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
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?