首頁 > 軟體

Android程式碼檢查規則Lint的自定義與應用詳解

2022-04-12 13:00:26

前言:

在日常的程式碼開發中,此處相信每個開發人員對程式碼質量都是高要求,有自己的一套程式碼規範,但是我們不是單獨作戰,往往大家都是團隊作戰,人是最大的變數,各人各異,如何保證團隊的程式碼質量和程式碼規範呢?靠開發者自覺嗎?也許有的團隊有嚴格的CR機制,在MR階段會進行CR,CR不通過的MR是不允許合入的,但是這樣會使Reviewer花費較多的時間去校驗,那麼這時候我們就需要在編碼過程中提供一種程式碼檢測機制。

例如:期望表現的效果就是在編碼時可以展示異常檢測的方法,高亮或者標紅,當滑鼠懸停在高亮的程式碼上時,會提供問題的描述和解決方法。需要這種效果,就需要自定義lint了。

什麼是Lint

在Android Studio中提供的程式碼掃描工具Lint,可在無需實際執行該應用,也不必編寫測試用例的情況下幫助開發者發現程式碼質量問題和提出一些改進建議。

Lint工具可檢查您的 Android 專案原始檔是否包含潛在錯誤,以及在正確性、安全性、效能、易用性、便利性和國際化方面是否需要優化改進。在使用 Android Studio 時,設定的 Lint 和 IDE 檢查會在您每次構建應用時執行。不過,您可以手動執行檢查或從命令列執行 Lint。

android studio內建了較多的lint規則,但內建的lint規則無法滿足直觀的適合我們時,就需要我們自定義lint了。

自定義Lint流程:

1. 新建立module,Module型別選擇Java or Kotlin Library, 暫時命名lint_tools

2. 在build.gradle中引入lint的依賴

    dependencies {
        compileOnly 'com.android.tools.lint:lint-api:27.2.2'
        compileOnly 'com.android.tools.lint:lint-checks:27.2.2'
    }

在moudle中依賴了lint-api和lint-checks,其中lint-api就是lint相關的api,lint-checks就是android studio裡自定義的一些lint規則,我們自定義lint可以參考lint-checks裡面的寫法。

3. 本地建立個資源id命名檢查規則,用來規範專案中的id統一命名

建立ViewIdDetector,直接繼承LayoutDetector(也可以繼承ResourceXmlDetector 或者 繼承Detector實現的介面是XmlScanner,方式多樣)

import com.android.SdkConstants
import com.android.tools.lint.detector.api.*
import com.android.tools.lint.detector.api.Category.Companion.CORRECTNESS
import com.android.tools.lint.detector.api.Scope.Companion.RESOURCE_FILE_SCOPE
import org.w3c.dom.Element
​
class ViewIdDetector : LayoutDetector() {
    
    override fun getApplicableElements(): Collection<String>? {
        return listOf(
            SdkConstants.TEXT_VIEW,
            SdkConstants.IMAGE_VIEW,
            SdkConstants.BUTTON
        )
    }
​
    override fun visitElement(context: XmlContext, element: Element) {
        if (!element.hasAttributeNS(SdkConstants.ANDROID_URI, SdkConstants.ATTR_ID)) {
            return
        }
        val attr = element.getAttributeNodeNS(SdkConstants.ANDROID_URI, SdkConstants.ATTR_ID)
        val value = attr.value
        if (value.startsWith(SdkConstants.NEW_ID_PREFIX)) {
            val idValue = value.substring(SdkConstants.NEW_ID_PREFIX.length)
            var matchRule = true
            var expMsg = ""
            when (element.tagName) {
                SdkConstants.TEXT_VIEW -> {
                    expMsg = "tv"
                    matchRule = idValue.startsWith(expMsg)
                }
                SdkConstants.IMAGE_VIEW -> {
                    expMsg = "iv"
                    matchRule = idValue.startsWith(expMsg)
                }
                SdkConstants.BUTTON -> {
                    expMsg = "btn"
                    matchRule = idValue.startsWith(expMsg)
                }
            }
            if (!matchRule) {
                context.report(
                    ISSUE, 
                    attr, 
                    context.getLocation(attr), 
                    "ViewIdName建議使用view的縮寫_xxx; ${element.tagName} 建議使用 `${expMsg}_xxx`"
                )
            }
        }
    }
​
    companion object {
        val ISSUE: Issue = Issue.create(
            "ViewIdCheck",
            "ViewId命名不規範",
            "ViewIdName建議使用 view的縮寫加上_xxx,例如tv_xxx, iv_xxx",
            CORRECTNESS,
            5, Severity.ERROR,
            Implementation(
                ViewIdDetector::class.java,
                RESOURCE_FILE_SCOPE
            )
        )
    }
}

