Kotlin Symbol Processing(KSP)使用初体验

在这里插入图片描述
近日,android官方发布了Kotlin Symbol Processing(KSP)的alpha版本。
Announcing Kotlin Symbol Processing (KSP) Alpha


为什么使用KSP?


很多人在使用Kotlin时的痛点之一就是编译速度过慢。
很多常见的三方库都通过注解简化模板代码,例如Room、Dagger、Retrofit等,
Kotlin使用KAPT处理注解,KAPT没有专门的注解处理器,需要借助APT实现的,因为APT只能处理Java,所以KAPT需要生成APT可以解析的stub(Java代码),这影响了KAPT的性能,从而拖慢了Kotlin项目整体编译速度:
在这里插入图片描述

KSP正是在这个背景下诞生的,它基于Kotlin Compiler Plugin实现,随着Kotlinc的过程同步处理注解,不需要生成stub代码,编译速度是KAPT的2倍以上


KSP 与 Kotlin Compiler Plugin


Kotlin提供了编译器插件Compiler Plugin,可以在编译期分析AST、修改字节码产物等,Kotlin很多语法关键字以及注解都是基于KotlinCompilerPlugin实现的,例如data class@Parcelizekotlin-android-extension 等。

理论上Kotlin Compiler Plugin可以完全替代APT、transform等编译期工具,且效率更高,但是KCP的API学习成本高,需要了解一些编译器底层知识,普通开发者很难直接基于KCP处理注解。

一个的Compiler Plugin的开发需要若干过程:

KSP 的出现了屏蔽了对KCP了解,可以像使用KAPT一样,更愉快地进行注解处理


KSP使用初体验


SymbolProcessor

一般需要继承SymbolProcessor来创建自己的KSP

interface SymbolProcessor {
    
    
    fun init(options: Map<String, String>,
             kotlinVersion: KotlinVersion,
             codeGenerator: CodeGenerator,
             logger: KSPLogger)
    fun process(resolver: Resolver) // Let's focus on this
    fun finish()
}

然后通过访问者模式,处理AST:

class HelloFunctionFinderProcessor : SymbolProcessor() {
    
    
    ...
    val functions = mutableListOf<String>()
    val visitor = FindFunctionsVisitor()

    override fun process(resolver: Resolver) {
    
    
        resolver.getAllFiles().map {
    
     it.accept(visitor, Unit) }
    }

    inner class FindFunctionsVisitor : KSVisitorVoid() {
    
    
        override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
    
    
            classDeclaration.getDeclaredFunctions().map {
    
     it.accept(this, Unit) }
        }

        override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
    
    
            functions.add(function)
        }

        override fun visitFile(file: KSFile, data: Unit) {
    
    
            file.declarations.map {
    
     it.accept(this, Unit) }
        }
    }
    ...
}

Samples

举几个例子展示一下KSP中的API是如何使用的

  • 访问类中的所有成员方法
fun KSClassDeclaration.getDeclaredFunctions(): List<KSFunctionDeclaration> {
    
    
    return this.declarations.filterIsInstance<KSFunctionDeclaration>()
}
  • 判断一个类或者方法是否是局部类或局部方法
fun KSDeclaration.isLocal(): Boolean {
    
    
    return this.parentDeclaration != null && this.parentDeclaration !is KSClassDeclaration
}
  • 判断一个类成员是否对其他Declaration可见
fun KSDeclaration.isVisibleFrom(other: KSDeclaration): Boolean {
    
    
    return when {
    
    
        // locals are limited to lexical scope
        this.isLocal() -> this.parentDeclaration == other
        // file visibility or member
        this.isPrivate() -> {
    
    
            this.parentDeclaration == other.parentDeclaration
                    || this.parentDeclaration == other
                    || (
                        this.parentDeclaration == null
                            && other.parentDeclaration == null
                            && this.containingFile == other.containingFile
                    )
        }
        this.isPublic() -> true
        this.isInternal() && other.containingFile != null && this.containingFile != null -> true
        else -> false
    }
}
  • 解析注解
// Find out suppressed names in a file annotation:
// @file:kotlin.Suppress("Example1", "Example2")
fun KSFile.suppressedNames(): List<String> {
    
    
    val ignoredNames = mutableListOf<String>()
    annotations.forEach {
    
    
        if (it.shortName.asString() == "Suppress" && it.annotationType.resolve()?.declaration?.qualifiedName?.asString() == "kotlin.Suppress") {
    
    
            it.arguments.forEach {
    
    
                (it.value as List<String>).forEach {
    
     ignoredNames.add(it) }
            }
        }
    }
    return ignoredNames
}

使用KSP替代KAPT


KSP的目标很明确:开发者可以用近似KAPT的API处理注解,得到2倍以上的性能提升;使用者可以方便的将KAPT替换为KSP:
在这里插入图片描述

目前,已有不少三方库被要求增加对KSP的支持,并提上日程,相信随着KSP版本的逐渐稳定,未来这个趋势会越发明显。

Library Status Tracking issue for KSP
Room In progress Link
Moshi Experimentally supported
Auto Factory Not yet supported Link
Dagger Not yet supported Link
Hilt Not yet supported Link
Glide Not yet supported Link

如果你的项目也有对KAPT的需求,不妨试试KSP?


KSP :https://github.com/google/ksp

猜你喜欢

转载自blog.csdn.net/vitaviva/article/details/113847098