4、规则配置入门:Lint 的 lint.xml 配置、Detekt 的 detekt.yml 配置

规则配置,说白了就是把工具的“检查清单”按你的项目胃口调一调。默认配置往往要么太松(漏检一堆问题),要么太紧(跑一次恨不得报几百个错误)。我个人习惯,先把门打开,然后慢慢收紧——这样团队不会一开始就被劝退。

核心思路:Lint 和 Detekt 一个侧重 Android 原生规范,一个侧重 Kotlin 代码风格。它们的配置方式完全不同,但目标一致——让规则适配项目,而不是项目去迁就规则。

4.1 Lint 的 lint.xml:简单但容易踩坑

Lint 的配置放在 lint.xml 里,通常放在模块根目录(比如 app/lint.xml)。它是 XML 格式,Android Studio 原生支持,可视化编辑也能行。但我建议手动写,因为你能控制每个规则的 severity。

我曾经遇到一个项目,lint 检查总是“不报错”,后来发现是 lint.xml 里把所有 severity 都设成了 ignore。这算是经典新手错误了。

基本结构

<?xml version="1.0" encoding="UTF-8"?>
<lint>
    <!-- 禁用某个规则 -->
    <issue id="HardcodedText" severity="ignore" />

    <!-- 提高某个规则的严重级别 -->
    <issue id="ObsoleteSdkInt" severity="error" />

    <!-- 针对特定文件路径排除 -->
    <issue id="UnusedResources" severity="error">
        <ignore path="**/res/values/strings.xml" />
    </issue>
</lint>

issue id 对应 Lint 规则名称,可以去 官方文档(别点,这是正文,我只是提一嘴)查全列表。severity 可选值:fatal、error、warning、informational、ignore。这里有个小技巧:在 CI 里,我习惯把 fatal 和 error 一起拦截构建,warning 只输出日志不阻断。

常见场景配置表

目标 规则 ID 推荐 severity
禁止硬编码文本 HardcodedText error
禁止过时 API 调用 ObsoleteSdkInt error
禁止使用已弃用 API Deprecated warning (或 error)
约束方法数量(防止超标) MethodCount warning
忽略 R.java 中的无用资源 UnusedResources ignore (针对 build 文件夹)

注意:lint.xml 里 ignore 路径用的是 Ant 风格通配符,比如 **/build/**。我曾经把 **/build/** 写成了 **/build/*,导致 build 下的子目录没被忽略,lint 跑了一个小时……嗯,血的教训。

4.2 Detekt 的 detekt.yml:从 JSON 到 YAML 的进化

Detekt 的配置在 detekt.yml 里,默认放在项目根目录或模块根目录。它是一个 YAML 文件,比 XML 可读性强太多。我刚开始接触 Detekt 时,就直接把官方默认配置复制了一份,然后逐条勾选——这方法笨但有效。

配置结构概览

# detekt.yml
build:
  maxIssues: 100
  excludeCorrectable: false

comments:
  active: true
  excludes: ["**/build/**"]

complexity:
  active: true
  LongParameterList:
    active: true
    constructorThreshold: 6
    functionThreshold: 5
  TooManyFunctions:
    active: true
    thresholdInFiles: 11
    thresholdInClasses: 11
    thresholdInInterfaces: 11
    thresholdInObjects: 11

performance:
  active: true
  SpreadOperator:
    active: false

potential-bugs:
  active: true
  UnreachableCode:
    active: true

style:
  active: true
  WildcardImport:
    active: false
  MaxLineLength:
    active: true
    maxLineLength: 120
    excludePackageStatements: true
    excludeCommentStatements: true
    excludeRawStrings: true

YAML 缩进不能错!空格不能少!我见过有人用 Tab 缩进导致 Detekt 直接报「配置解析失败」。记住用 2 个空格一级缩进。

关键节点说明

  • build:全局构建选项,maxIssues 控制允许的最大问题数,超过这个数构建失败。我习惯设 200,给团队留点喘息空间,后面逐步收紧。
  • comments:注释相关规则,比如 MissingDocumentation。我一般注释规则全关——Kotlin 代码自解释能力强,强制写文档反而拖慢开发。
  • complexity:复杂度相关,LongParameterList、TooManyFunctions 等。这是代码异味的高发区,建议保持 active: true。
  • potential-bugs:可能出 bug 的代码模式,比如 UnreachableCode、DoubleNegative。这块我会开最严——一次线上 bug 的代价远超配置调优的时间。
  • style:代码风格,比如 MaxLineLength、WildcardImport。这里要结合团队规范来,我一般保留 MaxLineLength: 120,把 WildcardImport 关掉(团队习惯用星号导入)。

配置分层:不同模块用不同规则

项目里如果有多模块(比如 app、domain、data),每个模块可以有自己的 detekt.yml。不过这样做维护成本高。我建议的做法是:项目根目录一个主配置,模块里通过 config 属性覆盖。

// 在 build.gradle.kts 或 build.gradle 中
detekt {
    config = files("${project.rootDir}/detekt.yml")
    // 模块级覆盖
    if (project.name == "domain") {
        config = files("${project.projectDir}/detekt-domain.yml")
    }
}

domain 层没有 Android 依赖,可以更严格——比如 MaxLineLength: 100,NamingRules 全开。而 app 层有大量第三方库,适当放宽一些规则。

4.3 配置核心逻辑:一张图全看懂

规则配置核心逻辑 配置入口 Lint:lint.xml Detekt:detekt.yml 规则ID + severity 路径排除(ignore) 子规则 active + 阈值 分组覆盖(模块定制) CI 管道统一执行 关键点:Lint 侧重 Android原生规则(资源、兼容性),Detekt 侧重 Kotlin代码风格与复杂度 两者配置互相补充,不冲突。建议先配 lint.xml 做“基础防线”,再用 detekt.yml 做“代码质量看板”

4.4 避坑指南:我踩过的三个坑

  • Lint 的 XML 编码: lint.xml 文件必须用 UTF-8 保存,否则中文注释会乱码导致解析失败。我遇到过 Jenkins 上 lint 一直报“XML parse error”,折腾半天才发现是文件保存时用了 GBK。
  • Detekt 的 YAML 版本兼容: 不同 Detekt 版本对配置项的支持不一样。比如 1.22 版本里 excludeCorrectable 还是 boolean,到 1.23 变成了 object。升级 Detekt 版本后一定要重新从官方默认配置 diff 一下。
  • 不要一次性全开所有规则: 我刚开始推行 Detekt 时,把 400 多个规则全开了,结果项目编译时间多了 3 分钟,问题列表 8000+,团队直接炸毛。建议分阶段启用:先开 bug 类和复杂度类,稳定后再开风格类。

4.5 配置生效验证小技巧

配置写好了,怎么确认它生效了?有两种快速验证方式:

# 验证 Lint 配置是否生效(命令行)
./gradlew lint  # 查看 lint-results.html 中规则是否按你的 severity 显示

# 验证 Detekt 配置是否生效(命令行)
./gradlew detektBaseline  # 生成 baseline 文件,看排除路径是否被忽略

另外,我习惯在 CI 里加一个步骤:把 detekt.yml 和 lint.xml 的内容 print 到日志里。这样万一配置被谁改了(比如 MR 合入时带错了文件),一眼就能发现问题。

一个小技巧: 使用 detekt --print-config 可以输出实际生效的完整配置(含所有默认值),方便对比你的配置是否覆盖了期望的规则。