第一步 创建一个工程以及两个module
创建app工程以及两个module,分别叫annotation以及processor。在annotation中仅完成目标注解的创建,在processor中主要处理识别出工程中的所有带有注解的方法或者类,并在编译过程中生成对应的文件。
第二步 处理annotation的module
1、依赖处理(也可以使用kotlin,本工程使用的是java)
plugins {
id 'java-library'
}
apply from: rootProject.file('publish.gradle')
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
2、注解处理
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface JavaHandlerAnnotation {
String methodName() default "";
}
第三步 处理processor的module
1、依赖处理
apply plugin: 'java-library'
apply plugin: 'kotlin'
sourceSets.main {
java.srcDirs("src/main/java")
}
dependencies {
implementation project(path: ':lib_annotation')
implementation ('com.squareup:javapoet:1.13.0')
implementation("com.squareup:kotlinpoet:1.12.0")
implementation("com.squareup:kotlinpoet-ksp:1.11.0")
implementation("com.squareup:kotlinpoet-metadata:1.11.0")
implementation("com.google.devtools.ksp:symbol-processing-api:1.7.20-1.0.6")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
需要引入annotation的module,加入javapoet、kotlinpote等依赖包
2、创建注解处理器
JavaHandlerKspProcessorProvider : SymbolProcessorProvider
提供注解处理器的provider,return的内容就是接下来创建的注解处理器
撰写注解处理器,举例说明
class JavaHandlerSymbolProcessor(
private val logger: KSPLogger,
private val codeGenerator: CodeGenerator,
options: Map<String, String>
) : SymbolProcessor {
private var init = false
@OptIn(KotlinPoetKspPreview::class)
override fun process(resolver: Resolver): List<KSAnnotated> {
logger.warn("------------JavaHandlerKspStart----------")
val symbol = resolver.getSymbolsWithAnnotation(JavaHandlerAnnotation::class.qualifiedName!!)
val elements = symbol.filterIsInstance<KSFunctionDeclaration>().toList()
if (init) {
return emptyList()
}
val list = mutableListOf<String>()
if (elements.isNotEmpty()) {
elements.forEach {
list.add(it.qualifiedName!!.getShortName())
}
// 生成方法信息
val companion = TypeSpec.companionObjectBuilder().addProperty(
PropertySpec.builder("methodList", String::class)
//初始化值
.initializer("%S", list.joinToString(separator = ","))
.addAnnotation(JvmStatic::class)
.build()
).build()
// 生成对应的类
val file =
FileSpec.builder(packageName, className)
.addType(
TypeSpec.classBuilder(
ClassName(
packageName,
className
)
//增加注释
).addKdoc("hhhhhhhhhhhhhhhhhhhhhhhhhhhh")
.addType(companion).build()
).build()
logger.warn("------------JavaHandlerKspStart list size:${list.size}----------")
init = true
file.writeTo(codeGenerator, true, emptyList())
}
logger.warn("------------JavaHandlerKspStart end----------")
return emptyList()
}
}
接下来对于生成文件的kotlinpote一些api解释:
类对象 说明
MethodSpec 代表一个构造函数或方法声明 TypeSpec 代表一个类,接口,或者枚举声明 FieldSpec 代表一个成员变量,一个字段声明 JavaFile 包含一个顶级类的Java文件 ParameterSpec 用来创建参数 AnnotationSpec 用来创建注解 ClassName 用来包装一个类 TypeName 类型,如在添加返回值类型是使用 TypeName.VOID
通配符: %S 字符串,如:%S, ”hello” %T 类、接口,如:%T, MainActivity
3、注册注解处理器 在此目录下创建自己的注解处理器 resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
com.vivo.space.jsdetect.JavaHandlerKspProcessorProvider
第四步 处理整个工程的依赖
1、首先是整个工程的build.gradle文件添加依赖
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:1.7.20-1.0.6"
2、app模块下的build.gradle文件
plugins {
id 'com.android.application'
id 'com.google.devtools.ksp'
id 'kotlin-android'
}
implementation project(path: ':lib_annotation')
implementation project(path: ':lib_processor')
ksp project(':lib_processor')
android.sourceSets.all { it.java.srcDir("build/generated/ksp/${it.name}/kotlin/") }
android.sourceSets是编译的apk中是否要加入此目录下生成的文件