Kotlin 2/KSP 2にアップグレードした時にやったこと

竜ヶ岳

2024年5月末にKotlin 2がリリースされましたね!Jetpack Composeもすでに対応していたので、私の進めているプロジェクトでも早速アップグレードをしてみました。対応したことと、参照したドキュメントを簡単にまとめます。

Jetpack Compose の kotlin repository 移動対応

Jetpack ComposeはKotlinのRepositoryで管理されるようになったので移行します。android-developers blogにあるように依存関係を追加するだけです。

android-developers.googleblog.com

// libs.versions.toml
[versions]
- kotlin = "1.9.0"
+ kotlin = "2.0.0"

[plugins]
+compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

-kotlin-ksp = { id = "com.google.devtools.ksp", version = "1.9.0-1.0.13" }
+kotlin-ksp = { id = "com.google.devtools.ksp", version = "2.0.0-1.0.21" }
// build.gradle.kts
plugins {
// 省略
+    alias(libs.plugins.compose.compiler) apply false
// 省略
}

// app/build.gradle.kts
plugins {
// 省略
+    alias(libs.plugins.compose.compiler)
// 省略
}

android {
 
-    composeOptions {
-       kotlinCompilerExtensionVersion = "1.5.1"
-   }

KSP + Hilt(Dagger)のエラーに対応する

上記設定をしてビルドしたところ、次のエラーが出力されました。

e: [ksp] InjectProcessingStep was unable to process 'appStateDataStore' because 'error.NonExistentClass' could not be resolved.

Dependency trace:
    => element (CLASS): com.covelline.xxx.xxx
    => element (FIELD): appStateDataStore
    => type (DECLARED field type): androidx.datastore.core.DataStore<error.NonExistentClass>
    => type (ERROR type argument): error.NonExistentClass

If type 'error.NonExistentClass' is a generated type, check above for compilation errors that may have prevented the type from being generated. Otherwise, ensure that type 'error.NonExistentClass' is on your classpath.

appStateDataStoreはProtocol Bufferで生成したDataStoreのことです。kspが自動生成したコードをHiltのProvidesでインスタンス化するときに、クラスの参照が取得できずビルドエラーとなっているようです。DaggerのIssueで同様の問題が報告されていました。

github.com

app/build.gradle.ktsに以下のコードを追記して対応しました。

androidComponents {
    onVariants(selector().all()) { variant ->
        afterEvaluate {
            val variantName = variant.name.capitalize()
            val proto = "generate${variantName}Proto"
            val ksp = "ksp${variantName}Kotlin"

            val protoTask = project.tasks.findByName(proto)
                    as? com.google.protobuf.gradle.GenerateProtoTask
            val kspTask = project.tasks.findByName(ksp)
                    as? org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool<*>
            kspTask?.run {
                protoTask?.let {
                    @Suppress("DEPRECATION")
                    setSource(it.outputSourceDirectorySet)
                }
            }
        }
    }
}

この問題は、AGPのアップデートで今後修正されるっぽいです。