自定义lint一篇文章就够了

什么是Lint?

Lint 的代码扫描工具,可帮助你发现并更正代码结构质量的问题,而无需您实际执行应用,也不必编写测试用例。

Lint都能检测什么

  • Java
  • Kotlin
  • XML文件
  • 图标
  • ProGuard 配置文件

Lint 配置为抑制警告

默认情况下,运行 Lint 扫描时,Lint 工具会检查它支持的所有问题。你也可以限制 Lint 要检查的问题,并为这些问题分配严重级别。例如你可以禁止对与项目无关的特定问题进行 Lint 检查,也可以将 Lint 配置为以较低的严重级别报告非关键问题

1.lint.xml

可以通过lint.xml文件中的<issue>标签标记中设置严重级别属性来更改某个问题的严重级别或对该问题停用 Lint 检查


  <?xml version="1.0" encoding="UTF-8"?>
    <lint>
        <!-- 在项目中禁止检测 id为 IconMissingDensityFolder的问题-->
        <issue id="IconMissingDensityFolder" severity="ignore" />

        <!-- 也可以通过 ignore忽略指定id下的指定文件 -->
        <issue id="ObsoleteLayoutParam">
            <ignore path="res/layout/activation.xml" />
            <ignore path="res/layout-xlarge/activation.xml" />
        </issue>
        
        <!-- 将硬编码字符串(HardcodedText)的严重程度更改为"error" -->
        <issue id="HardcodedText" severity="error" />
    </lint>

severity是指定级别的问题,lint系统自带的检测很多的有自己的级别,我们可以通过lint.xml自定义修改问题的严重级别

severity严重级别从上往下

  • Fatal
  • Error
  • Warning
  • Informational
  • Ignore

2.Gradle 配置 Lint 选项

build.gradle 文件中的 lintOptions {}


  android {
    // 移除lint检查的error,可以避免由于编译条件太过严格而编译不过的问题
    lintOptions {
        // 如果为 true,则当lint发现错误时停止 gradle构建
        abortOnError false
        // 如果为 true,则只报告错误
        ignoreWarnings true
        // 不检查给定的问题id InvalidPackage: Package not included in Android
        disable 'InvalidPackage'
        // 不检查给定的问题id 资源类型错误
        disable "ResourceType"
        // 忽略因MissingTranslation导致Build Failed错误 "app_name"
        disable 'MissingTranslation'
        // 检查给定的问题 id 
        enable 'RtlHardcoded','RtlCompat', 'RtlEnabled' 
        // * 仅 * 检查给定的问题 id 
        check 'NewApi', 'InlinedApi'
        // 配置写入输出结果的位置;它可以是一个文件或 “stdout”(标准输出)
        textOutput 'stdout'
        // 如果为真,会生成一个XML报告,以给Jenkins之类的使用
        xmlReport false
        // 用于写入报告的文件(如果不指定,默认为lint-results.xml)
        xmlOutput file("lint-report.xml")
        // 如果为真,会生成一个HTML报告(包括问题的解释,存在此问题的源码,等等)
        htmlReport true
        // 写入报告的路径,它是可选的(默认为构建目录下的 lint-results.html )
        htmlOutput file("lint-report.html")
        // 设置为 true, 将使所有release 构建都以issus的严重性级别为fatal
        //(severity=false)的设置来运行lint
        // 并且,如果发现了致命(fatal)的问题,将会中止构建
        //(由上面提到的 abortOnError 控制)
        checkReleaseBuilds true
        // 设置给定问题的严重级别(severity)为fatal (这意味着他们将会
        // 在release构建的期间检查 (即使 lint 要检查的问题没有包含在代码中)
        fatal 'NewApi', 'InlineApi'
        // 设置给定问题的严重级别为error
        error 'Wakelock', 'TextViewEdits'
        // 设置给定问题的严重级别为warning
        warning 'ResourceAsColor'
        // 设置给定问题的严重级别(severity)为ignore (和不检查这个问题一样)
        ignore 'TypographyQuotes'
        // 如果为 true,则检查所有的问题,包括默认不检查问题
        checkAllWarnings true
        // 重置 lint 配置(使用默认的严重性等设置)。
        lintConfig file("default-lint.xml")
        // 设置为 true,则当有错误时会显示文件的全路径或绝对路径 (默认情况下为true)
        absolutePaths true
    }

}

Secoo的lint

首先我们采用了 build.gradle 文件中的 lintOptions {}的配置方式

因为项目中有十几个module组成,为每个module单独引用lintOptions{}是一件比较繁琐而且不利于维护的事情,当然如果特殊的module我们也可以单出处理,这也时选择使用gradle配置的原因之一


  //抽出公共的lint配置
  common_lint_build.gradle
  
  //在common_component_build.gradle中引入  common_lint_build.gradle
  apply from:"../common_lint_build.gradle"
  

注意:项目中有的module没有引入common_component_build.gradle的模块需要单独引入common_lint_build.gradle

自定义Detector

lint支持自定义Detector来对自定义ISSUE检测规则

