Kotlin Android項目可用的靜態檢查工具: Android官方的Lint, 第三方的ktlint和detekt.html
靜態檢查工具, 指不須要運行代碼, 對代碼進行檢查的工具.android
不止代碼風格, 還能夠檢查代碼的正確性, 是否有安全問題, 是否有性能問題等.git
靜態檢查工具通常都具有可擴展性, 方便使用者制定和添加本身的規則.github
比較流行的Java靜態檢查工具備CheckStyle, FindBugs, PMD等.安全
Android項目, 用Kotlin語言, 可用的靜態檢查工具: 官方的Android Lint, ktlint和detekt.bash
Android官方提供了代碼掃描工具, 叫lint.app
在Android Studio運行lint, 在菜單中選: Analyze -> Inspect Code...
, 選擇範圍, 點OK
便可運行.ide
也能夠在命令行:工具
./gradlew lint
會分類報告出各類各樣的錯誤.gitlab
點擊菜單中的Analyze -> Inspect Code...
, 在彈框的Inspection profile
部分點擊表示更多的...
按鈕, 會彈出框顯示當前的全部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"
等.
能夠在gradle中進行設置一個baseline:
android { lintOptions { baseline file("lint-baseline.xml") } }
第一次添加這個, 運行lint以後, 會自動建立一個lint-baseline.xml
文件, 全部當前的問題都會被寫入這個文件.
當再次運行lint, 就只會讀這個文件, 做爲基準, 只報告新的錯誤或警告. 而且提示其餘原有問題在baseline文件中, 被排除.
若是想從新生成baseline能夠手動刪除這個文件, 從新進行.
代碼風格檢查, 遵循的是: Kotlin style guide
全部的規則代碼: github: ktlint rule set
在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" }
檢查:
./gradlew ktlint
自動修改:
./gradlew ktlintFormat
並非全部問題均可以自動修改, 有的問題須要手動改.
配置中的這句:
check.dependsOn ktlint
把運行檢查加到了check task中. 經過:
./gradlew check --dry-run
能夠查看運行check
task都會作哪些事情(dry run表示不用實際執行這些任務).
看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
Github: detekt也是一個Kotlin的靜態分析工具.
官方網站: 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.
運行:
./gradlew detekt
進行檢測.
detekt { }
塊是用來進行自定義的屬性設置的.
若是開啓了文件輸出, 結果在: app/build/reports/detekt
目錄下能夠查看.
而且運行./gradlew check --dry-run
能夠發現, 運行check
的時候也會執行detekt
.
能夠利用:
./gradlew detektGenerateConfig
生成配置文件: config/detekt/detekt.yml
.
在配置文件中能夠看到對各類規則的開關狀態, 編輯它能夠進行定製.
程序的入口在detekt-cli
module的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.
detekt的規則種類更多, 而且它包含了ktlint的代碼檢查規則. 全部的ktlint
規則被包裝在detekt-formatting
這個module下, 見: detekt formatting rules.
可是並非全部規則都默認開啓.
在配置文件的formatting
塊能夠查看具體的規則開關狀態.
若是須要修改定製, 須要生成本身的配置文件.
Lint工具的運行能夠放在CI上, 也能夠每次本地手動跑, 這樣在push以前就能發現錯誤並改正.
一種避免忘記的方法就是使用Git hook.
項目的.git/hooks
文件夾下自帶一些有意思的sample.
只要在.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.
由於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文件的目錄設置成指定目錄就行了.
本文介紹了三種靜態檢查的工具:
這些工具均可以擴展, 添加自定義的檢查規則.
結合Git hook把靜態檢查在本地進行, 能夠實現問題的儘早暴露和修改.
原文出處:https://www.cnblogs.com/mengdd/p/kotlin-android-lint-tools-ktlint-detekt.html