Re:ゼロから始めるbuild.gradle.kts生活

# はじめに
タイトルにあるように `build.gradle.kts`をAndroidアプリ開発で使っていこうと思います．
また，マルチモジュールでプロジェクトを運用する際に同じような記述を共通化させる部分の紹介もしたいと思います．

最初，Android StudioでNew Projectすると `build.gradle`というGroovyで記述されたスクリプトファイルが生成されます．
Groovyはあまり聞き慣れませんが，Javaから派生した動的型付けのプログラミング言語です．

`build.gradle`でGroovyを使う際のイマイチな点として以下のものが挙げられると思います．
- 普段はJavaやKollinで開発するのに `build.gradle`だけGroovyで書かなければいけないく，JavaやKotlinで得た知見を`build.gradle`に活かせない
- 補完が効かない

大きくこの2つかなと個人的な見解として思っています．
DroidKaigi2019の[セッション](https://droidkaigi.jp/2019/timetable/70863/)でも紹介されていました．

これを解決するために`build.gradle`をKotlinで記述してAndroidアプリ開発をしようというときに出てくるのが`build.gradle.kts`です．今までGroovyで記述していた`build.gradle`をKotlinで記述することができるようになります．

ではやっていきましょう．

Re:ゼロから始めるbuild.gradle.kts生活


# やっていく
## Step1 
まずは，プロジェクト直下に`buildSrc`という名前でdirectoryを作ります．
その中に `build.gradle.kts`ファイル を作って以下の中身を書きます．

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

repositories {
    jcenter()
}
```
書いたらsync nowします
色々ファイルが生成されます

## Step2
次に `buildSrc/src/main/java/dependencies`となるようにpackageを作ります
`dependencies`の中に `Libs.kt`作ります．
この中にはプロジェクトで必要なライブラリの依存関係を記述します．
よく `Dep.kt`という名前で作りますが，今回は後々 `Dependencies.kt`というファイルを作るときに名前が被るので適当に `Libs.kt`という名前にしておきたいと思います．

`Libs.kt`の中身はこのように書いていきます．ここはDroidKaigi/conference-app-2020の[Dep.kt](https://github.com/DroidKaigi/conference-app-2020/blob/master/buildSrc/src/main/java/dependencies/Dep.kt)が参考になると思います．

```kotlin:Dep.kt
object Dep {
    object Kotlin {
        val stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61"
    }
}
```

## Step3
`buildSrc`の中の`build.gradle.kts`に追記

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

repositories {
    jcenter()
    google()  // 追記
}

dependencies {
    implementation("com.android.tools.build:gradle:4.0.1")  // 追記
}
```
`com.android.tools.build:gradle`のバージョンは適宜変えてください．

これを入れることでこのあとマルチモジュールした際の依存関係の共通化をするコードを書くことができるようになります．

## Step4

次にもともと`build.gradle`にあった `android`ブロックを共通化させるためのコードを書いていきます，
マルチモジュールでプロジェクトを作るとき，デフォルトではこの部分はすべてのモジュールで同じことを書かなければいけません．
そこで，`buildSrc/src/main/java/dependencies`の中に `BuildConfig.kt`というような名前でファイルを作成します．
中身は以下のように記述します．

```kotlin:BuildConfig.kt
package dependencies

import com.android.build.gradle.BaseExtension

object BuildConfig {
    const val applicationId = "com.example.app"
    const val versionCode = 1
    const val versionName = "1.0"
    const val androidTargetSdkVersion = 29
    const val androidCompileSdkVersion = 29
    const val androidMinSdkVersion = 23
    const val buildToolsVersion = "29.0.3"
    const val testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    const val consumerProguardFiles = "consumer-rules.pro"
}

fun BaseExtension.baseExtension() {
    compileSdkVersion(BuildConfig.androidCompileSdkVersion)
    buildToolsVersion(BuildConfig.buildToolsVersion)

    defaultConfig {
        minSdkVersion(BuildConfig.androidMinSdkVersion)
        targetSdkVersion(BuildConfig.androidTargetSdkVersion)
        versionCode = BuildConfig.versionCode
        versionName = BuildConfig.versionName

        testInstrumentationRunner = BuildConfig.testInstrumentationRunner
        consumerProguardFiles(BuildConfig.consumerProguardFiles)
    }

    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
} 
```

## Step5
実際に使ってみます
appにある `build.gradle`を `build.gradle.kts`にrenameします．
中身は以下のように書き換えます．
一番下の `dependencies`のブロックは今はおいておきます．

```kotlin:app/build.gradle.kts
plugins {
    id("com.android.application")
    id("kotlin-android")
    id("kotlin-android-extensions")
}
android {
    baseExtension()
    defaultConfig.applicationId = BuildConfig.applicationId
}
```

先程の `BuildConfig.kt`で `baseExtension`という名前で定義したものが使えています．
このように実際に使う際は `android`ブロック内で `baseExtension()`と一行書くだけで冗長だったコードを共通化することができています．

## Step6
では次に`dependencies`ブロックについてです．いつも使いたいライブラリの依存関係を定義するところですね．
ここも例えば `features/home`と `features/settings`みたいなモジュールを作った際に使うライブラリの依存関係が同じようになることがよくあります．
その部分もある程度のベースとなる依存関係は共通化させるようにします．
`buildSrc/src/main/java/dependencies`に `Dependencies.kt`を作ります．
中身は以下のように書いてみます．

```kotlin:Dependencies.kt
fun Project.baseDependencies(additionalConfiguration: DependencyHandlerScope.() -> Unit) {
    dependencies {
        implementation(Libs.Kotlin.stdlib)
        implementation(Libs.AndroidX.appCompat)
        implementation(Libs.AndroidX.coreKtx)
        implementation(Libs.AndroidX.constraint)
    }
    dependencies(additionalConfiguration)
}

private fun DependencyHandler.implementation(depName: Any) {
    add("implementation", depName)
}
```

## Step7
では，先程作った `baseDependencies`を使ってみようと思います．
appの `build.gradle.kts`に `dependencies`を追加していきます．
中身を以下のようにします．

```kotlin:app/build.gradle.kts
import dependencies.baseExtension
import dependencies.BuildConfig

plugins {
    id("com.android.application")
    id("kotlin-android")
    id("kotlin-android-extensions")
}
android {
    baseExtension()
    defaultConfig.applicationId = BuildConfig.applicationId
}

baseDependencies {
}
```

いままで `dependencies`で書いて中に `implementation`を書いていましたが，どこでも使うようなベースになる依存関係はすべて `baseDependencies`だけでかけるようになりました．
もちろん `baseDependencies`の中でそのモジュール内でまた別に定義したい依存関係は `implementation`で適宜追加できます．

## おまけ
1つのライブラリを使いたいときにそれに関連する依存関係を複数まとめて書きたい場合があると思います．
そのときに， `Dependencies.kt`に以下のようなコードを追加してみます．

```kotlin:Dependencies.kt
fun DependencyHandler.groupie() {
    implementation(Libs.Groupie.groupie)
    implementation(Libs.Groupie.databinding)
}
```

そうすると，`build.gradle.kts`で今回だとGroupieで使いたい複数の依存関係を以下のように一行ですっきり書くことができるようになります．

```kotlin:app/build.gradle.kts
import dependencies.baseExtension
import dependencies.BuildConfig

plugins {
    id("com.android.application")
    id("kotlin-android")
    id("kotlin-android-extensions")
}
android {
    baseExtension()
    defaultConfig.applicationId = BuildConfig.applicationId
}

baseDependencies {
    groupie()
}
```

# さいごに
こんな感じで今まで冗長だった依存関係の記述をすっきり，共通化させてしかもKotlinで書くことができるようになります．
みなさんも良き `build.gradle.kts`生活を．

# 参考記事
- [【入門】Groovyとは？ いま大注目の言語の特徴から使い方を徹底解説](https://www.sejuku.net/blog/94700)
- [Groovyを知らない人のためのbuild.gradle読み書き入門](https://qiita.com/opengl-8080/items/a0bb31fb20cb6505188b)


- [build.gradle.ktsのandroidブロックをbuildSrcで共通化させてみる](https://inside.pixiv.blog/makun/6409)
- [DroidKaigi 2019 - build.gradle.kts に移行しよう / tnj [JA] YouTube](https://youtu.be/_s-0MbA5Gvw)
- [Multi-module Android project with Kotlin DSL for Gradle](https://medium.com/@madmuc/multi-module-android-project-with-kotlin-dsl-for-gradle-3b6509724f77)
- [Android: build.gradle.ktsのすゝめ](https://qiita.com/SorrowBlue/items/2a0d3866490af9cbb28b)
- [【Android】buildSrcを使ってライブラリの定義をまとめる](https://www.itcowork.co.jp/blog/?p=5357)
- [AndroidのGradleでKotlin DSLを使う](https://oldbigbuddha.dev/post/android-gradle-with-kotlin-dsl/)