前言

以前对下面的问题,我的态度是,不报错就是没问题,报错就用快捷键,根据Android Studio提示修复问题,从来不去问个为什么?现在代码洁癖症越来越严重的我,忍不住想看清什么东西在搞鬼。

认真看完本文,一定可以学到最新的知识。就算看不下去,也要点个赞收藏,绝对不亏。本文并不是吐槽Lint的不好,而是在学习Lint过程碰到问题,心态是奔溃的,以及解决每个问题带来的喜感。

不知道大家有没有注意项目中黄色代码块的提示,如下图所示:

或者红色标记的代码(并没有任何错误),如下图所示:


上文黄色的提醒和红色警告,都是来自Android Studio内置的Lint工具检查我们的代码后而作出的动作。
通过配置Lint,也可以消除上面的提醒。例如,我开发系统APK,根本不需要考虑用户是否授权。
那么Lint是什么呢?

Lint

Android Studio 提供一个名为Lint的静态代码扫描工具,可以发现并纠正代码结构中的质量问题,而无需实际执行该应用,也不必编写测试用例。
Lint 工具可检查您的 Android 项目源文件是否包含潜在错误,以及在正确性、安全性、性能、易用性、便利性和国际化方面是否需要优化改进。

也就是说,通过Lint工具,我们可以写出更高质量的代码和代码潜在的问题,妈妈再也不用担心我的同事用中文命名了。也可以通过定制Lint相关配置,提高开发效率。

Lint禁止检查

由于Android Studio内置了Lint工具,好像不需要我们干嘛。可是呀,我有强迫症,看着上面的黄色块,超级不爽的。所以我们得了解如何配置Lint,让它为我们服务,而不是为Google服务。

本文开始的红色错误可以通过注解来消除(一般建议是根据提示进行修正,除非明白自己在做什么),可以在类或该代码所在的方法添加@SuppressLint


上图中是禁止Lint检查特定的问题检查,如果要禁止该Java文件所有的Lint问题,可以在类前添加如下注解:@SuppressLint(all)
对XMl文件的禁止,则可以采用如下形式:

  1. 在lint.xml声明命名空间
namespace xmlns:tools="http://schemas.android.com/tools"
  1. 在布局中使用:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"tools:ignore="UnusedResources" ><TextViewandroid:text="@string/auto_update_prompt" />
</LinearLayout>

父容器声明了ignore属性,那么子视图会继承该属性。例如上文LinearLayout中声明了禁止Lint检查LinearLayout的UnusedResources问题,TextView自然也禁止检查该问题。禁止检查多个问题,问题之间用逗号隔开;禁止检查所有问题则使用all关键字。

tools:ignore="all"

我们也可以通过配置项目的Gradle文件来禁止检查。

例如禁止Lint检查项目AndroidManifest.xml文件的GoogleAppIndexingWarning问题。在项目对应组件工程的Gradle文件添加如下配置,这样就不会有黄色提醒了。

defaultConfig{lintOptions {disable 'GoogleAppIndexingWarning'}
}

那么,可以禁止lint工具检查什么问题?

配置Lint

在上文中通过注解和在xml使用属性来禁止Lint工具检查相关问题,其实已经是对Lint的配置了。Lint将多个问题归为一个issue(规则),例如下图右边的的六大规则。


上图是Lint工具的工作流程,下面了解相关概念。
App Source Files
源文件包含组成 Android 项目的文件,包括 Java 和 XML 文件、图标和 ProGuard 配置文件等。
lint.xml 文件
此配置文件可用于指定您希望排除的任何 Lint 检查以及自定义问题严重级别。
lint Tool
我们可以通过Android Studio 对 Android 项目运行此静态代码扫描工具。也可以手动运行。Lint 工具检查可能影响 Android 应用质量和性能的代码结构问题。
Lint 检查结果
我们可以在控制台(命令行运行)或 Android Studio 的 Inspection Results 窗口中查看 Lint 检查结果。

通过Lint工具的工作流程了解到,可以在lint.xml文件配置一些信息。一般新建项目都是没有lint.xml文件的,在项目的根目录创建lint.xml文件。格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<lint><!-- list of issues to configure -->
</lint>

那么有哪些Issues(规则)呢?

