🔬

【Android】KSPをPoCしてみた話

2023/06/18に公開

こんにちは、Androidエンジニアのぬまです。

最近読んで良かったなと思った漫画です。
https://shonenjumpplus.com/episode/4856001361331145833

今更感あるのですが、2021年リリースされたKSP(Kotlin Symbol Processing)というAndroidのライブラリの導入をPoCしてみた話をしていきます。

環境

Android Studio Electric Eel | 2022.1.1
Kotlin: 1.8.0
Gradle: 7.2.2

kaptって何?

Kotlin Annotation Processing Toolの略で、簡単にいうとDIツールのDaggerやDataBindingでを実装する際、Kotlin プロジェクトでもアノテーション(@)を使い自動コード生成ができるように利用されます。

kaptではJavaのスタブコードの自動生成に時間がかかります。

kaptは現在非推奨で、メンテナンスモードになっています。
https://kotlinlang.org/docs/kapt.html

kspって何?

kspはKotlin Symbol Processingの略で、kaptの代替として2021年に安定版が公開されました。
kaptからkspにするだけで、Javaの自動コード生成がなくなりビルド速度が2倍高速化できるようです。
にわかには信じがたいです。

VoicyのAndroidアプリではKaptを採用していて、kaptのコードジェネレートに50秒ほどかかっていました。
build速度解析はAndroid StudioのBuild > Build Analyzer > Tasks impacting build durationを選択します。
kaptGenerateStugほにゃららが該当するはず

公式の公表した内容をKSPに移行すると単純に25秒は短縮できることになり、実現できれば一回のビルドが25秒も短縮できれば、開発サイクルを素早く回すことに寄与できるということで、試してみます。

実装

  • Project直下のbuild.gradle
plugins {
+    id 'com.google.devtools.ksp' version '1.8.0-1.0.9' apply false
-    id 'kotlin-kapt'
}
  • appなどモジュール配下のbuild.gradle
plugins {
    id 'com.google.devtools.ksp'
}

kaptを使用するライブラリの除去

弊社プロジェクトではkaptを使っていたライブラリが以下の4つありました。
Kotlinの公式ドキュメントには2023年6月現在以下のうちGlideとRoomについてはサポートできているそうですが、Permission DispatcherやData Bindingについては記載がありませんでした。

  • Glide → supported🎉
  • Permission Dispatcher → Not supported as of June, 2023🥺
  • Room → supported🎉
  • DataBinding → Not supported as of June, 2023🥺

https://kotlinlang.org/docs/ksp-overview.html#supported-libraries

Permission Dispatcherについては、自動生成されたラッパークラスを使用できなくなるため以下のようにリファクタリングすることで移行できるようでした。

  • Permission Dispatcherのマイグレーション
    修正前
  override fun onViewReady(view: View) {
       // ....
       startLiveWithPermissionCheck()
       // ....
  }

  override fun onRequestPermissionsResult(
      requestCode: Int,
      permissions: Array<String>,
      grantResults: IntArray
  ) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    onRequestPermissionsResult(requestCode, grantResults)
  }

  @NeedsPermission(Manifest.permission.RECORD_AUDIO)
  fun startLive() {
       // ....
  }

修正後

  override fun onViewReady(view: View) {
       // ....
       requestPermission =
             registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
                        if (isGranted) {
                            // リクエスト許可時の処理
                            startLive()
                        } else {
                            // リクエスト拒否時の処理
                        }
                    }
       requestPermission.launch(Manifest.permission.RECORD_AUDIO)
       // ....
  }
  
  • DataBindingの除去
    DataBindingはViewBindingとともにVoicyアプリのほとんどのViewで採用していて、DataBindingのJetpackComposeに代替できれば先ほど記載したビルド時間の短縮が見込めそうですが、
    Recycler#Adapterクラス、BaseActivityなどの親クラスなど多岐に渡りほぼほぼフルリプレースになりUnitTestの書き換えや動作確認も合わせると超大な工数がかかるため、今回のData Binding移行は諦めることになりました。

JetpackComposeに置き換えていきながら徐々に移行の準備をしていけたらなと思います。

(build.gradleのDataBinding有効化の指定を削除すると、DataBindingライブラリが自動生成するBR.item 変数が参照できない)

  • Glide, Room, Permission Dispatcherの依存関係を修正
-    kapt "com.github.bumptech.glide:compiler:$rootProject.ext.glide_version"
+    ksp "com.github.bumptech.glide:ksp:$rootProject.ext.glide_version"

-    kapt "com.github.permissions-dispatcher:permissionsdispatcher-processor:$rootProject.ext.dispatcher_version"
+    ksp "com.github.permissions-dispatcher:permissionsdispatcher-processor:$rootProject.ext.dispatcher_version"

-    kapt "androidx.room:room-compiler:$rootProject.room_version"
+    ksp "androidx.room:room-compiler:$rootProject.room_version"

結果

今回はkaptからkspへの移行を検討したものの即時対応することができませんでした。ですが、kaptとkspは並行して利用可能なため、JetpackComposeへのリプレースと同様に徐々にData Bindingライブラリの排除などモジュールごと・ライブラリごとに行っていきます。

https://android-developers-jp.googleblog.com/2021/09/accelerated-kotlin-build-times-with.html

Voicyテックブログ

Discussion