Android -- kapt迁移至ksp

1,410 阅读3分钟

1. 常见注解处理器:apt、kapt、ksp

  • apt 全称是“Annotation Processing Tool”,是javac的一个工具,中文意思为编译时注解处理器。apt可以用来在编译时扫描和处理注解,提取相关信息,然后根据信息来自动的生成一些代码,省去了手动编写。

    详细可参考:编译时注解处理器(APT)详解

  • kapt aptjavac的一个工具,无法处理kotlin源码中的java注解。为了在kotlin源码中使用java注解,需要一个特殊的注解处理器,于是便有了kaptkapt先将kotlin源码编译成java源码,然后再使用apt处理注解。即kapt是基于apt的注解处理器。

    详细可参考:Android编译优化系列-kapt篇

  • ksp 全称是"Kotlin Symbol Processing",是Kotlin官方提供的用于生成代码的编译时注解处理器工具。用于替代kapt的工具,用于简化编译时代码生成的过程。可以理解成kotlin版本的apt

    详细可参考:Kotlin Symbol Processing API

  • 总结 截屏2023-10-08 11.32.31.png 上图描述了几个处理器的处理过程。目前kspkotlin官方推荐的注解处理器,相比kapt具备下面这些优点:
    • 编译效率更快 kapt处理时,需先把kotlin源码转换成java源码再处理注解。相比之下,ksp可以直接处理kotlin源码,省去中间的转换步骤,效率更高。
    • 跨平台 kapt依赖apt,即kapt仅适用于JVM平台。相比之下,ksp是基于kotlin的,而kotlin本身就是跨平台的,所以ksp也具备跨平台的能力。‘
    • 更多可以参考:Why KSP

2. kapt迁移至ksp

由于框架的要求等,迁移至ksp的前提是:AGP升级至8、kotlin升级至1.9。

基本的插件引入等,这里就不展开讨论了,详细可参考:Migrate from kapt to KSP

下面讨论主流框架升级时遇到的问题。

  • Dagger
    • 官方升级指南 传送门
    • 问题 Dagger目前仅做了部分ksp支持,有些注解还不支持。例如下面这个:
      kapt "com.google.dagger:dagger-android-processor:xxx"
      
      直接把上面依赖的kapt替换成ksp会导致报错,因为相关注解还不支持。
  • Room
    • 官方升级指南 传送门
    • 问题 Room支持导出数据库的架构,需要添加如下注解处理器选项:
android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += [
                    "room.schemaLocation":"$projectDir/schemas".toString(),
                    "room.incremental":"true"
                    ]
            }
        }
    }
}

Room切换到ksp后,需要将上述配置改成ksp版本的,如下所示。这部分在官方文档没有提到,我也是遇到崩溃后,经过一番折腾才知道的。

android {
    ...
    defaultConfig {
        ksp {  
            arg("room.schemaLocation", "$projectDir/schemas".toString())  
            arg("room.incremental", "true")
        }
    }
}

3. 总结

测试了几个项目中的常见场景

casekaptksp优化幅度
M1 + 增量debug安装(修改底层module)37s35s6%
M1 + clean + assembleDbeug4m50s4m24s9%
intel + clean + assembleRelease15m13m14%

几个场景下都会有收益,迁移也是比较简单的,值得一试。

4. 一些疑问

  • 同样使用了注解,为啥有的框架不需要通过 kapt "xxxxx"引入注解处理器呢?

    很多主流框架都使用了注解,注解可以辅助标记信息,使代码更加简单清晰,方便开发者使用框架。这些注解在不同阶段被使用,大致可以分成:编译阶段和运行阶段。

    编译阶段 比如GlideGlide利用注解处理器,在编译阶段生成模版代码,例如这个文件:/build/generated/ksp/allArchDebug/kotlin/com/bumptech/glide/GeneratedAppGlideModuleImpl.kt。在编译阶段处理注解,就需要引入相关的注解处理器,如:ksp "com.github.bumptech.glide:ksp:$glideVersion"

    运行阶段 比如RetrofitRetrofit则是在程序运行的时候,利用反射提取注解信息,然后动态构建代码。这种就不需要引入相关的注解处理器。

  • annotationProcessor、kapt、ksp的区别

    我们可以通过annotationProcessor "xx"kapt "xx"ksp "xx"等方式引入注解处理器。

    当模块中只包含java代码时,我们可以使用annotationProcessor "xx";当模块中同时包含javakotlin代码时,我们需要使用kapt "xx"ksp "xx"kaptksp会兼容kotlinjava代码。