Kotlin Android項目靜態檢查工具的使用

来源:https://www.cnblogs.com/mengdd/archive/2020/02/08/kotlin-android-lint-tools-ktlint-detekt.html
-Advertisement-
Play Games

Kotlin Android項目可用的靜態檢查工具: Android官方的Lint, 第三方的ktlint和detekt. ...


Kotlin Android項目靜態檢查工具的使用

Kotlin Android項目可用的靜態檢查工具: Android官方的Lint, 第三方的ktlint和detekt.

靜態檢查工具

靜態檢查工具, 指不需要運行代碼, 對代碼進行檢查的工具.

不止代碼風格, 還可以檢查代碼的正確性, 是否有安全問題, 是否有性能問題等.

靜態檢查工具一般都具備可擴展性, 方便使用者制定和添加自己的規則.

比較流行的Java靜態檢查工具有CheckStyle, FindBugs, PMD等.

Android項目, 用Kotlin語言, 可用的靜態檢查工具: 官方的Android Lint, ktlint和detekt.

Android Lint

Android官方提供了代碼掃描工具, 叫lint.

在Android Studio運行lint, 在菜單中選:
Analyze -> Inspect Code..., 選擇範圍, 點OK即可運行.

也可以在命令行:

 ./gradlew lint

會分類報告出各種各樣的錯誤.

查看所有的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分支.

參考


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 很久沒有寫過 .NET Core 相關的文章了,目前關店在家休息所以有些時間寫一篇新的
  • 首先,先看我個人的項目結構。 這個webapi項目是專門作為圖片上傳的業務處理,而其中分為兩個控制器:單圖片上傳和多圖片上傳。在接下來的內容主要還是針對單文件上傳,對於多文件的上傳,我暫且尚未研究成功。 其中pictureoptions類,由於我把關於圖片上傳相關的配置項(保存路徑、限制的文件類型和 ...
  • 編譯安裝 Centos8下PHP源碼編譯和通過yum安裝的區別和以後的選擇 其實這兩種方法各有千秋: yum安裝: 從yum安裝來說吧,yum相當於是自動化幫你安裝,你不用管軟體的依賴關係,在yum安裝過程是幫你把軟體的全部依賴關係幫你傻瓜式的解決了。而且現在Centos7的服務啟動已經換成syst ...
  • 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期 ...
  • Shell腳本基礎入門 Bash註釋 Bash只支持單行註釋,使用 開頭的都被當作註釋語句: 通過Bash的一些特性,可以取巧實現多行註釋: 所以,預設情況下讀寫數據都是終端,例如: 改變文件描述符對應的目標,可以改變數據的流向。比如標準輸入fd=1預設流向是終端設備,若將其改為/tmp/a.log ...
  • redis中壓縮列表ziplist相關的文件為:ziplist.h與ziplist.c 壓縮列表是redis專門開發出來為了節約記憶體的記憶體編碼數據結構。源碼中關於壓縮列表介紹的註釋也寫得比較詳細。 一、數據結構 壓縮列表的整體結構如下(借用redis源碼註釋): 1 /* 2 <zlbytes> < ...
  • 實例代碼: import React, { Component , PropTypes} from 'react'; import { AppRegistry, StyleSheet, Text, View, TextInput, TouchableOpacity } from 'react-nat ...
  • 慕課網- LovelyChubby-Jetpack全組件實戰 開發短視頻應用App-348元 筆記 微雲:https://share.weiyun.com/81aa12bb98016e200add31fb8e191cdf百度網盤:鏈接:https://pan.baidu.com/s/1IiClTkQ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...