Kotlin Android项目静态检查工具的使用

Kotlin Android项目静态检查工具的使用

Kotlin Android项目可用的静态检查工具: Android官方的Lint, 第三方的ktlint和detekt.html

静态检查工具

静态检查工具, 指不须要运行代码, 对代码进行检查的工具.android

不止代码风格, 还能够检查代码的正确性, 是否有安全问题, 是否有性能问题等.git

静态检查工具通常都具有可扩展性, 方便使用者制定和添加本身的规则.github

比较流行的Java静态检查工具备CheckStyle, FindBugs, PMD等.安全

Android项目, 用Kotlin语言, 可用的静态检查工具: 官方的Android Lint, ktlint和detekt.bash

Android Lint

Android官方提供了代码扫描工具, 叫lint.app

在Android Studio运行lint, 在菜单中选: Analyze -> Inspect Code..., 选择范围, 点OK便可运行.ide

也能够在命令行:工具

./gradlew lint

会分类报告出各类各样的错误.gitlab

查看全部的Lint规则

点击菜单中的Analyze -> Inspect Code..., 在弹框的Inspection profile部分点击表示更多的...按钮, 会弹出框显示当前的全部lint规则.

能够选择是否包括规则, 编辑它们的优先级和应用范围等.

Android Lint配置

全局的配置除了用IDE, 还能够经过lint.xml文件.

还能够在gradle中配置, 好比:

android {
  ...
  lintOptions {
    // Turns off checks for the issue IDs you specify.
    disable 'TypographyFractions','TypographyQuotes'
    // Turns on checks for the issue IDs you specify. These checks are in
    // addition to the default lint checks.
    enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'
    // To enable checks for only a subset of issue IDs and ignore all others,
    // list the issue IDs with the 'check' property instead. This property overrides
    // any issue IDs you enable or disable using the properties above.
    check 'NewApi', 'InlinedApi'
    // If set to true, turns off analysis progress reporting by lint.
    quiet true
    // if set to true (default), stops the build if errors are found.
    abortOnError false
    // if true, only report errors.
    ignoreWarnings true
  }
}

特定代码能够利用@SuprressLint注解. 好比: @SuppressLint("NewApi"), @SuppressLint("all").

特定xml文件中能够用tools:ignore, 好比tools:ignore="UnusedResources", tools:ignore="NewApi,StringFormatInvalid", tools:ignore="all"等.

Android Lint现状基准快照

能够在gradle中进行设置一个baseline:

android {
  lintOptions {
    baseline file("lint-baseline.xml")
  }
}

第一次添加这个, 运行lint以后, 会自动建立一个lint-baseline.xml文件, 全部当前的问题都会被写入这个文件.

当再次运行lint, 就只会读这个文件, 做为基准, 只报告新的错误或警告. 而且提示其余原有问题在baseline文件中, 被排除.

若是想从新生成baseline能够手动删除这个文件, 从新进行.

ktlint

ktlint

代码风格检查, 遵循的是: Kotlin style guide

全部的规则代码: github: ktlint rule set

ktlint安装

app/build.gradle中添加:

configurations {
    ktlint
}

dependencies {
    ktlint "com.pinterest:ktlint:0.36.0"
    ...
}
task ktlint(type: JavaExec, group: "verification") {
    description = "Check Kotlin code style."
    classpath = configurations.ktlint
    main = "com.pinterest.ktlint.Main"
    args "src/**/*.kt"
    // to generate report in checkstyle format prepend following args:
    // "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml"
    // see https://github.com/pinterest/ktlint#usage for more
}
check.dependsOn ktlint

task ktlintFormat(type: JavaExec, group: "formatting") {
    description = "Fix Kotlin code style deviations."
    classpath = configurations.ktlint
    main = "com.pinterest.ktlint.Main"
    args "-F", "src/**/*.kt"
}

ktlint使用

检查:

./gradlew ktlint

自动修改:

./gradlew ktlintFormat

