Android build system provides a lot of tools to optimize the code, find potential issues, improve performance, etc. One of the tool it supports is Lint. Lint is a tool which analyzes the source code and flags potential bugs and errors during the build, and Android Studio even uses Lint to show those bugs and errors in the editor.
A linter or lint refers to tools that analyze source code to flag programming errors, bugs, stylistic errors, and suspicious constructs.
Android build system provides a lot of Lint rules that are quite helpful such as
Hardcoded String in xml layout,
Missing Permissions in Java/Kotlin code. After lint runs over the codebase, it generates a report in html and xml showing warnings and errors.
Sometimes, based on your requirements, you may need to write your custom lint rules. And that’s a good thing. Writing your custom Lint rules has never been easier! Android Studio 3 provides a great support to write and run your custom lint rules and you no longer have to copy jar file to
~/.android/lint or some other place. It’s super easy now and you must use Lint!
Before writing some code, let’s understand different aspects of Lint. There are 4 main parts for every lint check.
- Issue: As the name suggests, this is what we are using lint for - to find issues in our code. Here, we define what issue we are looking for.
- Detector: Again, as the name suggests, a detector is used to detect issues in the source code. Here, we write the logic to find out the issues.
- Implementation: It binds an issue with a detector class and helps lint know where to look for a given issue.
- Registry: It’s a list of all the issues that lint should look for.
Ideally, we should read more about each element, but what’s the fun in that? Let’s write a simple custom lint rule that runs on app’s xml layouts and registers a warning for every
TextView that does not use
In your Android app project, create a new module and select
Java Library option. Once android studio creates the module, let’s edit build configuration.
Once we have added lint as dependency, we can easily proceed forward with writing our custom lint rule. Let’s write a simple Issue.
- Id: Id of the issue. This should be unique and is displayed in the report. You use this same id if you want to ingore a lint check.
- Description: Brief description of the issue.
- Explanation: Describe the issue in details and propose possible solutions.
- Category: This defines the category of the issue. There are many categories provided in lint tools such as
CORRECTNESS, etc. You should choose the correct category based on your issue.
- Priority: Define priority of the issue on a scale of 0 to 10.
- Severity: Define severity of the issue. eg.
Implementation binds the issue to the detector class. We provide the detector class and a scope of the implementation. We provide
Scope.RESOURCE_FILE_SCOPE because the issue may be present in resources only.
We need to write detection logic for lint to detect the issue.
Android lint provides some scanning APIs to be used for detectors.
- UastScanner: Java + Kotlin files
- ClassScanner: Bytecode
- BinaryResourceScanner: Binary resources
- ResourceFolderScanner: Resource folders
- XmlScanner: Xml files
- GradleScanner: Gradle files
- OtherFileScanner: Other files in projects
Here, we extend
ResourceXmlDetector which implements
XmlScanner to scan Xml files and get Xml dom elements to perform checks on.
We override method
getApplicableElements and return
TextView because we just want to check for TextViews. Based on your requirements, you may return multiple element names or
ALL which would scan all the elements in xml.
visitElement method is called when XmlScanner visits the applicable element. Here, we add our logic. We check if the TextView element has
textAppearance attribute or not. If not, we report the issue.
context.report method is used to report the issue and generate a report.
context.getLocation gives the location of the element (file path, line number, column) to pinpoint the exact location in the report.
We have our Issue, Detecor and Implementation ready. We just need to register the issue and update gradle build script to include the registry class.
getIssues method, we return a list of all the issues that we want to register with Lint.
We also need to update
We are all ready with our custom lint rule. We just need to add it to the app’s build file. Update your app’s
build.gradle file and add following dependency.
That’s it! Let’s run lint.
And your new custom lint rule will be used to check for issues.
Writing custom Lint rules for Android is super easy now and you should definitely write some of your own rules to avoid potential issues and especially to keep high code quality in a big team.
- Get started with Android Lint - custom lint rules
- Android Lint Deepdive - advanced custom lint rules
How to get away with READ/WRITE permissions on Android
Use FileProvider and the android ecosystem to create/edit/share files without asking users for Read and Write permissions. Improve your app's user experience by skipping unnecessary permission request dialogs. We will use android's Storage Access Framework to open documents and images.