自定義Detector可以實現一個或多個Scanner介面,選擇實現哪種介面取決於你想要的掃描範圍。
Lint API 中內建了很多 Scanner:

Scanner 型別Desc
UastScanner掃描 Java、Kotlin 原始檔
XmlScanner掃描 XML 檔案
ResourceFolderScanner掃描資原始檔夾
ClassScanner掃描 Class 檔案
BinaryResourceScanner掃描二進位制資原始檔
GradleScanner掃描Gradle指令碼

4. 實現IssueRegistry並新增對應的自定義Issue:

class IMockIssueRegistry: IssueRegistry() {
    override val issues: List<Issue>
        get() = listOf(
            ViewIdDetector.ISSUE
        )
​
}

5. 在module(lint_tools)中對應的build.gradle中設定如下資訊:

jar {
    manifest {
        attributes("Lint-registry-v2": "com.imock.lint.IMockIssueRegistry")
    }
}

6. 在需要進行lint檢查的module中或者app目錄現的build.gradle中參照對應的lint_tools即可使用。

dependencies {
    lintChecks project(path: ':lint-tools')
}

至此你可以試著自己自定義Lint了,相關語法api都可參考lint-checks中提供的Detector實現,來實現自己的Lint檢查規則。

拓展一下:

1. 針對Issue.create引數了解一下:

companion object {
    /**
     * Creates a new issue. The description strings can use some simple markup;
     * see the [TextFormat.RAW] documentation
     * for details.
     *
     * @param id the fixed id of the issue
     * @param briefDescription short summary (typically 5-6 words or less), typically
     * describing the **problem** rather than the **fix**
     * (e.g. "Missing minSdkVersion")
     * @param explanation a full explanation of the issue, with suggestions for
     * how to fix it
     * @param category the associated category, if any
     * @param priority the priority, a number from 1 to 10 with 10 being most
     * important/severe
     * @param severity the default severity of the issue
     * @param implementation the default implementation for this issue
     * @return a new [Issue]
     */
    @JvmStatic
    fun create(
        id: String,
        briefDescription: String,
        explanation: String,
        category: Category,
        priority: Int,
        severity: Severity,
        implementation: Implementation
    ): Issue {
        val platforms = computePlatforms(null, implementation)
        return Issue(
            id, briefDescription, explanation, category, priority,
            severity, platforms, null, implementation
        )
    }
}
  • 引數id 唯一的id,簡要表面當前提示的問題。
  • 引數briefDescription 簡單描述當前問題
  • 引數explanation 詳細解釋當前問題和修復建議
  • 引數category 問題類別
  • 引數priority 優先順序,從1到10,10最重要
  • 引數Severity 嚴重程度:FATAL(奔潰), ERROR(錯誤), WARNING(警告),INFORMATIONAL(資訊性),IGNORE(可忽略)
  • 引數Implementation Issue和哪個Detector繫結,以及宣告檢查的範圍。Scope有如下選擇範圍:RESOURCE_FILE(資原始檔),BINARY_RESOURCE_FILE(二進位制資原始檔),RESOURCE_FOLDER(資原始檔夾),ALL_RESOURCE_FILES(所有資原始檔),JAVA_FILE(Java檔案), ALL_JAVA_FILES(所有Java檔案),CLASS_FILE(class檔案), ALL_CLASS_FILES(所有class檔案),MANIFEST(設定清單檔案), PROGUARD_FILE(混淆檔案),JAVA_LIBRARIES(Java庫), GRADLE_FILE(Gradle檔案),PROPERTY_FILE(屬性檔案),TEST_SOURCES(測試資源),OTHER(其他);

到此這篇關於Android程式碼檢查規則Lint的自定義與應用詳解的文章就介紹到這了,更多相關Android程式碼檢查規則Lint內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com