前言:
在日常的代码开发中,此处相信每个开发人员对代码质量都是高要求,有自己的一套代码规范,但是我们不是单独作战,往往大家都是团队作战,人是最大的变量,各人各异,如何保证团队的代码质量和代码规范呢?靠开发者自觉吗?也许有的团队有严格的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(其他);
2. Lint API 中 UastScanner 相关回调方法介绍
- getApplicableUastTypes 与 createUastHandler
- getApplicableUastTypes 此方法返回需要检查的AST节点的类型,类型匹配的UElement将会被createUastHandler(createJavaVisitor)创建的UElementHandler(Visitor)检查。
- createUastHandler 创建一个UastHandler来检查需要检查的UElement,对应于getApplicableUastTypes
- getApplicableMethodNames 与 visitMethod
- getApplicableMethodNames 返回你所需要检查的方法名称列表,或者返回null,相匹配的方法将通过visitMethod方法被检查
- visitMethod 检查与getApplicableMethodNames相匹配的方法
- getApplicableConstructorTypes 与 visitConstructor
- getApplicableConstructorTypes 返回需要检查的构造函数类型列表,类型匹配的方法将通过visitConstructor被检查
- visitConstructor 检查与getApplicableConstructorTypes相匹配的构造方法
- getApplicableReferenceNames 与 visitReference
- getApplicableReferenceNames 返回需要检查的引用路径名,匹配的引用将通过visitReference被检查
- visitReference 检查与getApplicableReferenceNames匹配的引用
- appliesToResourceRefs 与 visitResourceReference
- appliesToResourceRefs 返回需要检查的资源引用,匹配的引用将通过visitResourceReference被检查
- visitResourceReference 检查与appliesToResourceRefs匹配的资源引用
- applicableSuperClasses 与 visitClass
- applicableSuperClasses 返回需要检查的父类名列表,此处需要类的全路径名
- visitClass 检查applicableSuperClasses返回的类
标签:Lint,自定义,检查,lint,SdkConstants,FILE,Android From: https://blog.51cto.com/u_16163480/6511345