Gradle学习-6 APT 实现一个路由跳转框架(APT、发布maven仓库)

  • Annotation 注解:注解是元数据,即描述数据的数据
  • APT(Annotation Processing Tool)注解处理器

APT工作原理
在这里插入图片描述

Demo介绍

APT项目地址
使用APT maven仓库地址

(1)项目配置

  • Gradle 8.2
  • AGP 8.2.0
  • Java jdk 17
  • Kotlin 1.9.0

(2)Demo介绍

  • 我们将自定义一个注解LeonDestination

MainActivity
在这里插入图片描述

TestActivity
在这里插入图片描述

  • 我们要实现通过 url 进行 activity 的跳转,如下通过url实现从MainActivity跳转至TestActivity
    在这里插入图片描述

1、实现注解模块

  • 在根目录下,新建一个 leon-ann 文件夹
  • 在leon-ann文件夹下新建一个build.gradle文件

build.gradle

//利用java插件、kotlin插件
apply plugin: 'java'
apply plugin: 'kotlin'

//源码兼容性 java jdk 17
java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}
  • 在根目录下的setting.gradle中加入leon-ann模块

setting.gradle

rootProject.name = "GradleApt"
include ':app'
include ':leon-ann'
  • 在leon-ann文件夹下新建一个src/main/java/com.leon.ann目录
  • 在com.leon.ann目录下新建一个Annotation类 LeonDestination
//限定作用于类
@Target(AnnotationTarget.CLASS)
//编译期可见
@Retention(AnnotationRetention.BINARY)

/**
 * @param url 路由
 * @param description 描述
 */
annotation class LeonDestination(
    val url: String,
    val description: String
)

2、实现注解处理器模块

  • 在根目录下,新建一个 leon-processor文件夹
  • 在leon-ann文件夹下新建一个build.gradle文件

build.gradle

//利用java插件、kotlin插件
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'


//源码兼容性 java jdk 17
java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}


dependencies{
    //依赖注解子工程
    implementation project(':leon-ann')

    //注册注解处理器
    implementation 'com.google.auto.service:auto-service:1.0-rc6'
    kapt 'com.google.auto.service:auto-service:1.0-rc6'

    //生成kotlin类
    implementation 'com.squareup:kotlinpoet:1.11.0'
}
  • 在根目录下的setting.gradle中加入leon-processor模块

setting.gradle

rootProject.name = "GradleApt"
include ':app'
include ':leon-ann'
include ':leon-processor'
  • 在leon-processor文件夹下新建一个src/main/java/com.leon.processor目录
  • 在com.leon.processor目录下新建一个类 LeonProcessor
//源码兼容性 java jdk 17
@SupportedSourceVersion(SourceVersion.RELEASE_17)
//自动生成注解处理器
@AutoService(Processor::class)
class LeonProcessor : AbstractProcessor() {

    //TAG
    companion object {
        const val TAG = "LeonProcessor"
    }


    //告诉编译器,当前注解处理器支持的注解类型 - LeonDestination
    override fun getSupportedAnnotationTypes(): MutableSet<String> {
        return Collections.singleton(
            LeonDestination::class.java.canonicalName
        )
    }


    /**
     * 编译器找到我们关心的注解后,会调用的方法
     *
     * @param set 编译器搜集到的注解信息
     * @param roundEnvironment 编译环境
     */
    override fun process(
        set: MutableSet<out TypeElement>?,
        roundEnvironment: RoundEnvironment?
    ): Boolean {

        roundEnvironment?.let { env ->
            if (env.processingOver()) {
                //编译结束了,就直接返回
                return false
            }


            log("LeonProcessor 开始了")

            //拿到所有标记了 @LeonDestination 注解的  类的信息
            val allLeonDestinationElements =
                env.getElementsAnnotatedWith(LeonDestination::class.java)

            allLeonDestinationElements?.let { elements ->
                log("使用LeonDestination注解的类,有${elements.size}个")

                if (elements.size > 0) {

                    //组装类信息
                    val stringBuffer = StringBuffer()
                    stringBuffer.append("val mapping = HashMap<String, String>()\n")

                    elements.forEach { element ->
                        val typeElement = element as TypeElement
                        //在当前类上,获取 @LeonDestination 信息
                        val leonDestination = typeElement.getAnnotation(LeonDestination::class.java)
                        leonDestination?.let { destination ->

                            //当前类的全名
                            val realPath = typeElement.qualifiedName.toString()

                            //当前类注解信息
                            val url = destination.url
                            val description = destination.description


                            log("realPath: $realPath")
                            log("url: $url")
                            log("description: $description")

                            stringBuffer.append("mapping[\"$url\"] = \"$realPath\"\n")
                        }
                    }

                    stringBuffer.append("return mapping\n")


                    //生成类到本地文件中
                    try {
                        val packageName = "com.leon.apt"
                        val className = "LeonDestinationMapping"
                        val fileBuilder = FileSpec.builder(packageName, className)
                        val classBuilder = TypeSpec.classBuilder(className)
                            .addType(
                                TypeSpec.companionObjectBuilder()
                                    .addFunction(
                                        FunSpec.builder("getMapping")
                                            .returns(
                                                Map::class.parameterizedBy(
                                                    String::class,
                                                    String::class
                                                )
                                            )
                                            .addStatement(stringBuffer.toString())
                                            .build()
                                    )
                                    .build()
                            )
                            .build()

                        fileBuilder.addType(classBuilder)

                        val kaptKotlinGeneratedDir = processingEnv.options["kapt.kotlin.generated"]
                        fileBuilder.build().writeTo(File(kaptKotlinGeneratedDir))

                    } catch (e: Exception) {
                        log("生成类失败:${e.message}")
                    }

                }

            }
        }


        log("LeonProcessor 结束了")
        return false
    }