并非全部问题均可以自动修改, 有的问题须要手动改.

配置中的这句:

check.dependsOn ktlint

把运行检查加到了check task中. 经过:

./gradlew check --dry-run

能够查看运行check task都会作哪些事情(dry run表示不用实际执行这些任务).

ktlint源码

看ktlint的源码, 程序的入口是Main.kt文件中的main.

使用的规则集是:

class StandardRuleSetProvider : RuleSetProvider {

    // Note: some of these rules may be disabled by default. See the default .editorconfig.
    override fun get(): RuleSet = RuleSet(
        "standard",
        ChainWrappingRule(),
        CommentSpacingRule(),
        FilenameRule(),
        FinalNewlineRule(),
        ImportOrderingRule(),
        IndentationRule(),
        MaxLineLengthRule(),
        ModifierOrderRule(),
        NoBlankLineBeforeRbraceRule(),
        NoConsecutiveBlankLinesRule(),
        NoEmptyClassBodyRule(),
        NoLineBreakAfterElseRule(),
        NoLineBreakBeforeAssignmentRule(),
        NoMultipleSpacesRule(),
        NoSemicolonsRule(),
        NoTrailingSpacesRule(),
        NoUnitReturnRule(),
        NoUnusedImportsRule(),
        NoWildcardImportsRule(),
        ParameterListWrappingRule(),
        SpacingAroundColonRule(),
        SpacingAroundCommaRule(),
        SpacingAroundCurlyRule(),
        SpacingAroundDotRule(),
        SpacingAroundKeywordRule(),
        SpacingAroundOperatorsRule(),
        SpacingAroundParensRule(),
        SpacingAroundRangeOperatorRule(),
        StringTemplateRule()
    )
}

能够看到都是代码格式相关的规则.

在线查看: ktlint ruleset standard

detekt

Github: detekt也是一个Kotlin的静态分析工具.

官方网站: detekt.

detekt安装

在项目根目录的build.gradle文件中添加:

plugins {
    id("io.gitlab.arturbosch.detekt").version("1.5.0")
}

allprojects {
    repositories {
        google()
        jcenter()
    }
    apply plugin: 'io.gitlab.arturbosch.detekt'
}

detekt {
    failFast = true // fail build on any finding
    buildUponDefaultConfig = true // preconfigure defaults
    config = files("$projectDir/config/detekt.yml")
    // point to your custom config defining rules to run, overwriting default behavior
    baseline = file("$projectDir/config/baseline.xml")
    // a way of suppressing issues before introducing detekt

    reports {
        html.enabled = true // observe findings in your browser with structure and code snippets
        xml.enabled = true // checkstyle like format mainly for integrations like Jenkins
        txt.enabled = true
        // similar to the console output, contains issue signature to manually edit baseline files
    }
}

运行./gradlew tasks能够看到相关任务被加进去了:

detekt
detektBaseline - Creates a detekt baseline on the given --baseline path.
detektGenerateConfig - Generate a detekt configuration file inside your project.
detektIdeaFormat - Uses an external idea installation to format your code.
detektIdeaInspect - Uses an external idea installation to inspect your code.

detekt使用

运行:

./gradlew detekt

进行检测.

detekt {
}

块是用来进行自定义的属性设置的.

若是开启了文件输出, 结果在: app/build/reports/detekt目录下能够查看.

而且运行./gradlew check --dry-run能够发现, 运行check的时候也会执行detekt.

能够利用:

./gradlew detektGenerateConfig

生成配置文件: config/detekt/detekt.yml.

在配置文件中能够看到对各类规则的开关状态, 编辑它能够进行定制.

detekt源码

程序的入口在detekt-climodule的Main.kt. 根据参数的不一样返回不一样的Runner.

主要用于检测的是这个Runner, 它的执行方法:

