Android Lint代码检查实践

1. 为啥用Lint

平时开发中我们在提mr的时候都会进行review,但有些问题通过人眼去看很难发现,比如Fragment必须有空参构造函数,因为在内存不足的时候Fragment恢复默认是通过反射调用空参构造函数重建Fragment、又或者直接使用了kt的扩展函数String#toInt,当服务端返回string不符合int的时候会发生NumberFormatException异常,这类问题在测试环境很难测出,review阶段也可能没注意到,直到线上出现crash才被发现。

那为了避免这一类问题,我们最开始是将发生过的问题都记录在checklist中,在review的时候着重去看,但靠人眼去看难免会有遗漏。那为了彻底杜绝checklist中的问题不在发生,有没有一种方法能在review之前进行自动扫描,将checklist中的问题都检查一遍呢,答案是有的,也就是今天要提到的Lint。

Lint功能强大,有诸多的优势:

  1. 功能强大,Lint支持Java和Kt源文件、class文件、资源文件、Gradle等文件的检查。

  2. 扩展性强,支持开发自定义Lint规则。

  3. 配套工具完善,Android Studio、Android Gradle插件原生支持Lint工具。

  4. Lint专为Android设计,原生提供了几百个实用的Android相关检查规则。

  5. 有Google官方的支持,会和Android开发工具一起升级完善。

为了避免各位提不起兴趣,这里先放几张效果图

可以在AS编码时实时提示

也可以将扫描结果以报告形式输出。

2. Lint Api简介

在开始前提一句,尽量不要用中文去搜Lint的资料,不然就会像我一样,3天demo才跑起来。因为网上搜的文章大部分都是几年前的,按照那样配置跑不起来。

2.1 Lint Api

言归正传先介绍下Lint相关类的作用

  • Issue:用来声明一个Lint规则。
  • Detector:用于检测并报告代码中的Issue,每个Issue都要指定Detector。
  • Scanner:用于扫描并发现代码中的Issue,每个Detector可以实现一到多个Scanner。
  • IssueRegistry:Lint规则加载的入口,提供要检查的Issue列表。

下面看个自定义规则,实现了Serializable接口的类,引用类型成员变量也必须要实现Serializable接口

class SerializableClassDetector : Detector(), Detector.UastScanner {
   

    companion object {
   
        private const val REPORT_MESSAGE = "该对象必须要实现Serializable接口,因为外部类实现了Serializable接口"
      private const val CLASS_SERIALIZABLE = "java.io.Serializable"
        val ISSUE = Issue.create(
            "SerializableClassCheck",
            REPORT_MESSAGE,
            REPORT_MESSAGE,
            Category.CORRECTNESS,
            10,
            Severity.ERROR,
            Implementation(SerializableClassDetector::class.java, Scope.JAVA_FILE_SCOPE)
        )
    }

    override fun applicableSuperClasses(): List<String>? {
   
        return listOf(CLASS_SERIALIZABLE)
    }

    override fun visitClass(context: JavaContext, declaration: UClass) {
   
        for (field in declaration.fields) {
   
            //字段是引用类型,并且可以拿到该class
            val psiClass = (field.type as? PsiClassType)?.resolve() ?: continue
            if (!context.evaluator.implementsInterface(psiClass, CLASS_SERIALIZABLE, true)) {
   
                context.report(ISSUE, context.getLocation(field.typeReference!!), REPORT_MESSAGE)
            }
        }
    }

}

然后在IssueRegister中注册

class CustomIssueRegistry : IssueRegistry() {
   

    override val issues: List<Issue>
        get() = listOf(
            SerializableClassDetector.ISSUE
        )

    override val api: Int
        get() = CURRENT_API
}

2.2 Lint Debug

看起来是比较简单的,坑的是api一点文档没有,基本所有api都要靠猜和试,所以掌握一手debug非常重要,好在Lint提供了测试框架com.android.tools.lint:lint:$lintVersion,这与java的单元测试非常像,我们只需继承LintDetectorTest重写对应方法即可进行debug,看个例子

class SerializableDetectorTest : LintDetectorTest() {
   
    override fun getDetector(): Detector {
   
        return SerializableClassDetector()
    }

    override fun getIssues(): MutableList<Issue> {
   
        return mutableListOf(SerializableClassDetector.ISSUE)
    }

    fun test() {
   
        lint()
            .files(
                kotlin("""
                    package com
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值