Пользовательское правило Lint для проверки всех представлений в макетах

В приложении, над которым я работаю, обязательно, чтобы все представления во всех файлах макетов имели набор id. Поэтому я пытаюсь создать собственное правило lint, чтобы обеспечить это.

Обычно можно использовать метод getApplicableElements() из XmlScanner и включать список строк для каждого тега элемента. Однако я не могу найти способ сделать так, чтобы все элементы в XML-макете, подкласс View.

Однако я попытался использовать XmlScannerConstants.ALL, который просматривает каждый элемент в каждом XML-файле. Учитывая, что у нас есть несколько других типов ресурсов на основе XML, это не сработает.

Мой код для класса инспектора ниже. Кто-нибудь знает хороший способ фильтровать getApplicableElements(), чтобы он смотрел на каждый элемент, который является подклассом View, и ничего больше?

class IdDetector : ResourceXmlDetector() {

    companion object {

        private const val ISSUE_ID = "MissingId"
        private const val ISSUE_DESCRIPTION = "Missing required attribute 'id'"
        private const val ISSUE_EXPLANATION = "Identifiers are required on all views."

        val ISSUE = Issue.create(
            id = ISSUE_ID,
            briefDescription = ISSUE_DESCRIPTION,
            explanation = ISSUE_EXPLANATION,
            category = Category.A11Y,
            priority = 10,
            severity = Severity.FATAL,
            androidSpecific = true,
            implementation = Implementation(IdDetector::class.java, Scope.RESOURCE_FILE_SCOPE)
        )
    }

    override fun getApplicableElements(): Collection<String>? = XmlScannerConstants.ALL

    override fun visitElement(context: XmlContext, element: Element) {
        if (!element.hasAttributeNS("http://schemas.android.com/apk/res/android", "id")) {
            context.report(ISSUE, element, context.getLocation(element), ISSUE_DESCRIPTION)
        }
    }
}

person rjr-apps    schedule 26.03.2020    source источник


Ответы (1)


В этом вам поможет метод appliesTo(@NonNull ResourceFolderType folderType). В вашем случае, я полагаю, вас будет интересовать только папка макета. Ваш новый детектор будет выглядеть примерно так:

class IdDetector : ResourceXmlDetector() {

    companion object {

        private const val ISSUE_ID = "MissingId"
        private const val ISSUE_DESCRIPTION = "Missing required attribute 'id'"
        private const val ISSUE_EXPLANATION = "Identifiers are required on all views."

        val ISSUE = Issue.create(
            id = ISSUE_ID,
            briefDescription = ISSUE_DESCRIPTION,
            explanation = ISSUE_EXPLANATION,
            category = Category.A11Y,
            priority = 10,
            severity = Severity.FATAL,
            androidSpecific = true,
            implementation = Implementation(IdDetector::class.java, Scope.RESOURCE_FILE_SCOPE)
        )
    }

    override fun appliesTo(folderType: ResourceFolderType): Boolean = ResourceFolderType.LAYOUT == folderType

    override fun getApplicableElements(): Collection<String>? = XmlScannerConstants.ALL

    override fun visitElement(context: XmlContext, element: Element) {
        if (!element.hasAttributeNS("http://schemas.android.com/apk/res/android", "id")) {
            context.report(ISSUE, element, context.getLocation(element), ISSUE_DESCRIPTION)
        }
    }
}
person Andrei Teslovan    schedule 21.04.2020