当前位置: 首页 > news >正文

使用 Kotlin 实现 Android 自定义 Lint 检查规则的步骤指南

一、创建 Lint 规则模块

  1. 新建 Android 库模块
    在项目中创建新的 Java/Kotlin Library 模块(非Android模块),例如命名为 custom-lint

  2. 配置 build.gradle.kts

plugins {id("java-library")id("org.jetbrains.kotlin.jvm") version "1.8.20" // 使用最新Kotlin版本
}dependencies {compileOnly("com.android.tools.lint:lint-api:30.4.0") // 根据AGP版本调整compileOnly("com.android.tools.lint:lint-checks:30.4.0")compileOnly(kotlin("stdlib"))
}java {sourceCompatibility = JavaVersion.VERSION_11targetCompatibility = JavaVersion.VERSION_11
}

二、实现自定义规则

1. 创建 Detector 类
import com.android.tools.lint.detector.api.*class ToastDetector : Detector(), Detector.UastScanner {override fun getApplicableMethodNames(): List<String> = listOf("makeText")override fun visitMethodCall(context: JavaContext,node: UCallExpression,method: PsiMethod) {val evaluator = context.evaluatorif (evaluator.isMemberInClass(method, "android.widget.Toast")) {// 检查是否调用了 show()val parent = node.parentif (parent !is UExpressionList || parent.uastParent !is UCallExpression ||(parent.uastParent as? UCallExpression)?.methodName != "show") {context.report(issue = ISSUE,location = context.getLocation(node),message = "必须调用 show() 方法显示 Toast")}}}companion object {val ISSUE = Issue.create(id = "ToastShowMissing",briefDescription = "缺少 Toast.show() 调用",explanation = "检测到 Toast.makeText() 但没有调用 show() 方法",category = Category.CORRECTNESS,priority = 6,severity = Severity.ERROR,implementation = Implementation(ToastDetector::class.java,Scope.JAVA_FILE_SCOPE))}
}
2. 创建 Issue Registry
@Suppress("UnstableApiUsage")
class CustomIssueRegistry : IssueRegistry() {override val issues: List<Issue>get() = listOf(ToastDetector.ISSUE// 添加更多检测规则)override val api: Int = CURRENT_API // 当前使用 14
}

三、配置清单文件

  1. 在模块 src/main/resources/META-INF/ 下创建 services 目录
  2. 新建文件 com.android.tools.lint.client.api.IssueRegistry
  3. 文件内容:
com.example.lint.CustomIssueRegistry

四、集成到项目

  1. 在应用模块的 build.gradle 中添加:
dependencies {lintChecks project(':custom-lint')
}

五、测试规则

  1. 编写测试用例
class LintTest : LintDetectorTest() {override fun getDetector(): Detector = ToastDetector()fun testMissingShow() {val code = """import android.widget.Toast;import android.content.Context;class Example {void test(Context context) {Toast.makeText(context, "test", Toast.LENGTH_SHORT);}}""".trimIndent()lint().files(java(code),// 添加必要依赖的stub文件*kotlin("""package android.widget;public class Toast {public static Toast makeText(Context c, String s, int d) { return null; }public void show() {}}""").indented()).issues(ToastDetector.ISSUE).run().expect("""|src/Example.java:6: Error: 必须调用 show() 方法显示 Toast [ToastShowMissing]|        Toast.makeText(context, "test", Toast.LENGTH_SHORT);|        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|1 errors, 0 warnings""".trimMargin())}
}

六、发布规则(可选)

  1. 打包为 AAR/JAR
./gradlew :custom-lint:assemble
  1. 发布到 Maven 仓库:
// 在 custom-lint 的 build.gradle 中添加
publishing {publications {create<MavenPublication>("lint") {groupId = "com.example"artifactId = "custom-lint"version = "1.0.0"from(components["java"])}}
}

高级技巧

  1. 检测 XML 布局
class XmlDetector : ResourceXmlDetector() {override fun getApplicableAttributes(): Collection<String> = listOf("textSize")override fun visitAttribute(context: XmlContext, attribute: Attr) {if (attribute.value.endsWith("sp")) {context.report(ISSUE, attribute, context.getValueLocation(attribute),"建议使用 dp 代替 sp 作为尺寸单位")}}
}
  1. 快速修复支持
context.report(issue = ISSUE,location = context.getLocation(node),message = "问题描述",quickfixData = LintFix.create().replace().text("旧代码").with("新代码").build()
)

注意事项:

  1. 保持 Lint API 版本与 AGP 版本一致
  2. 使用 ./gradlew lint 进行测试
  3. 通过 lint.debug = true 启用调试日志
  4. 在 Android Studio 的 Preferences | Editor | Inspections 中启用自定义检查

通过以上步骤,您可以创建针对团队特定编码规范的自定义 Lint 规则,有效提升代码质量和一致性。

http://www.xdnf.cn/news/653689.html

相关文章:

  • Kotlin学习34-data数据类1
  • 【Java学习笔记】final关键字
  • 「Python教案」判断语句的使用
  • 《软件工程》第 13 章 - 软件维护
  • 密度矩阵重整化群——DMRG
  • 【GESP真题解析】第 9 集 GESP 二级 2023 年 9 月编程题 2:数字黑洞
  • 如何优化 Python 爬虫的速度
  • Python开发Excel批量写入工具:多文件独立配置与Tkinter界面设计
  • IP 网段
  • DeepSeek-V3-0526乍现
  • Vue2实现Office文档(docx、xlsx、pdf)在线预览
  • PDF电子发票数据提取至Excel
  • 【计算机网络】IP 协议深度解析:从基础到实战
  • LeetCode#第58题:最后一个单词的长度
  • Python网络编程深度解析
  • 游戏引擎学习第312天:跨实体手动排序
  • YOLOv1 详解:单阶段目标检测算法的里程碑
  • SAP ABAP VK11/VK12 创建销售物料价格(附源码)
  • 华润电力招聘认知能力测评及性格测评真题题库考什么?
  • ATPrompt方法:属性嵌入的文本提示学习
  • 饭卡管理系统(接口文档)
  • 对接 uniapp 通过中间层(JSBridge)集成零信任 原生androiid和ios SDK
  • 【iOS】 锁
  • 【iOS】 GCD小结
  • NTDS.dit 卷影副本提权笔记
  • sass,less是什么?为什么要使用他们?
  • [特殊字符]《Qt实战:基于QCustomPlot的装药燃面动态曲线绘制(附右键菜单/样式美化/完整源码)》
  • 华为云物联网应用接入对于API及接口调试的梳理
  • Java设计模式之责任链模式:从基础到高级的全面解析
  • Chrome 开发中的任务调度与线程模型实战指南