自定义Detector需要继承自Detector并实现 Detector.UastScanner 接口,25.2.0及之前版本Detector.JavaPsiScanner已被弃用,UastScanner相比于JavaPsiScanner以及更老的JavaScanner,主要提供了对Kotlin支持,API更加简单,特点是成对存在(满足条件 -> visitor)此外可以lint-checks-version.jar中的各类型Detector源码可以学习其用法。

UastScanner包含13个回调方法,下面介绍常用的几个:

1.getApplicableUastTypes

此方法返回需要检查的AST节点的类型,类型匹配的UElement将会被createUastHandler(createJavaVisitor)创建的UElementHandler(Visitor)检查。

2.createUastHandler

创建一个UastHandler来检查需要检查的UElement,对应于getApplicableUastTypes

3.getApplicableMethodNames

返回你所需要检查的方法名称列表,或者返回null,相匹配的方法将通过visitMethod方法被检查

4.visitMethod

检查与getApplicableMethodNames相匹配的方法

5.getApplicableConstructorTypes

返回需要检查的构造函数类型列表,类型匹配的方法将通过visitConstructor被检查

6.visitConstructor

检查与getApplicableConstructorTypes相匹配的构造方法

7.getApplicableReferenceNames

返回需要检查的引用路径名,匹配的引用将通过visitReference被检查

8.visitReference

检查与getApplicableReferenceNames匹配的引用

9.appliesToResourceRefs

返回需要检查的资源引用,匹配的引用将通过visitResourceReference被检查

10.visitResourceReference

检查与appliesToResourceRefs匹配的资源引用

11.applicableSuperClasses

返回需要检查的父类名列表,此处需要类的全路径名

12.visitClass

检查applicableSuperClasses返回的类

ISSUE

ISSUE在每个Detector中定义,lint检查到相关项将ISSUE报告出来,示例:


    public static final Issue ISSUE = Issue.create(
            "LogUse",
            "避免使用Log/System.out.println",
            "使用LogUtils,防止在正式包打印log",
            Category.SECURITY, 5, Severity.ERROR,
            new Implementation(LogDetector.class, Scope.JAVA_FILE_SCOPE)
    );

id : 唯一值,应该能简短描述当前问题。利用Java注解或者XML属性进行屏蔽时,使用的就是这个id。
summary : 简短的总结,通常5-6个字符,描述问题而不是修复措施。
explanation : 完整的问题解释和修复建议。
category : 问题类别。详见下文详述部分。
priority : 优先级。1-10的数字,10为最重要/最严重。
severity : 严重级别:Fatal, Error, Warning, Informational, Ignore。
Implementation : 为Issue和Detector提供映射关系,Detector就是当前Detector。声明扫描检测的范围Scope,Scope用来描述Detector需要分析时需要考虑的文件集,包括:Resource文件或目录、Java文件、Class文件。

Lint提供检测的ISSUE查询文档

Category

Category表示lint结果在IDE中的分类,系统已有类别:

  • Lint
  • Correctness (incl. Messages)
  • Security
  • Performance
  • Usability (incl. Icons, Typography)
  • Accessibility
  • Internationalization
  • Bi-directional text

此外还可以自定义Category

自定义Category

自定义Category,示例:

public class MTCategory {
    public static final Category NAMING_CONVENTION = Category.create("命名规范", 101);
}

使用


public static final Issue ISSUE = Issue.create(
        "IntentExtraKey",
        "intent extra key 命名不规范",
        "请在接受此参数中的Activity中定义一个按照EXTRA_<name>格式命名的常量",
        MTCategory.NAMING_CONVENTION , 5, Severity.ERROR,
        new Implementation(IntentExtraKeyDetector.class, Scope.JAVA_FILE_SCOPE));
        
      

IssueRegistry

提供需要被检测的Issue列表(添加自定义Detector)示例:

 
public class SecooIssueRegistry extends IssueRegistry {

    @NotNull
    @Override
    public List<Issue> getIssues() {
        return Arrays.asList(
                LogDetector.ISSUE,
                ThreadDetector.ISSUE);
    }

    @Override
    public int getApi() {
        return ApiKt.CURRENT_API;
    }


    @Override
    public int getMinApi() { //兼容3.1  不兼容自定义lint一直l不检测 必须加上这个检测了
        return 1;
    }
}

Secoo的Lint module

为了方便项目扩展,自定义lint专门抽出一个module,以后扩展自定义的lint都可以在该模块下添加

        module-lint
       

具体的配置以及使用的方式在common_lint_build.gradle增加了对module-lint引用

        
    dependencies {
        lintChecks project(":module-lint")
    }

       

执行lint

因为项目包含一些编译变体,编译变体指的时buildTypes做的一些打包区分,所以不能直接执行lint

终端进入项目目录

全量debug 下执行:

./gradlew lintDebug

全量release 下执行:

./gradlew lintRelease

执行单一module的检测:

./gradlew 模块名:lintRelease
//示例
./gradlew  CommonSDK:lintDebug

(每天学习一点点.每天进步一点点,分享不宜路过点个赞呀)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352