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

656 阅读2分钟

上节详细介绍了java版本的自定义注解处理器步骤, kotlin 版本这里只把内容和注意事项给列出

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 代码

package com.example.annotationprocess.customapt

import com.example.annotation.APTAnnotation
import com.google.auto.service.AutoService
import java.io.IOException
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.RoundEnvironment
import javax.annotation.processing.SupportedAnnotationTypes
import javax.annotation.processing.SupportedSourceVersion
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.TypeElement
import javax.tools.Diagnostic

@SupportedAnnotationTypes("com.example.annotation.APTAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@AutoService(javax.annotation.processing.Processor::class)
class APTAnnotationProcessor : AbstractProcessor() {

    override fun process(annotations: Set<TypeElement>?, roundEnv: RoundEnvironment): Boolean {
        if (annotations.isNullOrEmpty()) return false

        for (element in roundEnv.getElementsAnnotatedWith(APTAnnotation::class.java)) {
            val annotation = element.getAnnotation(APTAnnotation::class.java)
            val value = annotation.value

            processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, "Processing ${element.simpleName} with value $value")

            // 在这里生成代码或执行其他操作
            generateClass(element, value)
        }
        return true
    }

    private fun generateClass(element: Element, value: String) {
        // 实现代码生成逻辑,例如生成一个Java类
        // 使用Filer创建文件并写入内容
        // 获取注解
        val annotation = element.getAnnotation(APTAnnotation::class.java)
        val className = element.simpleName.toString() + "Generated"
        val packageName = processingEnv.elementUtils.getPackageOf(element).toString()

        // 生成类内容
        val content = """package $packageName;

public class $className {
    public static void print() {
        System.out.println("${annotation.value}");
    }
}"""

        try {
            // 创建Java源文件
            val fileObject = processingEnv.filer.createSourceFile("$packageName.$className")
            val writer = fileObject.openWriter()
            writer.write(content)
            writer.close()
        } catch (e: IOException) {
            println("生成异常: " + e.message)
            e.printStackTrace()
        }
    }
}

2.3 Kotlin DSl 配置

注意这里面需要启用 kapt

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


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


}


dependencies {
    implementation(project(":annotation"))

    implementation("javax.annotation:javax.annotation-api:1.3.2")

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




}

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

3.1 结构

image.png

3.2 代码

3.2.1 使用注解


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

3.2.2 编译

  • kapt是Kotlin时代的产物,会检索kotlin/java代码,但kotlin的一些专有属性拿不到,如const关键字、伴生对象等在代码层面无法判断,同样的,没有用到注解时,不会工作;生成的代码在build/generated/source/kapt目录下

image.png

3.2.3 调用编译结果

package com.example.kotlin.other.annotation


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

}

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


}

3.3 Kotlin DSl 配置

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    id("kotlin-kapt")

}

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"))
    kapt (project(":annotation_process"))
}

3.4 运行结果

image.png