不止是“秘书”:从 APT 到 KSP,Android 编译时代码生成的演进之路

588 阅读3分钟

一句话总结:

APT 是 Java 时代的“代码秘书”,而在 Kotlin-First 的今天,KSP 才是那位更懂 Kotlin、速度更快的“智能助理”。选择 KSP,意味着选择更快的编译速度和更强的语言特性支持。


第一篇章:“古典时代”——APT 的权柄与枷锁

APT (Annotation Processing Tool) 是 Java 平台的基石之一,它赋予了我们在编译期动态生成代码的能力,从而催生了 ButterKnife, Dagger2, ARouter 等一代神器。

APT 的核心工作流(经典三部曲)

你的文章已经出色地总结了这一流程:

  1. 定义注解: 创建带有 @Retention(RetentionPolicy.CLASS) 的注解。
  2. 实现处理器: 继承 AbstractProcessor,在 process 方法中扫描注解,并使用 JavaPoet 等库生成 .java 文件。
  3. 注册处理器: 通过 META-INF/services 路径下的文件进行注册。

Kotlin 时代的“枷锁”——kapt

APT 的设计完全面向 Java。当我们在 Kotlin 项目中使用它时,必须借助一个名为 kapt (Kotlin Annotation Processing Tool) 的 Gradle 插件。kapt 的工作流暴露了 APT 的局限性:

Kotlin 源码 -> kapt 生成 Java 存根 -> APT 处理 Java 存根 -> 生成 .java 代码

这个**“生成存根”**的额外步骤,是导致编译速度缓慢的罪魁祸首。


第二篇章:“现代革命”——KSP (Kotlin Symbol Processing) 的崛起

为了彻底解决 kapt 的性能瓶颈,并提供一个真正面向 Kotlin 的 API,Google 推出了 KSP。

什么是 KSP?

KSP 是一个独立于 Kotlin 编译器的、可直接解析 Kotlin 源码的注解处理工具。

KSP 的革命性优势:

  1. 性能飞跃(快达 2 倍):

    KSP 的工作流更直接:

    Kotlin 源码 -> KSP 直接处理 -> 生成 .kotlin 或 .java 代码

    它砍掉了“生成 Java 存根”这一最耗时的步骤,直接带来了巨大的编译速度提升。

  2. Kotlin 语言的原生理解:

    KSP 能完全理解并访问 Kotlin 的语言特性,例如:

    • suspend 函数

    • 默认参数

    • 可空性 (?)

    • ......

      而 APT 只能看到这些特性被转换成 Java 后的“阉割版”,丢失了大量有用信息。

  3. 更简洁的 API:

    KSP 提供了更现代化、更符合 Kotlin 风格的 API (SymbolProcessorProvider, SymbolProcessor, Resolver),相比 APT 繁琐的 javax.lang.model API,学习和使用成本更低。

KSP 实践一瞥:

// KSP 的处理器接口
class MyProcessorProvider : SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        return MyProcessor(environment.codeGenerator)
    }
}

class MyProcessor(private val codeGenerator: CodeGenerator) : SymbolProcessor {
    override fun process(resolver: Resolver): List<KSAnnotated> {
        // API 更直观
        val symbols = resolver.getSymbolsWithAnnotation("com.example.MyAnnotation")
        
        // ... 处理 symbols 并通过 codeGenerator 生成代码 ...

        return emptyList() // 返回无法处理的 symbols
    }
}

第三章:2025 年的技术选型指南

对比维度APT (通过 kapt 用于 Kotlin)KSP
核心原理先将 Kotlin 生成 Java 存根,再用 Java 的工具处理直接解析 Kotlin 源码
编译性能慢,存在 kapt 带来的额外开销快(通常是 kapt 的 1.5 到 2 倍)
Kotlin 支持有限,只能看到 Java 视角的 Kotlin原生、完整地支持所有 Kotlin 语言特性
生态系统正在逐步被 KSP 取代主流库(Room, Dagger, Moshi, Hilt...)的首选
增量编译支持较弱,易被破坏设计上对增量编译更友好

你的决策清单:

  1. 如果你正在为一个 Kotlin-First 的项目开发一个新的注解处理器:

    • 答案是唯一的:使用 KSP。 没有任何理由再选择 kapt
  2. 如果你正在使用一个只提供 APT 支持的第三方库:

    • 被迫需要使用 kapt 插件来兼容它。此时,你需要意识到它可能成为你项目编译速度的瓶颈。可以向该库的作者提议,希望他们支持 KSP。
  3. 如果你正在维护一个纯 Java 的 Android 项目或库:

    • APT 仍然是标准的、正确的选择。 KSP 主要的优势体现在 Kotlin 生态中。

结论:

APT 是一项伟大而经典的技术,为 Java 生态的自动化代码生成立下了汗馬功勞。但在 Android 的新时代,KSP 已经从一个“备选项”成长为“默认的最优解”。理解 APT 是为了 appreciation 历史,而拥抱 KSP 则是为了 investment 未来。