More often that not, projects end up in one of these situations:
- Many random
*.gradle(.kts)
scripts that not everyone understands. - Very complicated
subprojects
andallprojects
blocks. - A
buildSrc
directory that houses much of the build logic.
The first two can cause a lot of trouble down the line because you either end up with a lot of code duplication as developers tend to copy/paste these scripts when creating new modules, or you end up with massive configuration blocks that needlessly apply most of your build logic to every module. The third option is a bit better in terms of code duplication, but buildSrc
is not great because it invalidates build cache every time you make changes to anything inside it, effectively causing a clean build with every change.
Convention Plugins are Gradle’s way of sharing your build logic between submodules and addressing the above concerns, and the Now in Android (NiA) app fully takes advantage of this.
These plugins are additive and composable, and try to only accomplish a single responsibility. Modules can then pick and choose the configurations they need.
The first thing we see here is some files that have configuration logic that different plugins can apply, like AndroidCompose.kt ,
KotlinAndroid.kt and
Flavor.kt
Some really good examples from the codebase that show how this is all tied together are the following:
- The
AndroidLibraryConventionPlugin applies the
com.android.library
andorg.jetbrains.kotlin.android
plugins, uses theconfigureKotlinAndroid()
function fromKotlinAndroid.kt
to configure things like yourcompileSdk
,compileOptions
,kotlinOptions
, and theconfigureFlavors()
function from theFlavor.kt
file to configure project flavors.
2. The AndroidFeatureConventionPlugin applies the same plugins from above plus
org.jetbrains.kotlin.kapt
because all features modules in NiA use libraries like Hilt which require KAPT for code generation. It also adds a lot of common dependencies
like the :core
modules and some libraries.
3. The AndroidLibraryComposeConventionPlugin uses the
configureAndroidCompose()
function to configure Compose to work in any module it’s applied to.
The result is your feature modules’ build scrips mostly end up looking like this, which is how they should. No duplication or unnecessary scripts that are hard to understand down the line. Just the things that your module needs.
You can immediately see what it means for these plugins to be additive and composable. Want a module that doesn’t use Compose? Just apply the first two plugins. Want to use Compose? Just add the third one. A good example of this in NiA is the build.gradle.kts
script in the :feature-author
module, which you can see here.
Those of you with a keen eye may have noticed that the plugin ids are different from their file names, that’s because when you register your custom plugins to be exposed to the rest of your project, they’re given an id and implementation. This can be seen here.
Add me on Linkedin and Twitter to talk about Gradle and Android! 🙂
This article was originally published on proandroiddev.com on July 27, 2022