KSP 使用记录

45 阅读1分钟

注解

@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
annotation class BindView(val resId: String)

注解处理器

//需要注册,
class BindViewProcessorProvider : SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        environment.logger.warn("=== BindViewProcessorProvider 被调用,创建处理器实例 ===")
        return BindViewProcessor(environment)
    }
}


class BindViewProcessor(val environment: SymbolProcessorEnvironment) : SymbolProcessor {
    private val codeGenerator = environment.codeGenerator
    private val logger = environment.logger

    override fun process(resolver: Resolver): List<KSAnnotated> {
        logger.warn("BindViewProcessor")
        //获取注解
        val annotationFields = resolver.getSymbolsWithAnnotation("com.example.annotations.BindView")
            .filterIsInstance<KSPropertyDeclaration>()
        val fieldsByClass = annotationFields.groupBy { it.parent as KSClassDeclaration }
        fieldsByClass.forEach { (ksClass, fields) ->
            generateBinding(ksClass, fields)
        }
        return emptyList()
    }

    fun generateBinding(ksClass: KSClassDeclaration, fields: List<KSPropertyDeclaration>) {
        //获取类名和包名
        val packageName = ksClass.packageName.asString()
        val className = ksClass.simpleName.asString()
        val bindingClassName = "${className}_viewBinging"
        val bindings = fields.map {
            logger.warn("------${it.annotations.first().annotationType}")
            val fieldName = it.simpleName.asString()
            val viewId = it.annotations.filter { it.annotationType.toString() == "BindView" }
                .first().arguments.first().value as String
            logger.warn("viewId: $viewId")
            val fieldType =
                it.type.resolve().declaration.qualifiedName?.asString() ?: error("无法解析类型")
            Binding(fieldName, viewId, fieldType)
        }

        val code = """
                package $packageName
                class $bindingClassName{
                     companion object {
                        fun binding(activity:$className){
                              ${bindings.joinToString("\n") { "activity.${it.fieldName} = activity.findViewById(${it.viewId})  as ${it.fieldType}" }}
                        }
                     }
                }
        """.trimIndent()
        logger.warn("生成的代码:\n $code")
        codeGenerator.createNewFile(
            dependencies = Dependencies(false, ksClass.containingFile!!),
            packageName = packageName, fileName = bindingClassName, extensionName = "kt"
        ).bufferedWriter().use { it.write(code) }
        logger.warn("生成View绑定类: $packageName.$bindingClassName")
    }


    //创建一个辅助类,用于存储字段绑定信息
    private data class Binding(val fieldName: String, val viewId: String, val fieldType: String)
}

注册方式 main -> resources ->META-INF->Services->com.google.devtools.ksp.processing.SymbolProcessorProvider 文件内容:

com.example.annotation_processor.BindViewProcessorProvider

module processor的 gradle文件

// KSP 符号处理API(必须)
implementation("com.google.devtools.ksp:symbol-processing-api:1.9.0-1.0.13")
// 代码生成工具(可选,如JavaPoet)
implementation("com.squareup:javapoet:1.13.0")
implementation(project(":annotations"))

project 的 gradle文件

 plugins {
    id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
 }

App的gradle文件

dependencies {
    ksp(project(":annotation-processor"))
    implementation(project(":annotations"))

}