在Android主要有如下六大类:

  • Security 安全性。在AndroidManifest.xml中没有配置相关权限等。
  • Usability 易用性。重复图标;上文开始黄色警告也属于该规则等。
  • Performance 性能。内存泄漏,xml结构冗余等。
  • Correctness 正确性。超版本调用API,设置不正确的属性值等。
  • Accessibility 无障碍。单词拼写错误等。
  • Internationalization国际化。字符串缺少翻译等。

其他更多Issues,可以通将命令行切换到…/Android/sdk/tools/bin目录下,然后输入lint --list。例如在Mac下:
cd /Users/gitcode8/Library/Android/sdk/tools/bin输入./lint --list
结果如下:

例如官网提供的参考例子:

<?xml version="1.0" encoding="UTF-8"?>
<lint><!-- 忽略整个工程目录下指定问题的检查 --><issue id="IconMissingDensityFolder" severity="ignore" /><!-- 忽略对指定文件指定问题的检查 --><issue id="ObsoleteLayoutParam"><ignore path="res/layout/activation.xml" /><ignore path="res/layout-xlarge/activation.xml" /></issue><!-- 更改检查问题归属的严重性  --><issue id="HardcodedText" severity="error" />
</lint>

学习Lint工具仅仅是为了安抚我的强迫症?不,还不知道Lint真正用来干嘛呢?

检查项目质量

不好容易开发了个APP,准备开始上班摸鱼了。还让代码自查?那就通过Lint来看看代码质量如何吧。

  1. 通过Android Studio 的菜单栏Analyze选项下拉选择第一个选项Inspect Code.


2、在弹出框根据自己需要选择lint工具的检查范围,这里选择整个项目。检查时间也是根据项目大小来定的。


3、等待一段时间后,会列出检查结果。从下图看到,不仅会检查Android存在的问题,也会检查Java等其他问题。通过单击问题,可以从右边提示框看到问题发生的地方和相关建议。


到这里,就开始对项目修修补补吧。

自定义规则

为什么要自定义呢?已有规则不符合自己或团队开发需求,或者觉得Lint存在一些缺陷。在网上大多数文章千篇一律,都是通过将Log打印来举例,看着都好累哦。由于没有相关官方文档和第三方教程(可能由于lint的api更新太快,没人愿意做这种吃力不讨好的工作),也这就只有这样了。本文通过自定义命名规范规则来讲解整个过程。

Lint中重点的API

先学习相关api,可以快速理解一些概念,可以粗略看过,下结实践再回来看。

1、Issue

Issue如上文所说,表示lint 工具检查的一个规则,一个规则包含若干问题。常在Detector中创建。下文是创建一个Issue的例子。

   private  static final Issue ISSUE = Issue.create("NamingConventionWarning","命名规范错误","使用驼峰命名法,方法命名开头小写,类大写字母开头",Category.USABILITY,5,Severity.WARNING,new Implementation(NamingConventionDetecor.class,EnumSet.of(Scope.JAVA_FILE)));
  • 第一个参数id 唯一的id,简要表面当前提示的问题。
  • 第二个参数briefDescription 简单描述当前问题
  • 第三个参数explanation 详细解释当前问题和修复建议
  • 第四个参数category 问题类别,例如上文讲到的Security、Usability等等。
  • 第五个参数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、IssueRegistry

用于注册要检查的Issue(规则),只有注册了Issue,该Issue才能被使用。例如注册上文的命名规范规则。

public class Register extends IssueRegistry {@NotNull@Overridepublic List<Issue> getIssues() {return Arrays.asList(NamingConventionDetector.ISSUE);}
}

4、Detector

查找指定的Issue,一个Issue对应一个Detector。自定义Lint 规则的过程也就是重写Detector类相关方法的过程。具体看下小结实践。

5、Scanner

扫描并发现代码中的Issue,Detector需要实现Scaner,可以继承一个到多个。

  • UastScanner 扫描Java文件和Kotlin文件
  • ClassScanner 扫描Class文件
  • XmlScanner 扫描Xml文件
  • ResourceFolderScanner 扫描资源文件夹
  • BinaryResourceScanner 扫描二进制资源文件
  • OtherFileScanner 扫描其他文件
  • GradleScanner 扫描Gradle脚本

