先来段developer的官方引用:html
Android Studio provides a code scanning tool called Lint that can help you to easily identify and correct problems with the structural quality of your code, without having to execute the app or write any test cases.java
该图诠释了Lint工具是如何检测应用源代码的:android
做为移动应用开发者,咱们总但愿发布的apk文件越小越好,不但愿资源文件没有用到的图片资源也被打包进apk,不但愿应用中使用了高于minSdk的api,也不但愿AndroidManifest文件存在异常,lint就能解决咱们的这些问题。git
Android Lint是Google提供给Android开发者的静态代码检查工具。使用Lint对Android工程代码进行扫描和检查,能够发现代码潜在的问题,提醒程序员及早修正。程序员
为保证代码质量,美团在开发流程中加入了代码检查,若是代码检测到问题,则没法合并到正式分支中,这些检查中就包括Lint。github
其余博客就不一一列举了。api
再来段官方文档:数组
The Lint tool checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. You can run Lint from the command-line or from Android Studio.app
简要来讲:maven
布局性能(之前是 layoutopt工具,能够解决无用布局、嵌套太多、布局太多)
未使用到资源
不一致的数组大小
国际化问题(硬编码)
图标的问题(重复的图标,错误的大小)
可用性问题(如不指定的文本字段的输入型)
manifest文件的错误
内存泄露 --- 如:handle的不当使用 。
占内存的资源及时回收 --- 如:cursor未关闭等
Lint检查的配置文件,该文件即为你修改的某些Lint配置项,其须要在对应模块的根目录,Lint Tool会自动扫描模块目录下是否有对应的lint配置文件。
该lint文件以下所示:
其中severity是严重级别:error,ignore,warning。注意其也能够只指定部分文件
@SuppressLint
注解,其容许在任何地方定义,如在方法体上定义,则忽略该方法体的Lint检测。@SuppressLint("NewApi")
最为常见,@SuppressLint("all")
意为忽略全部规则。
在xml文件,首先引入:
namespace xmlns:tools="http://schemas.android.com/tools"
简单介绍下tool,用于告知as,哪些属性可被忽略,只在设计布局时有效:
Lint提示。tools:ignore = "contentDescription"
意为忽略lint的imageview的contentDescription属性,该属性用于视力障碍者。
预览布局。
tools:text
如某控件在Java代码层动态设置text属性,而你须要看预览效果,一般会设置 android:text="I am a title"
,等预览完毕再进行删除,使用tools,则彻底达到预览效果。
tools:context
预览布局时,ide可知采用哪一种主题,还可Go to Related files。
具体tools分析:android中xml tools属性详解
分析了那么多,意在说明Lint工具的重要性,那么下一阶段则是如何在as中使用,以及配置,以及结合公司代码进行项目检查。
Analyze”菜单中选择“Inspect Code”,其中能够选择scope,即检测范围,也能够选择不一样的检测配置,咱们先进行默认的配置检测吧。检测须要必定的时间,结果会在EventLog显示:
能够看到,咱们的项目有不少问题,好比我选择了Correctness中的Using dp instead of sp for text sizes属性,发现应用中有2处在textSize中误用了dp,其给出了类的具体位置和解决方案。可能你以为这些无关大雅,那么能够查看Probable bugs项,在其中找到一项 String comparison using '==',instead of 'equals()',能够看到SecurityBankCardListActivity类中的有一行代码:
this.mBankCard.getCardId() == mBankCard.getCardId()//cardId为String类型
在此就不一一列举。
可能你会以为Lint分析的太过详细,我没法迅速找到问题,那么你能够点击,其分为四类,咱们应只关注前2类。
运行gradle lint
,而后在app/build/outputs打开lint-results.xml
打开设置对话框,找到Editor,而后是Inspections,选择某一个Lint选项,修改严重等级,如图:
gradle中的Android插件的lintOptions,具体lintOptions属性,可参照官方文档
咱们在实际使用Lint中遇到了如下问题:
原生Lint没法知足咱们团队特有的需求,例如:编码规范。
原生Lint存在一些检测缺陷或者缺乏一些咱们认为有必要的检测。
基于上面的考虑,咱们开始调研并开发自定义Lint。
那咱们的项目须要自定义Lint吗,我以为颇有必要,举几个例子:
咱们有MuLog模块,可是仍然有开发同事会使用android自带的Log工具类或java的System.out.print,显然咱们应该能够选择强制开发同事调用MuLog,若是调用Log等,编译器会报错等提示。
加强HashMap检测,Lint检测中有一项是Java性能检测,常见的就是:HashMap can be replaced with SparseArray。例以下面代码,原生Lint只能检测第一种状况。
public static void testHashMap() { HashMap<Integer, String> map1 = new HashMap<Integer, String>(); map1.put(1, "name"); HashMap<Integer, String> map2 = new HashMap<>(); map2.put(1, "name"); Map<Integer, String> map3 = new HashMap<>(); map3.put(1, "name"); }
Intent携参,activity页面间的跳转须要intent,而须要传输数据时,须要extra,对应的该extra都须要一个key,该key应该是跳转类中的命名常量,而不是写死在putExtra("key","value")
里,咱们能够强制开发同事Intent携参的key必须为按照EXTRA_<name>格式命名的常量。
好比Android因为性能的缘由应该尽可能减小或避免使用枚举。
好比线程的建立不该该是简单的new Thread,而是应该使用同一的全局的线程池。
参看美团自定义Lint实践文章,具体流程以下所示:
http://tools.android.com/tips...
根据该文章,将写好的jar拷贝到android/lint文件夹下,再下一次运行IDE时,IDE会检测其内的jar文件。
缺点:开发人员的机器上全部的Android工程都会受到影响,并且每一个开发人员间的拷贝成本大。
https://engineering.linkedin....
LinkedIn提供了另外一种思路 : 将jar放到一个aar中。这样咱们就能够针对工程进行自定义Lint,lint.jar只对当前工程有效。
aar文件中放入lint.jar是可选的。该lint.jar将会经过app的lint task被执行。
因此咱们选择该方案。
aar虽然很方便,可是在团队内部推广起来,依然很困难。
配置繁琐,不易推广。每一个库都须要自行配置lint.xml、lintOptions,而且compile aar。
不易统一。各库之间须要使用相同的配置,保证代码质量。但如今手动来回拷贝规则,且配置文件能够本身修改。
因而咱们想到开发一个plugin,统一管理lint.xml和lintOptions,自动添加aar。
集成了原生lint和自定义lint的全部检查规则
内置lintOptions(全部warning视为error,只输出htmlReport到${project.projectDir}/lint-report/lint-report.html)和 lint.xml。集成此插件后,原有配置会被覆盖,没有配置的也会执行插件中的配置
此处错误,仅仅是IDE提示开发人员须要进行修改,其仍然能够提交该代码并运行该代码。
建立lint的java项目,包含的是自定义的lint规则
建立lint的library项目,仅用来输出包含lint.jar的aar
建立Android项目,用来测试自定义lint规则
建立groovy项目,用于生产plugin
svn的pre-commit如何进行触发lint检查,以便开发人员每次提交代码时,都会启动lint检查提交的代码是否包含自定义Error,并拒绝其提交该代码。
project中的build.gradle文件的buildscript的dependencies中添加:
classpath 'com.mucfc.muna.lint:plugin:latest.integration'
在module中,如muapp中添加:
apply plugin: 'MTLintPlugin'
上述代码完成后,全部的开发人员当编写相关的代码时,如Log.d()都会出现错误提示,并且不会影响项目。
现阶段,我已经上传到公司maven库的有:plugin和aar。因此若是项目引用该plugin,则针对业务须要能够逐渐扩展该lint规则。
svn的提交前代码检查脚本。
美团技术:Android自定义Lint实践
LinkedIn Engineering:Writing Custom Lint Checks with Gradle
Google关于lint.jar:AAR Format
Google blog:Writing a Lint Check
yongce-AndroidDevNotes:自定义Android Lint规则