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

news2024/9/22 21:23:17
  • 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
                        )
                    })
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python爬虫速成之路(2):爬天气情况

hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;绝命Coding-CSDN博客 &a…

到底哪些牌子的鼠标好?选择鼠标需要注意哪些问题?

鼠标的选择从外观材质、手感、配置到价格定位都不尽相同&#xff0c;消费者的选择也越来越多。一般在选择鼠标时&#xff0c;我们也会发现鼠标能够选择的品牌虽然众多&#xff0c;但是不同品牌下的鼠标在品质和款式上都是大不相同的&#xff0c;那么到底哪些牌子的鼠标好呢?我…

黑马头条微服务学习day01-环境搭建、SpringCloud微服务(注册发现、网关)

文章目录 项目介绍环境搭建项目背景业务功能技术栈说明 nacos服务器环境准备nacos安装 初始工程搭建环境准备主体结构 app登录需求分析表结构分析手动加密微服务搭建接口定义功能实现登录功能实现 Swagger使用app端网关nginx配置 项目介绍 环境搭建 项目背景 业务功能 技术栈说…

11计算机视觉—语义分割与转置卷积

目录 1.语义分割应用语义分割和实例分割2.语义分割数据集:Pascal VOC2012 语义分割数据集预处理数据:我们使用图像增广中的随机裁剪,裁剪输入图像和标签的相同区域。3.转置卷积 上采样填充、步幅和多通道填充步幅多通道转置卷积是一种卷积:重新排列输入和核转置卷积是一种卷…

高校寻物平台小程序的设计

失主账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;寻物启示管理&#xff0c;失物归还管理&#xff0c;失物认领管理&#xff0c;举报投诉管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;寻物启示&#xff0c;失物招领&#xff0c;公告信息&…

机器学习和人工智能在农业的应用——案例分析

作者主页: 知孤云出岫 目录 引言机器学习和人工智能在农业的应用1. 精准农业作物健康监测土壤分析 2. 作物产量预测3. 农业机器人自动化播种和收割智能灌溉 4. 农业市场分析价格预测需求预测 机器学习和人工智能带来的变革1. 提高生产效率2. 降低生产成本3. 提升作物产量和质量…

[笔试训练](二十七)109:旋转字符串110:合并k个已排序的链表111:滑雪