旧版本的JavaScanner、JavaPsiScanner随着版本的更新已经被UastScanner替代了。

自定义Lint规则实践

通过实现命名规范Issue来熟悉和运用上小节相关的api。自定义规则需要在Java工程中创建,这里通过Android Studio来创建一个Java Library。

步骤:File->New->New Mudle->Java Library

这里Library Name为lib。

定义类NamingConventionDetector,并继承自Detector。因为这里是检测Java文件类名和方法是否符合规则,所以实现Detector.UastScanner接口。

public class NamingConventionDetector extends Detector implements Detector.UastScanner {
}

在NamingConventionDetector类内定义上文的Issue:

public class NamingConventionDetector extends Detector implements Detector.UastScanner {public static final Issue ISSUE = Issue.create("NamingConventionWarning","命名规范错误","使用驼峰命名法,方法命名开头小写",Category.USABILITY,5,Severity.WARNING,new Implementation(NamingConventionDetector.class,EnumSet.of(Scope.JAVA_FILE)));
}

重写Detector的createUastHandler方法,实现我们自己的处理类。

public class NamingConventionDetector extends Detector implements Detector.UastScanner {//定义命名规范规则public static final Issue ISSUE = Issue.create("NamingConventionWarning","命名规范错误","使用驼峰命名法,方法命名开头小写",Category.USABILITY,5,Severity.WARNING,new Implementation(NamingConventionDetector.class,EnumSet.of(Scope.JAVA_FILE)));//返回我们所有感兴趣的类,即返回的类都被会检查@Nullable@Overridepublic List<Class<? extends UElement>> getApplicableUastTypes() {return Collections.<Class<? extends UElement>>singletonList(UClass.class);}//重写该方法,创建自己的处理器@Nullable@Overridepublic UElementHandler createUastHandler(@NotNull final JavaContext context) {return new UElementHandler() {@Overridepublic void visitClass(@NotNull UClass node) {node.accept(new NamingConventionVisitor(context, node));}};}//定义一个继承自AbstractUastVisitor的访问器,用来处理感兴趣的问题public static class NamingConventionVisitor extends AbstractUastVisitor {JavaContext context;UClass uClass;public NamingConventionVisitor(JavaContext context, UClass uClass) {this.context = context;this.uClass = uClass;}@Overridepublic boolean visitClass(@org.jetbrains.annotations.NotNull UClass node) {//获取当前类名char beginChar = node.getName().charAt(0);int code = beginChar;//如果类名不是大写字母,则触碰Issue,lint工具提示问题if (97 < code && code < 122) {context.report(ISSUE,context.getNameLocation(node),"the  name of class must start with uppercase:" + node.getName());//返回true表示触碰规则,lint提示该问题;false则不触碰return true;}return super.visitClass(node);}@Overridepublic boolean visitMethod(@NotNull UMethod node) {//当前方法不是构造方法if (!node.isConstructor()) {char beginChar = node.getName().charAt(0);int code = beginChar;//当前方法首字母是大写字母,则报Issueif (65 < code && code < 90) {context.report(ISSUE, context.getLocation(node),"the method must start with lowercase:" + node.getName());//返回true表示触碰规则,lint提示该问题;false则不触碰return true;}}return super.visitMethod(node);}}
}

上文NamingConventionDetector类,已经是全部代码,只检查类名和方法名是否符合驼峰命名法,可以根据具体需求,重写抽象类AbstractUastVisitor的visitXXX方法。

如果处理特定的方法或者其他,也可以使用默认的处理器。重写Scanner相关方法。例如:

 @Override
public List<String> getApplicableMethodNames() {return Arrays.asList("e","v");
}

