更新时间:2016-04-02
Android 的 Lint 工具是一种静态的代码检查工具,作为 SDK Tools (版本号 >= 16)的一部分自动安装,用于帮助发现潜在的 BUG ,提高代码的兼容性和性能。 在 Android Studio 中,可以点击 Analyze > Inspect Code 运行。正是 Lint 这一点,在我第一次接触 Android Studio 时,觉得不可思议的好用。 效果图:
另外,要是觉得提示的程度太显眼了,你可以点击 Android Studio 右下角的老头:
当需要关闭 Lint 时, 可使用 annotation 和 attribute 来设置。
@SuppressLint("all")
// 进行关于 “NewApi” 的检查时忽略 onCreate() 方法
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//...
}
tools:ignore="all"
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<!--忽略两个以上的检查-->
tools:ignore="UnusedResources,NewApi" >
<TextView
android:text="@string/auto_update_prompt" />
</LinearLayout>
另一个方式是通过在设置项中的 lint.xml 文件。如果是自己手动添加的,需要将 lint.xml 文件放置到项目的根目录下;在 Android Studio 中会自动添加。
lint.xml 文件以 lint 为父节点,包含多个 issue 子节点,每个 issue 有一个唯一的 id 属性。 举个栗子:
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- 关闭在这个工程所给定的检查 -->
<issue id="IconMissingDensityFolder" severity="ignore" />
<!-- 忽略 ObsoleteLayoutParam issue 在相应的文件中 -->
<issue id="ObsoleteLayoutParam">
<ignore path="res/layout/activation.xml" />
<ignore path="res/layout-xlarge/activation.xml" />
</issue>
<!-- 忽略 UselessLeaf issue 在相应的文件中 -->
<issue id="UselessLeaf">
<ignore path="res/layout/main.xml" />
</issue>
<!-- 将 硬编码 String 的严重程度提升为 "error" -->
<issue id="HardcodedText" severity="error" />
</lint>
现在 Android Studio 已经自带超过 200 条的检查。但有时候我们需要添加自己的 Lint 规则。 每个 Link 都包含以下四个部分:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.tools.lint:lint-api:24.5.0'
compile 'com.android.tools.lint:lint-checks:24.5.0'
}
lint-api :官方给出的 API ,不过不是最终版,官方提醒随时都有可能改变接口。
lint-checks :已有的检查
一个简单的例子:
public class MyDetector extends ResourceXmlDetector {
public static final Issue ISSUE = Issue.create(
"MyId",
"My brief summary of the issue",
"My longer explanation of the issue",
Category.CORRECTNESS, 6, Severity.WARNING,
new Implementation(MyDetector.class, Scope.RESOURCE_FILE_SCOPE));
@Override
public Collection<String> getApplicableElements() {
return Collections.singletonList(
"com.google.io.demo.MyCustomView");
}
@Override
public void visitElement(XmlContext context, Element element) {
if (!element.hasAttributeNS(
"http://schemas.android.com/apk/res/com.google.io.demo",
"exampleString")) {
context.report(ISSUE, element, context.getLocation(element),
"Missing required attribute 'exampleString'");
}
}
}
其中 Implementtation 包括两个部分:
// 针对 Java 文件的检查
public class JavaDetector extends Detector implements Detector.JavaScanner {}
Lint 使用了 Lombok 做抽象语法树的分析,而不是一行一行代码地去找。所以在我们需要告诉它所需的类型后, 它就会把相应的 Node 返回给我们。
Issue 部分包含:
public static final Issue ISSUE = Issue.create(
ISSUE_ID, // 唯一的标识符,不能为 null
ISSUE_DESCRIPTION, // 简略描述
ISSUE_EXPLANATION, // 详细描述
ISSUE_CATEGORY, // 类别名
ISSUE_PRIORITY, // 优先级[1,10],数字越大越重要
ISSUE_SEVERITY, // 严重程度,一般为 WARNING :程序还能继续运行,还有 Fatal,ERROR,Informational, Ignore 可选择
IMPLEMENTATION // 前面讲过的
);
最后需要注册,本例中只有 Mydetector.ISSUE 这一个。
public class MyIssueRegistry extends IssueRegistry {
public MyIssueRegistry() {
}
@Override
public List<Issue> getIssues() {
return Collections.singletonList(
MyDetector.ISSUE
);
}
}
在 getIssue() 方法中返回需要被检测的 Issue List。 在 Build.gradle 中补充声明 Lint-Registy 属性
jar {
manifest {
attributes("Lint-Registry": "包名.MyIssueRegistry")
}
}
自定义Lint是一个Java工程,那么打出的jar包如何使用呢?以下介绍两种方案:
$ mkdir ~/.android/lint/
$ cp customrule.jar ~/.android/lint/
缺点:针对所有工程,会影响同一台机器其他工程的 Lint 检查。即使触发工程时拷贝过去,执行完删除,但其他进程或线程使用 ./gradlew lint 仍会受到影响。
本文写得比较简略,要是细节进一步了解可以去看下文末的“参考”。
Lint 还支持通过命令行来执行,感兴趣的可以去看看:传送门
参考: