build.gradle.ktsへの書き換えとハマリポイント part 2

[前回](https://qiita.com/chibatching/items/d63c0c9afc8e1e6bc9de)、途中で力尽きてしまったので続きです。

## Step 2 続き

Step 2のハマリポイントは記載しきったつもりだったのですが、1つ忘れていたのでそこからです。
コード全体は[前回のStep 2](https://qiita.com/chibatching/items/d63c0c9afc8e1e6bc9de#step-2---app%E3%83%AC%E3%83%99%E3%83%AB%E3%81%AEbuildgradle)を参照してください。

### ハマリポイント 3: Pluginのconfigurationが参照できない

このsampleでは[Ribbonizer plugin](https://github.com/maskarade/gradle-android-ribbonizer-plugin)を使用しています。
Groovy版ではこのように設定を書くことが出来ました。

```groovy:app/build.gradle
ribbonizer {
    builder { variant, iconFile ->
        if (variant.buildType.name == "debug") {
            return yellowRibbonFilter(variant, iconFile)
        } else {
            return grayRibbonFilter(variant, iconFile)
        }
    }
}
```

ぱっと見、そのままKotlin化できそうな雰囲気を感じますが実際には`builder`が参照できずコンパイルエラーになります。
`ribbonizer`は参照できているのでコードジャンプして見てみます。

```kotlin:accessors.kt
/**
 * Configures the [ribbonizer][com.github.gfx.ribbonizer.plugin.RibbonizerExtension] project extension.
 *
 * `ribbonizer` is not accessible in a type safe way because:
 * - `com.github.gfx.ribbonizer.plugin.RibbonizerExtension` is not public
 */
fun Project.`ribbonizer`(configure: Any.() -> Unit): Unit =
    extensions.configure("ribbonizer", configure)
```

どうやら、plugins構文で指定されたプラグインへのアクセスはこの`accessors.kt`というファイルが生成されることで実現しているようです。
この拡張関数のコメントによると、configurationのインターフェースであるExtensionクラスがpublicではないときにtype safeなアクセスができないようです。
実際、`RibbonizerExtension`クラスはpublicではありませんでした。

このような場合どうするかというと、`withGroovyBuilder`ブロックを使って文字列指定でパラメータやメソッドに値を設定していくことになります。

```kotlin:build.gradle.kts
ribbonizer {
    withGroovyBuilder {
        "builder"(FilterBuilder { variant, iconFile ->
            return@FilterBuilder when (variant.buildType.name) {
                "debug" -> YellowRibbonBuilder().apply(variant, iconFile)
                else -> GrayRibbonBuilder().apply(variant, iconFile)
            }
        })
    }
}
```

このように書くことで`builder`メソッドに引数を渡すことができます。
また、groovyで`yellowRibbonFilter(variant, iconFile)`のようにしていた箇所も直接アクセス出来ないため`yellowRibbonFilter`の内部実装をコピペしています。

## Step 3 - plugin versionの共通化

pluginのバージョン指定をする際、変数やgradle.propertiesの値を使うことができない謎の制限があるため、Kotlin関連プラグインのような同じバージョンのものを複数指定するパターンで記述をまとめることができず更新時などに辛い感じになってしまいます。

```kotlin:app/build.gradle.kts
plugins {
    ...

    kotlin("android") version "1.2.0-rc-39"
    kotlin("android.extensions") version "1.2.0-rc-39"
    
    ...
}
```

これを一箇所まとめたい場合はまた`pluginManagement`で行うことになります。
今回はkotlinのバージョンはgradle.propertiesに記載することにします

```gradle.properties
kotlinVersion=1.2.0-rc-39
```

idを正規表現でKotlin関連プラグインが引っかかるように定義してuseVersionでバージョンを指定

```groovy:settings.gradle
resolutionStrategy {
    eachPlugin {
        switch (requested.id.id) {
            ...

            case ~/org\.jetbrains\.kotlin\..*/:
                useVersion("${kotlinVersion}")
                break
        }
    }
}
```

build.gradle側では、versionの指定を無くします

```kotlin:app/build.gradle.kts
plugins {
    ...

    kotlin("android")
    kotlin("android.extensions")
    
    ...
}
```

拡張プロパティの取得は`extra`というdelegated propertyで行えたのですが、プロジェクトのプロパティは同様に`project`というdelegated propertyで行えます。
（projectで取得できる型はAnyになるので適宜Stringなどにcastして使ってください）

```kotlin:app/build.gradle.kts
val kotlinVersion by project
```

## 参考資料

gradleのkotlin-dslリポジトリにはサンプルが多く用意されているのでまずはここを見てみるのがいいと思います
[gradle/kotlin\-dsl: Kotlin language support for Gradle build scripts](https://github.com/gradle/kotlin-dsl)

## おわりに

今回、build.gradleをkotlinに書き換えてみましたが正直なところ本格的に使うのは厳しいかなという感じです。
この記事では書きませんでしたが、一度スクリプトがコンパイルエラーになると補完がまともに効かなくなりコンパイルが通るようになるまで結局補完を使えないみたいな状況になりがちで想像していた快適さには程遠いものでした。
とはいえ、今後そのあたりも改善されていくと思うので期待しながら状況ウォッチしていきたいと思います。

今回の最終的なコードはここにあります
[chibatching/KtsSample](https://github.com/chibatching/KtsSample)
途中のstep毎にコミットしているので必要に応じてそちらも参照していただけると〜