Blog Infos
Author
Published
Topics
, , , ,
Published

Enhance Your CI Efficiency by Disabling Unnecessary Lint Tasks When Building APKs

 

Photo by Elena Mozhvilo on Unsplash

I’ve been exploring ways to speed up a white-label automated app-building system. After a deeper inspection, I realized that the Android Gradle build task could run much faster for assemble tasks, a.k.a. building APKs. Given the number of apps this system generates, even minor improvements can be highly valuable.

These days, when you upload an Android app to Google Play or the Amazon Appstore, an Android App Bundle (AAB) is required*. When building AABs, the lint task doesn’t run by default. If your only requirement is an AAB, this article won’t be your recipe for speed. However, if you still need to generate APKs, whether for uploading to an automated test platform, easier distribution to QA teams, or other specific needs, keep reading.

*Note: Amazon Appstore still accepts APKs.

Gradle Build

The Gradle build system provides many optimizations for completing tasks faster. It caches the inputs and outputs of the executed tasks, and if the inputs haven’t changed, it skips the task and reuses the cached output. It is also capable of running independent tasks in parallel. You can learn more about Gradle caching here and parallel task execution here.

However, our white-label system executes tasks in a fresh and clean workspace, similar to ephemeral CI environments, which prevents us from leveraging caching out of the box. Therefore, I aimed to prevent unnecessary tasks from running.

I ran a clean release build with Gradle’s --scan option and began exploring the Timeline. As its name suggests, the Timeline displays each executed task chronologically, showing how long it took to start and finish. After I ordered the tasks by duration, I noticed that lintVitalAnalyzeRelease, a task that runs by default for a release APK build consumed a significant portion of the overall execution time. This appeared to be a low-hanging fruit I could easily tackle.

For demonstration purposes, I used the mozilla-mobile/fenix project to showcase the Gradle build scan results but the same idea applies to any Android project.

Gradle Scan Timeline from mozilla-mobile/fenix Project.

The lint task for the app module alone took 33.944 seconds to complete, accounting for approximately 15% of the entire execution time. It’s important to note that the lint task runs for all Android modules the project depends on. Below, you’ll find the Gradle Scan Timeline for android/nowinandroid, a project with 21 Android module dependencies for the assembleRelease task at the time of writing.

Gradle Scan Timeline filtered by lint tasks from android/nowinandroid project.

By filtering for tasks of type AndroidLintAnalysisTask, you can see how much time each module’s code analysis took. To be fair, some of these tasks ran in parallel, so the report’s 5m 11s duration doesn’t reflect the actual time, as the overall execution finished in 4m 16s.

Overall task execution duration for the android/nowinandroid project.

Lint. The good, the bad, and the lintVitalRelease task

A linter is a tool that analyzes your code to identify syntax errors, potential bugs, vulnerabilities, and code smells, among other issues. In an Android project, the Android Gradle Plugin provides numerous lint rules that address a wide range of concerns, including accessibility, performance, usability, and security. If you’re up for a challenge, you can also create custom lint checks for your specific needs.

Out-of-the-box AGP lint rules

The cost of these checks increases somewhat linearly with the size of your project, as larger codebases have more lines of code to be validated against lint rules. It’s important to note that lint tasks, by default, are only executed for release APK builds. This means they won’t run each time you deploy changes to a device during development or when you build an app bundle.

Below is an overview of the impact of lint tasks in the assembleRelease task on projects of varying sizes. All tasks were executed on an M3 Pro Mac.

Project LOC Modules Lint On Lint Off Saved Reduction %
fenix 487398 5 220s 166s 54s 25
nowinandroid 90939 30 256s 189s 67s 27
tivi 180888 66 344s 293s 51s 15
white-label 216956 2 91s 55s 36s 40
view raw comparison.md hosted with ❤ by GitHub

Build times with lint on/off for the assembleRelease task

 

Note: The LOC’s (Lines of Code) accounts for Java, Kotlin and XML files only.

Disabling Lint in CI builds

Logs from successful builds, including lint task reports, are frequently overlooked in CI environments. This oversight means valuable processing time, and the money it represents can be wasted.

If you’re not actively using these lint reports and run multiple builds regularly, you can save time and money by disabling the execution of lint tasks. Add the following lines to your project’s Gradle configuration file.

 

android {
lint {
checkReleaseBuilds = false
}
}

You might not want lint tasks to be permanently disabled. Instead, you can control their execution by passing an extra parameter to Gradle tasks. For example, you can run ./gradlew assembleRelease -PdisableReleaseLint to disable lint only when this parameter is present. Here’s how to set it up in your Gradle configuration file:

lint {
if (project.hasProperty("disableReleaseLint")) {
checkReleaseBuilds = false
}
}

These samples use the AGP Lint DSL. You can learn more about it in the official docs.

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Declarative Gradle on Android

Declarative Gradle is a project that targets better isolation of concern and expressing any build clearly and understandably. It is our key initiative towards improving the developer experience and maintainability of Gradle projects.
Watch Video

Declarative Gradle on Android

Nelson Osacky & Inaki Villar
Lead Solutions Engineer & solutions engineer
Gradle

Declarative Gradle on Android

Nelson Osacky & In ...
Lead Solutions Engin ...
Gradle

Declarative Gradle on Android

Nelson Osacky & ...
Lead Solutions Engineer & ...
Gradle

Jobs

Wrapping up!

Optimizing CI build times by managing Android Gradle tasks is not just about increasing speed and saving costs, it’s also about freeing up developer time for more critical tasks. Disabling the lint task was a low-hanging fruit that brought immediate benefits. While the advantages of this approach might seem minimal for smaller projects, dealing with hundreds or thousands of builds for each new app version can significantly reduce computing load. More importantly, it accelerates delivery, ensuring the latest version quickly get into users hands.

For teams managing extensive build pipelines, these insights can serve as a foundation for exploring additional CI/CD process optimizations.

Thank you!

Please share your numbers if you’ve made it here and this post has helped you! I’m keen to see the lint impact in different projects.

Do you have any other tips on how to improve build time? I would love to discuss!

Feel free to connect with me on LinkedIn.

This article was previously published on proandroiddev.com.

Menu