Android-设计模式与项目架构-01-编译插桩技术- APT(编译期注解处理器)-kotlin+ksp版本

430 阅读2分钟

** kapt 目前逐渐被淘汰了,这节介绍 ksp 版本**

1 annotation模块

1.1 结构

image.png

1.2 代码

package com.example.annotation

//自定义注解
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class APTAnnotation(val value: String = "Default Value")  // 定义一个属性
//    val priority: Int = 1  // 定义一个优先级属性

1.3 Kotlin DSl 配置

plugins {
    alias(libs.plugins.jetbrains.kotlin.jvm)
    id("java-library")

}

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17


}



dependencies {

}

2 annotation-process模块

2.1 结构

image.png

2.2 代码

注意这里和之前的定义不太一样,这里的自定义注解处理器实现了SymbolProcessorProvider,生成逻辑是一致的,大家可以做对比,这个需要依赖另外一个库,同时开启 ksp

package com.example.annotationprocess.apt

import com.example.annotation.APTAnnotation
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.TypeSpec
import java.io.OutputStreamWriter
import javax.annotation.processing.Processor


//@AutoService(SymbolProcessorProvider::class)
class MyAnnotationProcessorProvider : SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        return MyAnnotationProcessor(environment.codeGenerator, environment.logger)
    }
}

class MyAnnotationProcessor(
    private val codeGenerator: CodeGenerator,
    private val logger: KSPLogger
) : SymbolProcessor {

    override fun process(resolver: Resolver): List<KSAnnotated> {
        val symbols = resolver.getSymbolsWithAnnotation(APTAnnotation::class.qualifiedName!!)
        symbols.filterIsInstance<KSClassDeclaration>().forEach { classDeclaration ->
            val className = "${classDeclaration.simpleName.asString()}Generated"
            val fileSpec = FileSpec.builder(
                packageName = classDeclaration.packageName.asString(),
                fileName = className
            ).addType(
                TypeSpec.classBuilder(className)
                    .addFunction(
                        FunSpec.builder("print")
                            .addStatement("println("Generated by MyAnnotationProcessor with value: ")")
                            .build()
                    )
                    .build()
            ).build()

            codeGenerator.createNewFile(
                dependencies = Dependencies.ALL_FILES,
                packageName = classDeclaration.packageName.asString(),
                fileName = className
            ).writer().use { writer ->
                fileSpec.writeTo(writer)
            }

            logger.info("Generated file for ${classDeclaration.simpleName.asString()}")
        }
        return emptyList()
    }
}

2.3 Kotlin DSL 配置

注意这里面不用 autoservice 注册的话不需要启用 ksp

plugins {
    alias(libs.plugins.jetbrains.kotlin.jvm)
//    id("java-library")
//    id("com.google.devtools.ksp") version "1.9.24-1.0.20"
}



java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17


}


dependencies {


    implementation(project(":annotation"))


    // 添加 kotlinpoet 依赖
    implementation("com.squareup:kotlinpoet:1.12.0")

    implementation ("com.google.devtools.ksp:symbol-processing-api:1.9.24-1.0.20")
//    ksp("com.google.devtools.ksp:symbol-processing-api:1.9.24-1.0.20")

//    implementation ("com.google.auto.service:auto-service:1.0.1")
//    ksp("com.google.auto.service:auto-service:1.0.1")




}

2.4 手动注册

这里面我用了 autoservice 一直报错,暂时无法解决 所以用了手动注册的方式,创建如下路径的文件

image.png

文件内容如下

com.example.annotationprocess.apt.MyAnnotationProcessorProvider

3 app模块 注意这里区别于之前 java 的版本,该 modle 为 application模块

3.1 结构

image.png

3.2 代码

3.2.1 使用注解

package com.example.kotlin.other.annotation

import com.example.annotation.APTAnnotation


//注解参数也必须是编译时常量。你遇到的“An annotation argument must be a compile-time constant”错误表示你试图将一个运行时计算的值作为注解参数
const val CONSTANT_VALUE = "Hello, custom APT!"
//以常量的形式这样调用注解,否则会报上面那个错误
@APTAnnotation(CONSTANT_VALUE)
class MyClass {
}

3.2.2 编译

注意:- ksp则是最新的注解处理器,编译速度号称是kapt的2倍有余,且完全弥补了kapt/annotationProcessor的缺陷,但纯Java项目用不了,必需要集成kotlin;生成的代码在build/generated/ksp目录下

image.png

3.2.3 调用编译结果

package com.example.kotlin.other.annotation


//测试注解处理器编译结果
class Test {

}

fun main() {
    MyClassGenerated().print()


}

3.3 Kotlin DSl 配置

import com.android.build.gradle.AppExtension

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    id("com.google.devtools.ksp") version "1.9.24-1.0.20"

}


//extensions.getByType<AppExtension>().apply {
//    applicationVariants.all {
//        addJavaSourceFoldersToModel(file("$buildDir/generated/ksp/$name/kotlin"))
//    }
//}

android {

    namespace = "com.example.kotlin"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.kotlin"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        vectorDrawables {
            useSupportLibrary = true
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = "17"
    }


    buildFeatures {
        viewBinding = true
    }



    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }


    packaging {
        resources {
//            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}


dependencies {

    //------------


    // 编译时注解
 
    implementation(project(":annotation"))
    ksp (project(":annotation_process"))
}

3.4 运行结果

image.png