目录 109:旋转字符串 110:合并k个已排序的链表 111:滑雪 109:旋转字符串 题目链接:旋转字符串_牛客题霸_牛客网 (nowcoder.com) 题目: 题解: class Solution { public:bool solve(string A, string B) {int nA.size();if(n!B.size()) return false;for(int i0;i<n;i){…

32路串口服务器 应用领域

32路串口服务器在多个领域有着广泛的应用&#xff0c;以下是详细的应用实例&#xff1a; 一、工业自动化 在工业自动化领域&#xff0c;32路串口服务器发挥着举足轻重的作用。传统的工业设备往往采用串口通信方式&#xff0c;而串口服务器能够将这些设备接入网络&#xff0c;…

护网HW面试常问——组件中间件框架漏洞(包含流量特征)

apache&iis&nginx中间件解析漏洞 参考我之前的文章&#xff1a;护网HW面试—apache&iis&nginx中间件解析漏洞篇-CSDN博客 log4j2 漏洞原理&#xff1a; 该漏洞主要是由于日志在打印时当遇到${后&#xff0c;以:号作为分割&#xff0c;将表达式内容分割成两部…

C++基础入门(下)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 C基础入门(下) 收录于专栏【C语法基础】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1.函数重载 1.1.参数类…

【调试笔记-20240713-Windows-Tauri 多个HTML页面支持】

调试笔记-系列文章目录 调试笔记-20240713-Windows-Tauri 多个HTML页面支持 文章目录 调试笔记-系列文章目录调试笔记-20240713-Windows-Tauri 多个HTML页面支持 前言一、调试环境操作系统&#xff1a;Windows 10 专业版调试环境调试目标 二、调试步骤搜索相似问题 三、应用场…

哪些单位和系统需要做等保测评

在信息安全领域&#xff0c;等级保护&#xff08;简称“等保”&#xff09;测评是一项至关重要的工作&#xff0c;旨在确保信息系统的安全性与合规性。本文将详细阐述哪些单位、哪些系统必须进行等保二级或三级测评&#xff0c;并探讨等保测评对企业的重要性。 一、必须进行等保…

【第27章】MyBatis-Plus之Mybatis X 插件

文章目录 前言一、安装指南二、核心功能1.XML 映射跳转2.代码生成3. 重置模板 三、JPA 风格提示四、常见问题解答1. JPA 提示功能无法使用&#xff1f;2. 生成的表名与预期不符&#xff1f; 五、代码生成模板配置1. 默认模板2. 重置默认模板3. 自定义模板内容3.1 实体类信息3.2…

pico+unity3d运行测试方法

一. 发布并运行程序 这个就很简单&#xff0c;电脑和pico数据库连接、pico打开开发者模式、运行的时候选择设备pico 二. pico串流助手 1.需要先下载pico的软件 PICO Developer Center、并安装串流助手、这种方式的话&#xff0c;安装了向日葵的小伙伴可能有冲突、百度一下解…

计算机图形学入门28:相机、透镜和光场

1.前言 相机(Cameras)、透镜(Lenses)和光场(Light Fields)都是图形学中重要的组成部分。在之前的学习中&#xff0c;都是默认它们的存在&#xff0c;所以现在也需要单独拿出来学习下。 2.成像方法 计算机图形学有两种成像方法&#xff0c;即合成(Synthesis)和捕捉(Capture)。前…

java框架-struts2

文章目录 1. struts2访问流程&架构&介绍2. 搭建struts2框架3. strust.xml配置详解4. Action生命周期5. ActionContext内容6. 访问servletAPI方式7. jsp获得8. Action接收参数9. struts、hibernate的javassist-3.18.1-GA.jar包重复,删除版本低的.10. OGNL表达式10.1. OG…

Unity中一键生成具有身体感知的虚拟人物动作

在虚拟现实(VR)和增强现实(AR)的浪潮中&#xff0c;如何让虚拟人物的动作更加自然、真实&#xff0c;已经成为一个重要课题。AI4Animation项目&#xff0c;一个由 Sebastian Starke 主导的开源框架&#xff0c;为Unity开发者提供了强大的工具集&#xff0c;以实现这一目标。本文…

唐刘:当 SaaS 爱上 TiDB(一)- 行业挑战与 TiDB 的应对之道

导读 在 TiDB 8.1 发布后&#xff0c;TiDB 展现了强大的支持 SaaS 业务的能力&#xff0c;成为 SaaS 业务数据库的优先选择之一。 本文为“当 SaaS 爱上 TiDB”系列文章的第一篇&#xff0c;系列文章将从技术原理和真实用户体验两个角度深入探讨 TiDB 在 SaaS 业务中的表现&a…

idm站点抓取可以用来做什么 idm站点抓取能抓取本地网页吗 idm站点抓取怎么用 网络下载加速器

在下载工具众多且竞争激烈的市场中&#xff0c;Internet Download Manager&#xff08;简称IDM&#xff09;作为一款专业的下载加速软件&#xff0c;仍然能够赢得众多用户的青睐&#xff0c;这都要得益于它的强大的下载功能。我们在开始使用IDM的时候总是有很多疑问&#xff0c…

Mysql具体数据操作和表的约束(上)

表中数据的增删改查 插入数据(添加数据) 1.按指定字段插入数据:insert into <表名> (字段1,字段2,...) values (),(),.... 注意1:values后面的括号是指行数(几条记录),一个括号表示插入一条记录,多个括号以此类推 注意2:values后面括号内部插入的数据…