表示e(),v()方法会被检测到,并调用visitMethod()方法,实现自己的逻辑。

    @Overridepublic void visitMethod JavaContext context,  JavaElementVisitor visitor,  PsiMethodCallExpression call, PsiMethod method) {//todo somethingsuper.visitMethod(context, visitor, call, method);}

接下来就是注册自定义的Issue:

public class Register extends IssueRegistry {@NotNull@Overridepublic List<Issue> getIssues() {return Arrays.asList(NamingConventionDetector.ISSUE);}
}

在lib项目的build.gradle文件添加相关代码:

apply plugin: 'java-library'dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.tools.lint:lint-api:26.4.2'implementation 'com.android.tools.lint:lint-checks:26.4.2'}
//添加如下代码
jar {manifest {attributes 'Lint-Registry': 'com.gitcode.lib.Register'}
}sourceCompatibility = "7"
targetCompatibility = "7"

到这里就自定义Lint自定义规则就搞定了,接着是使用和确定规则是否正确。

使用自定Lint规则

使用自定义Lint规则有两种形式:jar包和AAR文件。

jar形式使用

在Android Studio的Terminal输入下面命令:

./gradlew lib:assemble

看到BUILD SUCCESSFUL则表示生成jar包成功,可以在下面路径找到:

lib->build->libs

如图:


将lib.jar拷贝下面目录:

~/.android/lint/

如果lint文件夹不存在,则创建。通过命令行输入lint --list。滑到最后可以看到配置的规则,如图:


重启Android Studio,让规则生效。
检测到方法大写,不符合命名规范,报导该问题。

类名不符合规范:


从上文可以看到,放在目录下的jar包对所有工程都是有效的。如果要针对单个工程,那么就需要需要AAR形式了。

AAR形式

在同个工程新建一个Android Library,名为lintLibrary,修改相关配置。

1、修改Java工程的依赖

修改自定义lint规则的Java库的build.gradle(这里是上文的Java lib库),注意到要将implementation改为compileOnly。

apply plugin: 'java-library'dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])//将implementation改为compileOnly,不然报错compileOnly 'com.android.tools.lint:lint-api:26.4.2'compileOnly 'com.android.tools.lint:lint-checks:26.4.2'}jar {manifest {attributes 'Lint-Registry-v2': 'com.gitcode.lib.Register'}
}sourceCompatibility = "7"
targetCompatibility = "7"
2、修改Android Library依赖

Android Library主要用来输出AAR文件,要注意到Android Studio新特性的变更(在这里踩了大坑)。

dependencies {......lintPublish project(':lib')
}

在Android Studio 3.4+,lintChecks project(':lib'):lint检查只在当前工程生效,也就是Android Library,并不会打包到AAR文件中。lintPublish project(':lib')才会将lint检查包含AAR文件中。

3、输出AAR文件

此时跟输出普通的AAR文件没什么区别,但为了手把手教会第一个自定义Issue,我写!

步骤:

菜单栏:View->Tool Windows->Gradle

此时Android Studio在右边会打开如下窗口:


根据上图操作,双击assemble,稍等一会,在控制台看BUILD SUCCESSFUL,则可在下面目录找到AAR文件。

lintLibrary->build->outputs->aar

这一小节的步骤也可以通过命令行执行。

4、使用AAR文件

有本地依赖或者上传远程仓库,这里只介绍本地依赖。将上小结生成的AAR文件拷贝在app的libs文件夹。并配置app组件的build.gradle

repositories {flatDir {dirs 'libs'}
}
dependencies {implementation (name:'lintlibrary-release', ext:'aar')
}

到这里,就能使用自定义的lint规则了,效果和上面使用jar包是一致的。如果不生效,重启Android Studio看看。

采坑记

1、Found more than one jar in the ‘lintChecks’ configuration. Only one file is supported

这是因为在输出AAR文件中,参考其他人的文章。没有将Java Library的依赖改为compileOnly。而且Android Library中使用lintChecks

2、输出AAR文件没有生效

不知道为什么,Linkedin的参考文章没有生效,可能是Android Studio版本的问题。

另外使用lintChecks输出AAR不生效,Android Studio 3.4+新特性变更,采用lintPublish(AGP 3.4+)。

总结

花了好长好长的时间写本文,差点就放弃了。因为自己Android Studio看不了lint的源码,只能从网上找,网上又找不到最新的doc。过滤太多雷同文章,差点想哭,一些最新的文章也跟不上相关技术的更新。。。

但是一切都值得,因为能帮助到想学习Android Studio lint工具的同学,一起向往美好的生活。

GitHub

点个赞行不

写此文找到的一些具有参考意义的文章:

Android 官方指导

Linkedin 指导

美团->Android自定义Lint实践

lint-custom-rules

另外:本文没有demo,demo的代码已经贴在文章里了。

