Android Lint规则(包括翻译规则)和空指针检查研究

一、Android Lint

  • Lint简介

Android Lint 是有 Android SDK 提供的一种静态代码检测工具,用于检测 Android 的代码质量。Android Lint 的源码集成在 Android SDK Tools 16 及更高的版本中,我们可以在项目目录下通过 ./gradlew lint 命令调用,也可以通过 Android Studio 的 【Analyze】->【Inspect Code】路径调用 Lint 检查。
Lint 是 Android 提供的一个强大的,用于静态扫描应用源码并找出其中的潜在问题的实用工具。lint 工具可以检查你的 Android 项目源文件是否有潜在的错误,以及在正确性、安全性、性能、易用性、无障碍性和国际化方面是否需要优化改进。
Lint 既可以用作命令行工具,也可以与 Eclipse 和 IntelliJ 集成在一起。它被设计成独立于 IDE 的工具,我们可以在 Android Studio 中非常方便的使用它。

  • Lint的工作流

  • Lint的问题等级

Fatal严重致命的、Error错误、Warning警告、Information提示、Ignore忽略 不提示
实际测试Fatal、Error只是错误代码部分增加红色和下划线提示,不会报错和阻断编译。

  • Lint规则使用方法

1、配置Gralde,build.gradle 文件的android下增加lintOptions,下面列举 lintOptions 可定义的选项

android {
    lintOptions {
        // true--关闭lint报告的分析进度
        quiet true
        // true--错误发生后停止gradle构建
        abortOnError false
        // true--只报告error
        ignoreWarnings true
        // true--忽略有错误的文件的全/绝对路径(默认是true)
        //absolutePaths true
        // true--检查所有问题点,包含其他默认关闭项
        checkAllWarnings true
        // true--所有warning当做error
        warningsAsErrors true
        // 关闭指定问题检查
        disable 'TypographyFractions', 'TypographyQuotes'
        // 打开指定问题检查
        enable 'RtlHardcoded', 'RtlCompat', 'RtlEnabled'
        // 仅检查指定问题
        check 'NewApi', 'InlinedApi'
        // true--error输出文件不包含源码行号
        noLines true
        // true--显示错误的所有发生位置,不截取
        showAll true
        // 回退lint设置(默认规则)
        lintConfig file("default-lint.xml")
        // true--生成txt格式报告(默认false)
        textReport true
        // 重定向输出;可以是文件或'stdout'
        textOutput 'stdout'
        // true--生成XML格式报告
        xmlReport false
        // 指定xml报告文档(默认lint-results.xml)
        xmlOutput file("lint-report.xml")
        // true--生成HTML报告(带问题解释,源码位置,等)
        htmlReport true
        // html报告可选路径(构建器默认是lint-results.html )
        htmlOutput file("lint-report.html")
        //  true--所有正式版构建执行规则生成崩溃的lint检查,如果有崩溃问题将停止构建
        checkReleaseBuilds true
        // 在发布版本编译时检查(即使不包含lint目标),指定问题的规则生成崩溃
        fatal 'NewApi', 'InlineApi'
        // 指定问题的规则生成错误
        error 'Wakelock', 'TextViewEdits'
        // 指定问题的规则生成警告
        warning 'ResourceAsColor'
        // 忽略指定问题的规则(同关闭检查)
        ignore 'TypographyQuotes'
    }
}

2、指定规则

// 回退lint设置(默认规则)
lintConfig file("default-lint.xml")
default-lint.xml手动创建放在当前module目录
类似

这种可以单独写在xml中

3、执行Lint检测

分为三种:
第一种,常见的实时检测,AndroidStudio自带的,可以通过lintOption配置显示错误的等级。

测试 我把NewApi和InlineApi这种错误改成Fatal致命的,build同步一下

看代码

只会提示但不会阻挡编译和运行,Error的效果相同。

Warning和Infomational的效果一样,也是只会提示但不会阻挡编译和运行。

 

忽略检测

  

指定方法忽略

lint在实时检测只能发挥提示的作用,进一步查看lint规则,找到需要的规则。

下方有专门的规则列表

https://wiki.h3d.com.cn/pages/viewpage.action?pageId=86346982

针对空指针,手动写个报错代码

未赋值实时检测lint是有提示的。

手动赋值为null竟然不显示,下面会依次查找现有规则。

第二种,手动静态扫描 

第三种,Gradle命令

  1. ./gradlew lint
  2. ./gradlew app:lintDebug
  3. ./gradlew app:lintTiktokI18nDebug

 

这些命令,会执行gradle文件,应用lintOptions的配置,进行Lint检测,结果会放在配置中指定的xml或html中。

生成html报告中没有找到空指针相关的提示。

  • Lint规则

Lint规则

官方规则

Android Lint Checks - Android Studio Project Site

我翻译后的规则单独都放在了这里

https://wiki.h3d.com.cn/pages/viewpage.action?pageId=86346982lint规则包含一下几个分类

