上一篇聊了 Lifecycle 源码,这篇聊聊代码质量保障工具链。代码质量不是靠 code review 人肉盯出来的,而是靠工具在 CI 和 IDE 层面拦截。Lint、ktlint、detekt 三件套配合好了,大部分低级问题在提交前就挡住了。
三种工具的分工
三者不冲突,互补使用。
Android Lint
Lint 是 Android SDK 自带的静态分析工具,检查 Android 特有问题。
基础使用
./gradlew lintDebug
报告生成在 app/build/reports/lint-results-debug.html。
常用规则
HardcodedText:硬编码字符串(应该用资源文件)UsingWebView:WebView 未设置安全配置ObsoleteLintCustomCheck:过时的 Lint 规则UnusedResources:未使用的资源文件IconLauncherShape:启动图标问题NewApi:使用了高于 minSdk 的 API
配置
// build.gradle
android {
lint {
abortOnError = false // 发现错误不中断构建
warningsAsErrors = false
disable += "HardcodedText" // 禁用某条规则
enable += "UnknownNullness"
baseline = file("lint-baseline.xml") // 基线文件
}
}
Baseline 文件
存量项目加 Lint 会报几百个问题,不可能一次性全修。用 baseline 把当前问题"固定"下来,只检查新增问题:
./gradlew lintDebug --update-baseline
生成 lint-baseline.xml 后提交到仓库,后续只报告 baseline 之外的新问题。
ktlint
ktlint 检查 Kotlin 代码风格,规则来自官方 Kotlin Coding Conventions。
集成
// build.gradle (root)
plugins {
id("org.jlleitschuh.gradle.ktlint") version "12.1.1" apply false
}
// build.gradle (app)
plugins {
id("org.jlleitschuh.gradle.ktlint")
}
使用
./gradlew ktlintCheck # 检查
./gradlew ktlintFormat # 自动修复
ktlintFormat 能自动修复大部分格式问题(缩进、import 排序、尾随空格等),非常方便。建议在 git pre-commit hook 里跑 ktlintFormat。
自定义规则
// .editorconfig
[*.{kt,kts}]
ktlint_standard_no-wildcard-imports = enabled # 禁止通配符 import
ktlint_standard_function-naming = disabled # 禁用函数命名规则
max_line_length = 120
通过 .editorconfig 文件控制规则开关,不需要改 Gradle 配置。
detekt
detekt 检查 Kotlin 代码质量,比 ktlint 更深入:复杂度、坏味道、潜在 bug。
集成
// build.gradle (root)
plugins {
id("io.gitlab.arturbosch.detekt") version "1.23.6" apply false
}
// build.gradle (app)
plugins {
id("io.gitlab.arturbosch.detekt")
}
detekt {
config.setFrom("$rootDir/config/detekt.yml")
buildUponDefaultConfig = true
parallel = true
}
配置文件
# config/detekt.yml
complexity:
LongMethod:
threshold: 60 # 方法超过 60 行报警
LongParameterList:
functionThreshold: 6 # 参数超过 6 个报警
CyclomaticComplexMethod:
threshold: 15
style:
ReturnCount:
max: 3 # return 语句超过 3 个报警
WildcardImport:
active: true
naming:
FunctionNaming:
functionPattern: '([a-z][a-zA-Z0-9]*)|(`.*`)'
自定义规则
detekt 支持自定义规则,通过实现 Rule 类:
class NoLogDirectCallRule(config: Config) : Rule(config) {
override val issue = Issue(
id = "NoLogDirectCall",
severity = Severity.Warning,
description = "Don't call android.util.Log directly, use AppLog",
debt = Debt.FIVE_MINS
)
override fun visitImportDirective(importDirective: KtImportDirective) {
if (importDirective.importedFqName?.asString() == "android.util.Log") {
report(CodeSmell(issue, Entity.at(importDirective), issue.description))
}
}
}
自定义规则打包成 jar 插件,在 detekt.yml 中启用:
NoLogDirectCall:
active: true
Git Pre-commit Hook
#!/bin/bash
# .git/hooks/pre-commit
# 只检查暂存区的文件
files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.kt$|\.kts$')
if [ -n "$files" ]; then
echo "Running ktlintFormat..."
./gradlew ktlintFormat -PinternalPreCommit=true --daemon > /dev/null 2>&1
# 重新暂存格式化后的文件
echo "$files" | xargs git add
fi
或者用 ktlint 的 Git Hook 插件自动安装:
plugins {
id("org.jlleitschuh.gradle.ktlint-idea") version "12.1.1"
}
./gradlew addKtlintCheckGitPreCommitHook
CI 集成
# GitHub Actions
- name: Run Lint
run: ./gradlew lintDebug
- name: Run ktlint
run: ./gradlew ktlintCheck
- name: Run detekt
run: ./gradlew detekt
- name: Upload reports
if: always()
uses: actions/upload-artifact@v4
with:
name: code-quality-reports
path: |
app/build/reports/lint-results-*.html
app/build/reports/detekt/detekt.html
实际效果
在一个 50 万行代码的项目上接入三件套后的统计:
Lint 发现 120 个问题(20% NewApi,30% 硬编码文本,50% 其他)
ktlint 修复了 300+ 格式问题
detekt 发现 15 个复杂度过高的方法、5 个潜在空指针
接入后新代码的质量明显提升,review 时不再纠结格式问题,聚焦逻辑和架构。
小结
代码质量保障三件套:Lint 管 Android 特性、ktlint 管格式、detekt 管质量。配合 baseline 文件做存量管理、pre-commit hook 做增量拦截、CI 做门禁,形成"开发-提交-CI"三层防线。投入一天配置,长期受益。
这是系列文章第 50 篇,Android 100 篇进阶笔记已完成一半。后续将继续深入:编译器插件、字节码插桩、热修复原理、Flutter 与 Android 互操作等更硬核的主题。