    //输出日志信息
    private fun log(msg: String?) {
        msg?.let { m ->
            System.out.println("$TAG >>>>>> $m")
        }
    }
}
  • 在app目录下的build.gradle加入leon-ann、leon-processor依赖

在这里插入图片描述

    id "kotlin-kapt"
    implementation project(':leon-ann')
    kapt project(':leon-processor')
  • 在MainActivity上使用注解LeonDestination

在这里插入图片描述

  • 在命令行中执行以下命令
    注意,执行命令行时,先执行以下"gradle -v"、"java -version"命令,确保gradle是8.2,java jdk是17
//清理项目
./gradlew clean -q

//构建项目
./gradlew :app:assembleDebug

执行效果
在这里插入图片描述

在app/build目录下生成了类LeonDestinationMapping
在这里插入图片描述

3、发布maven仓库

  • 在根目录下的gradle.properties中,添加以下代码
LEON_MAVEN_PATH=../leon-maven
LEON_MAVEN_GROUP_ID=com.leon.apt
LEON_MAVEN_VERSION=1.0.0
  • 在leon-ann目录下新建gradle.properties
LEON_MAVEN_ARTIFACT_ID=leon-apt-ann
  • 在leon-processor目录下新建gradle.properties
LEON_MAVEN_ARTIFACT_ID=leon-apt-processor
  • 在根目录下新建 leon-maven-publish.gradle
//引用 maven 插件,用于发布
apply plugin: 'maven-publish'

//读取 rootProject 中的配置属性
Properties rootProjectProperties = new Properties()
rootProjectProperties.load(project.rootProject.file('gradle.properties').newDataInputStream())
def LEON_MAVEN_PATH = rootProjectProperties.getProperty("LEON_MAVEN_PATH")
def LEON_MAVEN_GROUP_ID = rootProjectProperties.getProperty("LEON_MAVEN_GROUP_ID")
def LEON_MAVEN_VERSION = rootProjectProperties.getProperty("LEON_MAVEN_VERSION")


//读取子工程中的配置属性
Properties projectProperties = new Properties()
projectProperties.load(project.file("gradle.properties").newDataInputStream())
def LEON_MAVEN_ARTIFACT_ID = projectProperties.getProperty("LEON_MAVEN_ARTIFACT_ID")


//输出日志
log("LEON_MAVEN_PATH: $LEON_MAVEN_PATH")
log("LEON_MAVEN_GROUP_ID: $LEON_MAVEN_GROUP_ID")
log("LEON_MAVEN_VERSION: $LEON_MAVEN_VERSION")
log("LEON_MAVEN_ARTIFACT_ID: $LEON_MAVEN_ARTIFACT_ID")


//发布信息填写
publishing {
    publications {
        mavenJava(MavenPublication) {
            //设置groupId,通常为当前插件的包名
            groupId = LEON_MAVEN_GROUP_ID
            //设置artifactId,作为当前插件名称
            artifactId = LEON_MAVEN_ARTIFACT_ID
            //设置插件版本号
            version = LEON_MAVEN_VERSION
            log("pom信息groupId: $groupId")
            log("pom信息artifactId: $artifactId")
            log("pom信息version: $version")
            // 指定要发布的组件,例如Java库或插件等
            from components.java
        }
    }

    repositories {
        maven {
            //设置发布路径为  工程根目录下的  leon-publish 文件夹
            url = uri(LEON_MAVEN_PATH)
        }
    }
}


//日志输出
def log(String msg) {
    println("maven发布 >>>>>> $msg")
}
  • 在leon-ann目录下的build.gradle引用 leon-maven-publish.gradle
apply from: rootProject.file("leon-maven-publish.gradle")
  • 执行命令
./gradlew clean -q
./gradlew :leon-ann:publish

执行结果
在这里插入图片描述
根目录下生成maven库
在这里插入图片描述

  • 在leon-processor目录下的build.gradle引用 leon-maven-publish.gradle
apply from: rootProject.file("leon-maven-publish.gradle")
  • 执行命令
./gradlew clean -q
./gradlew :leon-ann:publish

执行结果

在这里插入图片描述

根目录下生成maven库

在这里插入图片描述

4、在其他项目中引用maven仓库

  • 新建一个新的项目Application1
  • 在Application1的根目录下setting.gradle中引入leon-maven仓库

在这里插入图片描述

//引入leon-maven
maven {
    url uri("/Users/leon/AndroidStudioProjects/GradleLearn/apt/leon-maven")
}
  • 在app目录下build.gradle中引入leon-ann和leon-processor

在这里插入图片描述

    //groupId : artifactId : version
    implementation 'com.leon.apt:leon-apt-ann:1.0.0'
    kapt 'com.leon.apt:leon-apt-processor:1.0.0'
  • 在MainActivity和TestActivity中使用LeonDestination注解

在这里插入图片描述

在这里插入图片描述

  • 执行命令行
./gradlew clean -q
./gradlew :app:assembleDebug -q

执行效果
在这里插入图片描述

app/build目录下生成了类LeonDestinationMapping
在这里插入图片描述

  • 在MainActivity中实现跳转代码
import com.leon.ann.LeonDestination
import com.leon.apt.LeonDestinationMapping

@LeonDestination(
    url = "leon://page-main",
    description = "这是主页"
)
class MainActivity : AppCompatActivity() {
    private var mBtn: TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mBtn = findViewById<TextView?>(R.id.id_btn_skip).apply {
            setOnClickListener {
                //点击事件
                LeonDestinationMapping.getMapping()["leon://page-test"]?.let { des ->
                    //跳转
                    startActivity(Intent().apply {
                        setClassName(
                            packageName,
                            des
                        )
                    })
                }
            }
        }
    }
}
  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KillerNoBlood

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值