Android自定义Lint检查有效提高代码质量、避免人工的低级失误、规范代码,属于程序自动化的内容,这部份内容涉及的资料较少,可是实际意义重大,尤为是对有规模的团队而言。node
提示:文中连接须要点击文章末尾处阅读原文才能点击。android

一、 Coding时遇到的问题json
案例1:com.alibaba.fastjson.JSONapi
工程中常常会使用 FastJson 来解析 Json 数据,因为会使用反射机制构造 JavaBean 对象,那么 release 版本混淆的状况下,若是没有对相应的 JavaBean 对象作keep处理的话,JavaBean 没法成功构建,从而出现对象为 NULL 的状况。每每会在临上线的两三天在release包中忽然发现莫名的崩溃、功能失效之类的问题,都是因为这个缘由。形成往往发版本就要加班的窘境。数组
案例2:activity基类安全
因为有一些统计,例如友盟统计活跃的需求,须要在 Activity 中的 OnResume/OnPause 实现某些方法,固然还有不少咱们项目自身的缘由,须要全部工程中的 Activity都要继承自某一个咱们实现的 BaseActivity,若是是个小工程小团队,咱们能够全局搜索一下,按期检查一下,均可以。若是是个十余人甚至更大的团队,每一个版本的需求中都有可能产生新的 Activity,或者在大的工程重构后,可否保证人不会犯错,不会忘记将咱们的 Activity 继承自咱们的 BaseActivity ?微信
案例3:团队的编码规范网络
当一个团队技术负责人认认真真的制订了少许有效的编码规范后,苦口婆心的像是传销似的要求团队成员遵循,难道须要咱们对工程中的每行代码都要 review 吗?培养习惯真的不容易。app
好了,管中窥豹而已,项目中的“非典型技术的技术问题”还有不少是否是?除了自动化咱们就别想期望人来解决。ide
类型1: 若是你根本没据说过 Lint,请赶忙 Google 一下 Android Lint。由于你是一个或者极可能会成为一个技术 Leader,若是到时候要靠人工审核这些,你的麻烦就大了去了;(初级-看一下整个第二大部分)
类型2: 若是你据说过Lint没有使用过,打开你的工程cd到主工程,再 ../gradlew Lint 一下。或者在 AndroidStudio Menu 中点击Analyse -> Inspect Code。由于知识不仅停留在:“啊,我据说过”;(初级-看一下整个第二大部分)
类型3: 若是常用 Google 提供的 Lint,然而没有自定义过 Lint,这篇文章最适合你。由于关于自定义 Custom-Lint 资料很少,我也把好的资料地址都放进来了;
类型4: 若是你是自定义 Lint 高手,联系我 Email,交换一下学习心得,这个最可贵。
版权说明:此部分概念性内容大部分摘抄自网络,并不是原创,地址放在文章最后一部分参考资料中。
Android Lint 是一个静态代码分析工具,它可以对你的 Android 项目中潜在的 bug 、可优化的代码、安全性、性能、可用性、可访问性、国际化等进行检查。Android Lint 内置了不少 Lint 规则,到如今为止是230余项检查,总共能够分为如下几类:
Correctness 正确性
Security 安全性
Performance 性能
Usability 可用性
Accessibility 可访问性
Internationalization 国际化
静态代码分析工具常被用来检测代码中的质量问题或者编码规范问题。Lint 做为最先的静态代码分析工具,已被用来做为静态代码分析工具的代名词。所以,Android SDK 也把其静态代码分析工具取名为 Android Lint。Android Lint 内置了不少 Lint 规则,用来检测一些常见的代码问题(例如,正确性问题、安全问题、性能问题,等等)。同时,Android Lint 也支持自定义 Lint 规则,以便开发者灵活应用,更好地提高项目代码质量。利用自定义 Lint 规则,既能够用来在项目中检测代码质量问题,也能够用来保证编码规范的执行。
更直观的讲,咱们平时代码写的疏漏,Java文件、xml 文件等等写的有问题时,第一时间报警给咱们,编译时报错没法经过,这都是 Lint 在帮咱们作检查。固然,这些检查都是 Google 默认帮咱们写好的。
下面列举一些常见的lint会检测的代码问题:缺乏翻译(和未使用的翻译);
布局性能问题(老的 layout opt 工具会用于查找全部这样的问题,和除此以外更多的问题);
未使用的资源;
不一致的数组大小(当在多个配置中定义数组);
可访问性和国际化问题(硬编码字符串,缺乏 contentDescription 等);
图标问题 (如丢失密度、 重复图标、 错误尺寸等);
可用性问题 (如不在文本字段上指定输入的类型);
清单错误。
Google 提供的默认 Lint 检查很全面可是咱们终归会有不少项目特性、自定义规则没法知足,如开头我提到的几个案例,这时候咱们须要自定义 Lint。另外更深层的问题是要自动化检查取代人工检查的成本,提升生产效率,下降人工低级失误带来的负面影响,这个理论是自从工业革命开始就早已被确认的毋庸置疑了,没什么可争论的,无论自动化过程花费多长时间、多大精力,咱们都要坚持。Google 在 Custom-Lint 上提供了强大的 API 支持咱们,并且更新速度很快,只惋惜相关文档仍是比较少的。
说明:此部分可参见教程:自定义 Lint 规则简介,这里仅罗列大致思路和使用时的备注。
A. Gradle配置包
compile 'com.android.tools.lint:lint-api:25.2.0' compile 'com.android.tools.lint:lint-checks:25.2.0'
至于使用的版本号,你能够查看一下最新的,请务必如此,我以前在写“FastJsonDetector”时,使用的是24.3.1版本,想查看某个类是否实现了某个接口,调查了好久而不得方法,结果发现新版本25.1.0里面新增了“getInterfaces”这个方法。因此但愿你们尽可能使用新版本API。
B. com.android.tools.lint.client.api.IssueRegistry
实现一个继承自此类的子类,他起到的做用是注册你有哪些检查要开放出去在 Lint 过程当中被执行。
另一定注意这个地方,要在 Gradle 配置上他才能够。
jar { manifest { attributes('Lint-Registry': 'com.qjoy.LFIssueRegistry') } }
C. Detector 实例+ XXXScanner 接口
继承 Detector 并选择 Detector 中合适的 XXXScanner 接口来实现。在这里根据自身业务需求,实现各类自定义探测器(Detector ),并定义各类 issue,根据自身需求的不一样这样的类能够有一个或多个。
其中,com.android.tools.lint.detector.api.Detector 提供了7种 XXXScanner 接口。
另外,利用 Context(此处的 Context 是 Lint 检查的类,不是 Android 的那个)的 report 方法报警,就会在错误日志中产生一条记录啦。
怎么样,是否是足够强大,检查全部你能想到的。
每种 XXXScanner 接口功能说明:
JavaScanner 功能:Specialized interface for detectors that scan Java source file parse trees
ClassScanner 功能:Specialized interface for detectors that scan Java class files
BinaryResourceScanner 功能:Specialized interface for detectors that scan binary resource files
ResourceFolderScanner 功能:Specialized interface for detectors that scan resource folders (the folder directory itself, not the individual files within it)
XmlScanner 功能:Specialized interface for detectors that scan XML files
GradleScanner 功能:Specialized interface for detectors that scan Gradle files
OtherFileScanner 功能:Specialized interface for detectors that scan other files
说明:最好看一下源码: GitHub follow&star。
咱们选择两个咱们实现的Detector简单分析一下,其他的请查看源代码吧:
目标:类是否继承自 LFBaseActivity 或者 LFBaseAppCompatActivity。
public class BaseActivityDetector extends Detector implements Detector.JavaScanner { ...省略非核心代码... public AstVisitor createJavaVisitor(JavaContext context) { return new ForwardingAstVisitor() { @Override public boolean visitClassDeclaration(ClassDeclaration node) { ...核心代码... 在这里分析node,检查经过或者报警 } } }
因为是扫描 Java 代码内容,咱们实现 JavaScanner,利用createJavaVisitor 接口的 visitClassDeclaration 扫描内容。
这里咱们使用一个递归方法recursiveSupperClass
查看父类,追溯直到checkActivityRules
发现继承了 LFBaseActivity/LFBaseAppCompatActivity,或者直到发现直接继承了 Activity/AppCompatActivity,或者直接继承了 Object (说明他根本不是 Activity )。
目标:检查图片文件尺寸是否超过某个限定的大小。
public class ImageFileSizeDetector extends Detector implements Detector.BinaryResourceScanner { ...省略非核心代码... @Override public boolean appliesTo(ResourceFolderType var1) { return var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.MIPMAP)) || var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.DRAWABLE)); } @Override public void checkBinaryResource(ResourceContext context) { String filename = context.file.getName(); ...核心代码... 在这里分析node,检查经过或者报警 } }
因为是扫描二进制资源,咱们实现 BinaryResourceScanner,利用 BinaryResourceScanner 接口的 checkBinaryResource 扫描内容。
经过 ResourceContext 能够获取文件信息,用来作咱们判断的条件。
最后,让咱们看看执行效果吧:
官方文档:lint-api 25.1.0版本
没有什么比读官方api文档更高效的方法了,这里看看官方最新的版本是什么,以后替换链接中的25.1.0查看最新的文档。
GitHub-AndroidDevNotes
构建自定义lint检查整个工程什么样的结构;
教程:自定义 Lint 规则简介
美团app-lint实现方案
google实现好的lint检查源代码
a11n-android-lint
英文原文的;
Github-yongce/AndroidArch
不错的实例程序;
教程-Android Lint
全面而系统讲了原理相关知识,应该是目前能搜索到的最高级的资料了。
工程源码托管在 GitHub follow&star。
本文由原做者薛晴独家受权Open软件开发小组发布,著做权归原做者全部。如需转载请联系原做者申请受权。
申请加群交流学习请加主编微信:Jf-1994(井方哥),并备注:姓名-地区-公司-职业-加群。
专一Android开发,欢迎关注open_dev!
本文分享自微信公众号 - Open软件开发小组(open_dev)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。