今年もARABAKI ROCK FEST.24楽しみです、mukaiyachiです。
AndroidアプリのビルドツールはGradleですが、これまでGroovyという言語でbuild.gradleやsetting.gradleといったスクリプトにビルド定義を記述していました。
しかし2023年にKotlin DSLで記述するbuild.gradle.ktsやsetting.gradle.ktsがデフォルトになりました。
現在はAndroid Studioで新規にプロジェクトを作成した際に合わせて作られるのもこれらとなっています。
Kotlin DSL が新規 Gradle ビルドのデフォルトに
すぐに現在の開発に影響するわけではないですが今後のことを考慮して、少し前にとあるプロジェクトのビルドスクリプトをGroovyからKotlin DSLに移行しました。
また合わせて以下の対応も行いました。
- gradleの依存関係とプラグインの管理をバージョンカタログに移行。(依存関係やプラグインが管理しやすくなる)
- アノテーション処理をサポートするツールをkaptからKSPに移行。(kaptは現在メンテナンスモードとなっていて非推奨・kaptよりビルド速度が向上する可能性あり)
今回はその内容について書いていきます。
対応は概ね下記のAndroidのドキュメントページを参考に行いました。
ビルド構成を Groovy から Kotlin に移行する
ビルドをバージョン カタログに移行する
kapt から KSP に移行する
目次
ビルドスクリプトの構文を変換
ビルド構成を Groovy から Kotlin に移行する – 構文を変換する
GroovyとKotlinの構文は異なる部分があるため、それらの違いを反映する必要があります。
以下は変換内容の例です。
メソッド呼び出しにかっこを追加
1 2 |
// 変更前 implementation 'com.sun.mail:android-mail:1.5.5' |
1 2 |
// 変更後 implementation("com.sun.mail:android-mail:1.5.5") |
代入呼び出しに「=」を追加
・例1
1 2 |
// 変更前 compileSdk 34 |
1 2 |
// 変更後 compileSdk = 34 |
・例2
1 2 |
// 変更前 buildConfig true |
1 2 |
// 変更後 buildConfig = true |
文字列を変換
1 2 |
// 変更前 buildConfigField 'Long', 'REPEAT_INTERVAL', '15L' |
1 2 |
// 変更後 buildConfigField("Long", "REPEAT_INTERVAL", "15L") |
ファイル拡張子を変更
・変更前
/app/build.gradle
/build.gradle
・変更後
/app/build.gradle.kts
/build.gradle.kts
defをvalまたはvarで置き換える
1 2 |
// 変更前 def work_version = "2.9.0" |
1 2 |
// 変更後 val workVersion = "2.9.0" |
BOOL値プロパティに接頭辞「is」を追加
1 2 |
// 変更前 minifyEnabled false |
1 2 |
// 変更後 isMinifyEnabled = false |
リストとマップを変換
1 2 |
// 変更前 implementation fileTree(include: ['*.jar'], dir: 'libs') |
1 2 |
// 変更後 implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs"))) |
buildscriptブロックからpluginsブロックに移行 & pluginsブロックを変換
(手順1〜6)
ビルド構成を Groovy から Kotlin に移行する – buildscript から plugins ブロックに移行する
(手順7)
ビルド構成を Groovy から Kotlin に移行する – plugins ブロックを変換する
対応は下記の手順で行います。
- プラグインIDを確認
- buildscript ブロックで宣言されているプラグインのリポジトリがまだある場合、代わりに settings.gradle ファイルに移動
- 最上位の build.gradle ファイルの plugin ブロックにプラグインを追加
- 最上位の build.gradle.kts ファイルから classpath エントリを削除
- モジュールレベルの build.gradle ファイルの plugins ブロックにプラグインを追加して適用
- モジュールレベルの build.gradle ファイルからプラグインの apply plugin 呼び出しを削除
- plugins ブロック内をKotlinの記述方法に変換
以下はこれらの手順実施前と実施後の記述になります。
変更前の記述
モジュールレベル(app配下) build.gradleでは、元々pluginsブロックを使っていたのでその箇所に変更はありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// トップレベル build.gradle buildscript { ext.kotlin_version = '1.9.0' ext.hilt_version = '2.48' repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:8.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" } } |
1 2 3 4 5 6 7 |
// モジュールレベル(app配下) build.gradle plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' id 'dagger.hilt.android.plugin' } |
変更後の記述
1 2 3 4 5 6 7 8 9 10 |
// トップレベル build.gradle plugins { val kotlinVersion = "1.9.0" val hiltVersion = "2.50" kotlin("android").version(kotlinVersion).apply(false) kotlin("kapt").version(kotlinVersion).apply(false) id("com.android.application").version("8.2.2").apply(false) id("com.google.dagger.hilt.android").version(hiltVersion).apply(false) } |
1 2 3 4 5 6 7 |
// モジュールレベル(app配下) build.gradle plugins { id("com.android.application") kotlin("android") kotlin("kapt") id("com.google.dagger.hilt.android") } |
1 2 3 4 5 6 7 |
// settings.gradle pluginManagement { repositories { google() mavenCentral() } } |
依存関係とプラグインの管理をバージョンカタログに移行
バージョンカタログファイルを作成する
まずはプロジェクト直下にある gradle フォルダにlibs.versions.tomlを作成して、下記の3つのセクションを追加します。
1 2 3 |
[versions] [libraries] [plugins] |
依存関係を移行
次にモジュールレベル(app配下) build.gradle.ktsにある依存関係を、[libraries]セクションに記述します。
例)
1 2 3 |
// build.gradle.kts implementation("com.google.dagger:hilt-android:${hiltVersion}") kapt("com.google.dagger:hilt-android-compiler:${hiltVersion}") |
1 2 3 |
// libs.versions.toml hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "2.50" } hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "2.50" } |
そして、バージョンについては[versions]セクションに記述し、[libraries]セクションで version.ref = “xxxxx” という形で呼び出せるようにします。
例)
1 2 3 4 5 6 |
[versions] hiltVersion = "2.50" [libraries] hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltVersion" } hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltVersion" } |
さらに libs.versions.toml で定義した名前により build.gradle.kts の依存関係を定義するようにします。
1 2 3 4 |
// 変更前 val hiltVersion = "2.50" implementation("com.google.dagger:hilt-android:${hiltVersion}") kapt("com.google.dagger:hilt-android-compiler:${hiltVersion}") |
1 2 3 |
// 変更後 implementation(libs.hilt.android) kapt(libs.hilt.android.compiler) |
プラグインを移行
同様の方法でプラグインを移行します。
依存関係は[libraries]セクションに定義しましたが、プラグインは[plugins]セクションに定義します。
バージョンは依存関係と同じ[versions]セクションに定義します。
1 2 3 4 5 6 7 8 9 10 |
// 変更前トップレベル build.gradle.kts plugins { val kotlinVersion = "1.9.0" val hiltVersion = "2.50" kotlin("android").version(kotlinVersion).apply(false) kotlin("kapt").version(kotlinVersion).apply(false) id("com.android.application").version("8.2.2").apply(false) id("com.google.dagger.hilt.android").version(hiltVersion).apply(false) } |
1 2 3 4 5 6 7 |
// 変更前モジュールレベル(app配下) build.gradle.kts plugins { id("com.android.application") kotlin("android") kotlin("kapt") id("com.google.dagger.hilt.android") } |
1 2 3 4 5 6 |
// libs.versions.toml [plugins] kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlinVersion" } android-application = { id = "com.android.application", version.ref = "gradlePluginVersion" } dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "hiltVersion" } |
そして libs.versions.toml で定義した名前によりプラグインを定義するようにします。
1 2 3 4 5 6 7 |
// 変更後トップレベル build.gradle.kts plugins { alias(libs.plugins.android.application).apply(false) alias(libs.plugins.kotlin.android).apply(false) alias(libs.plugins.kotlin.kapt).apply(false) alias(libs.plugins.dagger.hilt).apply(false) } |
1 2 3 4 5 6 7 |
// 変更後モジュールレベル(app配下) build.gradle.kts plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.kapt) alias(libs.plugins.dagger.hilt) } |
アノテーション処理をサポートするツールをkaptからKSPに移行
kapt(Kotlin Annotation Processor Tool)はKotlinのアノテーションプロセッサで、ソースコード内のアノテーションを見つけて、それにもとづいてコードを生成する役割を持ちます。
ただ、kaptは現在メンテナンスモードになっているため、できるだけKSPに移行することが推奨されています。
KSP(Kotlin Symbol Processing)はkaptに変わるもので、ビルドのパフォーマンス向上やメモリ効率の向上、高い柔軟性や拡張性が特徴とのことです。
ほとんどの場合プロジェクトのビルド構成を変更するだけで移行できます。
変更内容は以下のような形です。
※こちらはバージョンカタログ移行後の書き方になります。
※バージョンカタログ使用していない書き方は公式ドキュメントをご覧ください。
* トップレベル build.gradle.kts
1 2 3 |
// 変更前 plugins { alias(libs.plugins.kotlin.kapt).apply(false) |
1 2 3 |
// 変更後 plugins { alias(libs.plugins.kotlin.ksp).apply(false) |
* モジュールレベル(app配下) build.gradle.kts
1 2 3 |
// 変更前 plugins { alias(libs.plugins.kotlin.kapt) |
1 2 3 |
// 変更後 plugins { alias(libs.plugins.kotlin.ksp) |
* libs.versions.toml
1 2 3 |
// 変更前 [plugins] kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlinVersion" } |
1 2 3 4 5 6 |
// 変更後 [versions] kspVersion = "1.9.22-1.0.17" [plugins] kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "kspVersion" } |
1つ注意点として、もしプロジェクトで「Data Binding」を使用している場合「ViewBinding」に移行する作業も必要になります。
「Data Binding」はKSPではサポートしておらずkaptに依存した機能とのことです。
kapt から KSP に移行する – kapt プラグインを削除する
注: データ バインディングを使用しているモジュールでは、kapt も有効にする必要があるため、kapt を削除することはできません。
今回記事には書いていませんが、該当のプロジェクトではData Bindingを使用していたのでViewBindingへの移行も行いました。
ボリュームが大きくこの作業が一番大変だったかもしれません。
もし対応期間があまり取れないという場合はKSPへの移行は見送っても良いかもしれません。
その他
ドキュメントなどにあまり記載していないものなど。
Android アプリのプロダクトフレーバー(Product Flavors)を定義
1 2 3 4 5 6 7 |
// 変更前(モジュールレベル build.gradle) productFlavors { flavor1 { } flavor2 { } } |
1 2 3 4 5 6 7 |
// 変更後(モジュールレベル build.gradle.kts) productFlavors { create("flavor1") { } create("flavor2") { } } |
Android アプリのパッケージングに関する設定
1 2 3 4 5 6 |
// 変更前(モジュールレベル build.gradle) packagingOptions { resources { pickFirsts += ['META-INF/LICENSE.txt'] } } |
1 2 3 4 5 6 |
// 変更後(モジュールレベル build.gradle.kts) packaging { resources { pickFirsts += "META-INF/LICENSE.txt" } } |
ビルド時に生成されたファイルやアーティファクトを削除するためのタスク
1 2 3 4 |
// 変更前(トップレベル build.gradle) tasks.register('clean', Delete) { delete rootProject.buildDir } |
1 2 3 4 |
// 変更後(トップレベル build.gradle.kts) tasks.register<Delete>("clean") { delete(rootProject.buildDir) } |
libs.versions.tomlでライブラリのバージョンを指定して定義
1 2 |
#noinspection GradleDependency okhttp = { strictly = "3.12.12" } |
以上になります。
同じような対応を検討している方、対応中だけど困っている方がいましたら参考になれば幸いです。