查找android官方lint库,没有找到类似空指针这种语法级别的规则。

二、Lint自定义规则

1、为什么需要自定义 Lint ?


    由于每个业务线自身的需求,Lint 默认的检查项目可能不能满足我们的需求。 比如司机端一个自定义控件需要抽成一个库给其他项目使用,但是我们希望使用者必须在 XML 中定义一个属性,否则组件无法正常运行,我们希望Lint能够对此进行检查,并在忘记添加此属性时给出明确的错误提示。
再比如,我们的基础组件有一个日志库,能够方便的在 release 版本中关闭日志输出,还能够把日志输出到指定的文件中方便事后分析,这时如果来了一个新同学,他可能还是习惯性的用 android.util.Log 来打印日志,我们希望能够检测到本项目中所有使用了 android.util.Log 的代码,并发出警告。 要满足这些自定义需求,我们就需要通过 Android Lint 的扩展机制自己定制 Lint 规则。

同时发现潜在的空指针未赋值等造成Crash的语法问题。

2、lint Api

如果要查看 lint 工具支持的 issue 的完整列表和它们所对应的 issue ID,可以使用 lint --list 命令。

Lint 中包括多种类型的 Scanner 如下,其中最常用的是扫描 Java 源文件和 XML 文件的 Scanner:

SourceCodeScanner:扫描 Java 和kotlin源文件
XmlScanner:扫描 XML 文件
ClassScanner:扫描 class 文件
BinaryResourceScanner:扫描二进制资源文件
ResourceFolderScanner:扫描资源文件夹
GradleScanner:扫描 Gradle 脚本
OtherFileScanner:扫描其他类型文件

使用Detecotor探测器,实现多个scanner扫描,然后找出lint问题,并通过Issue提示出来。

最后通过注册器IssueRegistry,注册到androidLint。

3、自定义lint

3.1、建立lint扫描的module(lint_tools)

类型选Java or Kotlin library,命名lint_tools

 

包名com.h3d.qqx5.lint,保持现有结构

  • build.gradle设置导包

导包

compileOnly "com.android.tools.lint:lint-api:$lint_version"
compileOnly "com.android.tools.lint:lint-checks:$lint_version"

一定要是compileOnly确保只编译不打包进主Module。

我这里使用kotlin的module所以额外有kotlin导包。

  • 编写一个代码检查器LogDetector.kt

继承Detector探测器,实现SourceCodeScanner接口,该接口支持扫描java和kotlin类。

看看源码该扫描类的方法

 

返回此检测器感兴趣的方法名称列表,或者空,也就是该类调用了什么方法,需要设置要检测的方法名,限制了范围。

 

方法访问,由getApplicableMethodNames()限制的方法名,该方法就可以检测到指定的方法。

比如检查App内调用了系统Log和System.out.println方法的标记并提示报错。

isMemberInClass是检查指定的方法的类名是否存在于该检测类中。存在我们就荣国ISSUE来跟Lint一样的样式提示出来。

参数分别是1、取消检测使用的注解名称 2和3、lint提示 4、Lint类型(性能、Icon、国际化这种,默认Lint)5、优先级1-10 6、报错等级 7、默认实现

编写好的ISSUE需要注册到Lint

  • 编写注册类

  • 编写module的build.gradle,全局配置文件设置注册类

3.2、主module使用lint_tools

由于安卓官方推荐的方式是把lint_tools打成jar,然后命名为lint.jar直接放到开发者C盘的.android/lint目录下使用,这将导致所有工程都要使用该lint,没必要。

lint_tools是lib工程只会生成jar,如果将该lint_tools直接导入主module,因为module是以jar的形式,无法直接发布,需要以aar形式引入。

这就需要中间module作为aar,创建Android Module (aar) lint_check

 

build.gradle下发布lint_tools module

其他选项和主module保持一致

主Module导入

gradle同步一下,以后build或者编译或者lint运行都可以实时检测。

 

但是空指针怎么判断还没有具体方法,继续研究~

改造LogDetetor,设想检测方法,所有get开头的方法判断获取到的内容是否为空

但是发现并没有错误提示。

后来查看api注释,只有添加的调用方法名,才能被Lint检查,Log之所以可以是因为它是系统Api,被广泛调用。也就是说已经被调用的通用代码可以使用,但是空指针一般都是未知的方法。

尝试加入

必须明文传入的方法才可以被检测,所以空指针的Lint暂时未找到实现方式。

  • Java代码增加空安全语法包裹

设计思路:传入原始数据,返回不为空的数据

类型必须要使用到泛型,因为Java的泛型实例化也是必须使用class类型的,由于data如果为空是不可能拿到class的,所以还需要额外的class传入,泛型这里是class<T>

对一个可能的数据空,调用该方法,除非实例化异常,否则很难出空指针异常了。

 

重要代码优先转Kotlin

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值