Android Studio Lint 工具看完这一篇还不够相关推荐

  1. android studio lint,Android Studio Lint 工具

    Android Studio 报错信息 FAILURE: Build failed with an exception. * What went wrong: Execution failed for ...

  2. Android Studio lint工具所提示的需要注意的内容简要记录

    Android lint部分: Duplicated icons under different names 相同的icon 用了不同的名字 FrameLayout can be replaced w ...

  3. flutter图标按钮_Flutter开发第一个项目android studio 开发工具的使用说明

    Flutter开发第一个项目android studio 开发工具的使用说明 做个自我介绍 自我介绍还是有必要介绍一下的,毕竟这是网络里,你看不到我,我看不到你,只能通过文字来传递信息,本人做技术8年 ...

  4. 【Android 应用开发】Ubuntu 下 Android Studio 开发工具使用详解 (旧版本 | 仅作参考)

    . 基本上可以导入项目开始使用了 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21035637 ...

  5. android studio spellchecker,Exclude files from Android Studio lint spell checker

    问题 The Android Studio lint spell checker flags hex codes that look to it like words in certain files ...

  6. android studio开发工具遇到一个新问题一直卡indexing paused due to batch update不停的转

    3.2.1以上版本的android studio开发工具遇到一个新问题一直卡indexing paused due to batch update不停的转 解决方法有一下两种方式: 1.第一种解决方式 ...

  7. 无线智能插座Android Studio开发工具下载安装

    该无线智能插座Android Studio开发工具的下载和安装,接下来将进行详细的介绍说明. (1)Android Studio开发工具下载 首先Android Studio开发工具的安装包下载链接为 ...

  8. 分享一波关于做Kaggle比赛,Jdata,天池的经验,看完我这篇就够了。

    @Author : Jasperyang @School : BUPT 这篇文章同时在知乎里放着- 写在前面 Kaggle的数据挖掘比赛近年来很火,以至于中国兴起了很多很多类似的比赛,做了两个这种类型 ...

  9. 别在问PMP和ACP哪个更有用了,看完这一篇你就知道!

    别在问PMP和ACP哪个更有用了,看完这一篇你就知道. 老原很多粉丝和学员在我的后台问我: 要不要考PMP和ACP? PMP和ACP的区别是啥? PMP.ACP证书考哪个更有用?还是两个都考? PMP ...

最新文章

  1. [名词解释] intuitive
  2. 传奇霸业维护服务器,37传奇霸业8月18日部分区服维护计划
  3. java网络io_彻底搞懂Java的网络IO
  4. P2872 [USACO07DEC]Building Roads S(最小生成树)
  5. 掌握SpringAOP
  6. win7 64位MMC管理控制台使用“远程桌面”
  7. C# winform程序运行在XP
  8. linux下默认分区system的id,Linux学习笔记之系统中的分区和文件系统
  9. Python调用百度地图api查询经纬度
  10. 【《Real-Time Rendering 3rd》 提炼总结】(五) 第六章 · 纹理贴图及相关技术 The Texturing
  11. SMAP数据产品介绍与下载方法
  12. 基于C++实现(WinForm)家谱管理系统【100010033】
  13. 【开源】SoDiaoEditor 可能是目前最好用的开源电子病历编辑器(B/S架构)
  14. 机器人瓦力漫威_漫威归来的发明家
  15. 四步教你用网站源码建站
  16. wordpress企业网站主题仿制02-wordpress企业网站首页的仿制
  17. Paint画笔及Color
  18. .gitignore git忽略文件
  19. 无法删除文件夹,目录不是空的或U盘文件无法删除的解决办法
  20. iOS混淆--OLLVM在iOS中的实践(Xcode9.2)

热门文章

  1. Oracle X$BH
  2. spin_lock_bh使用
  3. 通过实例理解Go Execution Tracer
  4. 虚拟化 oracle rac,数据库虚拟化之战:VM与Oracle RAC
  5. Vue3官网-高级指南(十五)Vue 与 Web Components
  6. win10中文字符乱码解决方案
  7. Celery (1)- 安装配置及使用
  8. 猫狗二分类实战(PyTorch)
  9. OpenMP 快速入门
  10. LINE开发(二)开发LINE Notify 创建服务篇