override fun execute() {
    createSettings().use { settings ->
        val (checkConfigTime) = measure { checkConfiguration(settings) }
        settings.debug { "Checking config took $checkConfigTime ms" }
        val (serviceLoadingTime, facade) = measure { DetektFacade.create(settings) }
        settings.debug { "Loading services took $serviceLoadingTime ms" }
        var (engineRunTime, result) = measure { facade.run() }
        settings.debug { "Running core engine took $engineRunTime ms" }
        checkBaselineCreation(result)
        result = transformResult(result)
        val (outputResultsTime) = measure { OutputFacade(arguments, result, settings).run() }
        settings.debug { "Writing results took $outputResultsTime ms" }
        if (!arguments.createBaseline) {
            checkBuildFailureThreshold(result, settings)
        }
    }
}

读取配置, 建立服务, 执行检测, 转化输出结果.

当没有用户本身声明的配置文件时, 使用的默认配置文件是default-detekt-config.yml.

在这里能够看到对全部规则的默认开关状态.

detekt的规则代码放在detekt-rules这个module下: detekt rules.

官方文档上也有说明, 好比这是performance分类下的rules: detekt performance.

包含ktlint的规则

detekt的规则种类更多, 而且它包含了ktlint的代码检查规则. 全部的ktlint规则被包装在detekt-formatting这个module下, 见: detekt formatting rules.

可是并非全部规则都默认开启.

在配置文件的formatting块能够查看具体的规则开关状态.

若是须要修改定制, 须要生成本身的配置文件.

和Git hook结合

Lint工具的运行能够放在CI上, 也能够每次本地手动跑, 这样在push以前就能发现错误并改正.

一种避免忘记的方法就是使用Git hook.

项目的.git/hooks文件夹下自带一些有意思的sample.

如何使用git hook

只要在.git/hooks路径下添加对应名字的文件, 如pre-push, pre-commit, 写入想要的代码便可.

hook文件返回0表示经过, 会进行下一步操做. 不然后面的操做会被放弃.

注意文件要有执行权限: chmod +x 文件名

若是不想跑hook能够加上 --no-verify 好比

git commit --no-verify

在提交以前运行静态检查

以ktlint为例, 咱们但愿每次commit的时候先运行./gradlew ktlint, 若是有issue则放弃提交.

.git/hooks中添加pre-commit文件, 其中:

#!/bin/bash
echo "Running ktlint"

./gradlew ktlint
result=$?
if [ "$result" = 0 ] ; then    
   echo "ktlint found no problems"     
   exit 0
else
   echo "Problems found, files will not be committed."     
   exit 1
fi

detekt的添加也是相似, 官网上给了一个例子: detekt/git-pre-commit-hook.

如何track, 共享Git hooks

由于hooks文件在.git目录里, 只是在本地, 那么在团队成员间如何共享呢?

根据这个问题: https://stackoverflow.com/questions/427207/can-git-hook-scripts-be-managed-along-with-the-repository

从git 2.9开始, 能够设置:core.hooksPath了.

能够在repo里面添加一个目录hooks, 而后把git hooks文件放进去track.

在命令行跑:

git config core.hooksPath hooks

把找hook文件的目录设置成指定目录就行了.

总结

本文介绍了三种静态检查的工具:

  • Android Lint: Android自带的Lint检查. 检查的内容比较丰富.
  • ktlint: Kotlin代码样式规范检查. 特点: 有自动修正命令.
  • detekt: 除了code style还有performance, exceptions, bugs等方面的检查. formatting模块包含了ktlint的全部style检查(虽然有的具体的规则默认不开启, 可是能够配置), 是前者的超集.

这些工具均可以扩展, 添加自定义的检查规则.

结合Git hook把静态检查在本地进行, 能够实现问题的尽早暴露和修改.

示例代码

AndroidLintDemo

  • ktlint集成: ktlint分支.
  • detekt集成: detekt分支.

参考

原文出处:https://www.cnblogs.com/mengdd/p/kotlin-android-lint-tools-ktlint-detekt.html

相关文章
相关标签/搜索