Implementing and Managing Custom Android Lint Rules for Code Quality
The article explains how to create, configure, and integrate custom Android Lint rules—using Issue, Detector, Scope, and IssueRegistry APIs—to catch crashes, bugs, performance and security problems such as missing Toast.show() or unsafe Log usage, supports incremental git‑based scans, and demonstrates deployment in IDE, builds, pre‑commit hooks and CI for improved code quality.
Lint is a static code analysis tool provided by Google for Android. It can scan Java source files, class files, resources, Gradle scripts and report potential problems. Besides the hundreds of built‑in rules, developers can write custom Lint rules to meet specific needs.
Why use Lint
During the iteration of Meituan Waimai Android App, many crashes were caused by misuse of Serializable, missing Toast.show(), etc. Traditional code reviews and testing could not fully eliminate these problems. Static analysis offers a systematic way to detect them early.
We evaluated several static analysis frameworks (FindBugs, PMD, Coverity, Checkstyle) and chose Lint because it:
Supports Java source, class, resource and Gradle files.
Is extensible – custom rules can be added.
Has complete tooling support in Android Studio and the Gradle plugin.
Provides many Android‑specific checks out of the box.
Is maintained by Google and evolves together with Android tools.
Lint API Overview
The most important APIs are: Issue: represents a Lint rule. Detector: performs the actual analysis and reports Issue s. Scope: defines which files a Detector should scan (e.g., JAVA_FILE_SCOPE, CLASS_FILE_SCOPE, RESOURCE_FILE_SCOPE, GRADLE_SCOPE). Scanner: the low‑level component that walks the AST. IssueRegistry: entry point that supplies the list of Issue s.
Example of a simple rule that checks whether Toast.makeText() is followed by Toast.show():
public class ToastDetector extends Detector implements JavaPsiScanner {<br/> public static final Issue ISSUE = Issue.create(<br/> "ShowToast",<br/> "Toast created but not shown",<br/> "...",<br/> Category.CORRECTNESS,<br/> 6,<br/> Severity.WARNING,<br/> new Implementation(ToastDetector.class, Scope.JAVA_FILE_SCOPE));<br/> // ...<br/>}Corresponding IssueRegistry:
public class MyIssueRegistry extends IssueRegistry {<br/> @Override<br/> public List<Issue> getIssues() {<br/> return Arrays.asList(ToastDetector.ISSUE, LogDetector.ISSUE /*, ... */);<br/> }<br/>}Scanner Types
JavaScanner / JavaPsiScanner / UastScanner – scan Java source files.
XmlScanner – scan XML resources.
ClassScanner – scan compiled class files.
BinaryResourceScanner – scan binary resources.
ResourceFolderScanner – scan whole resource folders.
GradleScanner – scan Gradle scripts.
OtherFileScanner – generic file scanner.
The Java scanner has evolved from Lombok‑based AST to PSI (Android Studio 2.2) and finally to UAST (Android Studio 3.0), which also supports Kotlin.
Typical Lint Rules
We focus on rules that prevent crashes, bugs, performance or security issues. Examples:
Crash prevention : NewApi (detect high‑API calls on low‑API devices), custom SerializableCheck, ParseColorCheck.
Bug prevention : SpUsage (enforce unified SharedPreferences wrapper), ImageViewUsage, TodoCheck.
Performance / Security : ThreadConstruction (ban direct new Thread()), LogUsage (ban android.util.Log).
Rule Implementation Example
Reading a JSON configuration file to customize the error message for LogUsage:
import com.android.tools.lint.detector.api.Context;<br/><br/>public final class LintConfig {<br/> private LintConfig(Context context) {<br/> File projectDir = context.getProject().getDir();<br/> File configFile = new File(projectDir, "custom-lint-config.json");<br/> if (configFile.exists() && configFile.isFile()) {<br/> // read config...<br/> }<br/> }<br/>}Using the configuration in a detector:
public class LogUsageDetector extends Detector implements Detector.JavaPsiScanner {<br/> private LintConfig mLintConfig;<br/><br/> @Override<br/> public void beforeCheckProject(@NonNull Context context) {<br/> mLintConfig = new LintConfig(context);<br/> }<br/><br/> @Override<br/> public List<String> getApplicableMethodNames() {<br/> return Arrays.asList("v", "d", "i", "w", "e", "wtf");<br/> }<br/><br/> @Override<br/> public void visitMethod(JavaContext context, JavaElementVisitor visitor, PsiMethodCallExpression call, PsiMethod method) {<br/> if (context.getEvaluator().isMemberInClass(method, "android.util.Log")) {<br/> String msg = mLintConfig.getConfig("log-usage-message");<br/> context.report(ISSUE, call, context.getLocation(call.getMethodExpression()), msg);<br/> }<br/> }<br/>}Template Lint Rules
We created JSON‑based templates to generate common rules, such as deprecated-api (ban specific API calls) and handle-exception (require try‑catch for certain methods). The template matches method signatures, fields, constructors or super‑classes using glob or regex patterns.
Git‑Based Incremental Checking
To avoid massive refactoring of legacy code, we added a git-base property to the configuration. Only files added after the specified commit are scanned. The implementation runs git rev-parse --show-toplevel to get the repository root and git ls-tree … to obtain the file list, then compares each node’s file path via Context.getLocation(node).getFile().
Conclusion
Static analysis with Lint dramatically reduces crashes, bugs, performance and security problems in Android projects. By integrating Lint into IDE real‑time checks, local builds, pre‑commit hooks and CI pipelines, teams can catch high‑priority issues early, enforce coding standards, and lower the learning curve for new developers.
References
Using Lint to Improve Your Code
LintOptions DSL
Custom Android Lint Practice
Lint Source Code Analysis (3)
Android Studio Release Notes
Git Documentation
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Meituan Technology Team
Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
