# Publishing a Lint Check Lint will look for jar files with a service registry key for issue registries. You can manually point it to your custom lint checks jar files by using the environment variable `ANDROID_LINT_JARS`: ```shell $ export ANDROID_LINT_JARS=/path/to/first.jar:/path/to/second.jar ``` (On Windows, use `;` instead of `:` as the path separator) However, that is only intended for development and as a workaround for build systems that do not have direct support for lint or embedded lint libraries, such as the internal Google build system. ## Android ### AAR Support Android libraries are shipped as `.aar` files instead of `.jar` files. This means that they can carry more than just the code payload. Under the hood, `.aar` files are just zip files which contain many other nested files, including api and implementation jars, resources, proguard/r8 rules, and yes, lint jars. For example, if we look at the contents of the timber logging library's AAR file, we can see the lint.jar with several lint checks within as part of the payload: ```shell $ jar tvf ~/.gradle/caches/.../jakewharton.timber/timber/4.5.1/?/timber-4.5.1.aar 216 Fri Jan 20 14:45:28 PST 2017 AndroidManifest.xml 8533 Fri Jan 20 14:45:28 PST 2017 classes.jar 10111 Fri Jan 20 14:45:28 PST 2017 lint.jar 39 Fri Jan 20 14:45:28 PST 2017 proguard.txt 0 Fri Jan 20 14:45:24 PST 2017 aidl/ 0 Fri Jan 20 14:45:28 PST 2017 assets/ 0 Fri Jan 20 14:45:28 PST 2017 jni/ 0 Fri Jan 20 14:45:28 PST 2017 res/ 0 Fri Jan 20 14:45:28 PST 2017 libs/ ``` The advantage of this approach is that when lint notices that you depend on a library, and that library contains custom lint checks, then lint will pull in those checks and apply them. This gives library authors a way to provide their own additional checks enforcing usage. ### lintPublish Configuration The Android Gradle library plugin provides some special configurations, `lintChecks` and `lintPublish`. The `lintPublish` configuration lets you reference another project, and it will take that project's output jar and package it as a `lint.jar` inside the AAR file. The [](https://github.com/googlesamples/android-custom-lint-rules) sample project demonstrates this setup. The `:checks` project is a pure Kotlin library which depends on the Lint APIs, implements a `Detector`, and provides an `IssueRegistry` which is linked from `META-INF/services`. Then in the Android library, the `:library` project applies the Android Gradle library plugin. It then specifies a `lintPublish` configuration referencing the checks lint project: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ apply plugin: 'com.android.library' dependencies { lintPublish project(':checks') // other dependencies } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Finally, the sample `:app` project is an example of an Android app which depends on the library, and the source code in the app contains a violation of the lint check defined in the `:checks` project. If you run `./gradlew :app:lint` to analyze the app, the build will fail emitting the custom lint check. ### Local Checks What if you aren't publishing a library, but you'd like to apply some checks locally for your own codebase? You can use a similar approach to `lintPublish`: In your app module, specify ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ apply plugin: 'com.android.application' dependencies { lintChecks project(':checks') // other dependencies } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now, when lint runs on this application, it will apply the checks provided from the given project. !!! Warning This mechanism works well on the CI server for enforcing local code conventions, and it also works for developers on your team; the errors should be flagged in the IDE (providing they are analyzing single-file scopes). However, there have been various bugs and difficulties around the lint checks getting rebuilt after changes or clean builds. There are some bugs in the Android Gradle Plugin issue tracker for this. ### Unpublishing If you end up “deleting” a lint check, perhaps because the original conditions for the lint check are not true, don't just stop distributing lint checks with your library. Instead, you'll want to update your `IssueRegistry` to override the `deletedIssues` property to return your deleted issue id or ids: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * The issue id's from any issues that have been deleted from this * registry. This is here such that when an issue no longer applies * and is no longer registered, any existing mentions of the issue * id in baselines, lint.xml files etc are gracefully handled. */ open val deletedIssues: List<String> = emptyList() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The reason you'll want to do this is listed right there in the doc: If you don't do this, and if users have for example listed your issue id in their `build.gradle` file or in `lint.xml` to say change the severity, then lint will report an error that it's an unknown id. This is done to catch issue id typos. And if the user has a baseline file listing incidents from your check, then if your issue id is not registered as deleted, lint will think this is an issue that has been “fixed” since it's no longer reported, and lint will issue an informational message that the baseline contains issues no longer reported (which is done such that users can update their baseline files, to ensure that the fixed issues aren't reintroduced again.)