By the end of this article you should be able to write your first Android lint rule. But first …

What is lint?

Lint is a static analyser, which has the goal of finding bugs on our source code without the need of compiling or running it.

And even if you are not totally sure what I am talking about, you have definitely seen it in action during your Android development work. Are this type of messages familiar to you?

If so, you saw Lint in Action!

We can then understand the power of these rules, and how they can help developers to quickly identify and fix bugs in a systematic way.

However, the default set of lint rules is limited and in some situations we could benefit from creating custom rules that identify issues that are specific to our projects. We will now go over the process of creating and integrating a Lint rule.

Creating your rules module

We start off by defining a separate Java/Kotlin module where our rules will be declared. This module is the rules module. We then go to the rules/build.gradle and add the following dependencies:

dependencies {

compileOnly "com.android.tools.lint:lint-api:lint-version"

compileOnly "com.android.tools.lint:lint-checks:lint-version"

}

Important: For historical reasons, your lint version should correspond to the Android Gradle Plugin version + 23. This is, if your AGP is 3.5.1, then your lint version should be 26.5.1

In order to integrate our custom rules with the app module, we then add the following to our app/build.gradle :

dependencies {

...

lintChecks project(path: ':rules')

}

This way, the lint rules existing in the rules module will be compiled into the final lint.jar that your app uses.

Issues and Detectors

After the initial setup, we can now look into how to actually write custom Lint rules. For that we need to understand two fundamental concepts: Issues and Detectors.

What is an Issue?

As per the documentation, an Issue is a potential bug in an Android application. It is the way you declare the bug your rule should tackle.

An issue has the following base structure:

id — in order to identify uniquely this issue

— in order to identify uniquely this issue briefDescription — summarised description of the issue

— summarised description of the issue explanation — should be a more in-depth description of the issue and ideally on how it should be solved

— should be a more in-depth description of the issue and ideally on how it should be solved category — identifies the type of the issue. There are a lot of possible categories such as CORRECTNESS , USABILITY , I18N , COMPLIANCE , PERFORMANCE , ...

— identifies the type of the issue. There are a lot of possible categories such as , , , , , ... priority — a number between 1 and 10, where the bigger the number the more serious the issue is

— a number between 1 and 10, where the bigger the number the more serious the issue is severity — it can be one of the following values: FATAL , ERROR , WARNING , INFORMATIONAL and IGNORE . Note: If the severity is either FATAL or ERROR then running lint will fail and you will have to address the issue.

— it can be one of the following values: , , , and . If the severity is either or then running will fail and you will have to address the issue. implementation — the class responsible for analysing files and detecting the issue

What is a Detector?

A Detector is a class that is able to find one/more specific issues. Depending on the Issue , we can use different types of Detector in order to provide better interfaces to different file types: