CharlieTap
Posted on January 26, 2022
Android studio Bumblebee became stable this week and with it comes a bunch of new features and updates. One of which being that new projects created in Bumblebee have a modernised Gradle configuration. You can read about this here
Whilst this is great for new projects, it's important to keep legacy projects up to date, and migrating from old to new is great way to understand the new approach (I say "new" here, but the syntax has in fact been around for quite some now, it just hadn't been widely adopted).
Why Upgrade?
A quick scan of the Gradle docs goes on to explain the following:
Alongside this, generally its good to keep your configuration compliant with the latest version of Gradle, it eases the migration path when moving between versions.
How did we used to do it again?
Historically Android projects would use the buildscript DSL to load load plugins into the classpath, you would do this is your top level build.gradle file.
It should look something like this:
build.gradle
buildscript {
repositories {
google()
gradlePluginPortal()
}
dependencies {
classpath 'com.android.tools.build:gradle:x.y.z'
classpath "org.jetbrains.kotlin:kotlin-gradle-pluginx.y.z"
}
}
Theres two things happening inside this block:
It's declaring a set of repositories, these are repositories which will be searched when Gradle looks for the plugins you have declared. This is similar to the list of repositories you declare when you are configuration your dependencies, however these repositories will only be searched when Gradle looks for plugins.
It's declaring a set of plugins you wish to use in your project and loading a particular version for each into the classpath.
Applying the plugins in your application
Inside your :app modules build.gradle you would use the now legacy apply plugin syntax to enable the plugins on that particular module.
app/build.gradle
apply plugin: 'com.android.application'
If you've ever worked on projects that have more than one Gradle module you realise the benefits of the separation above as you'll be able to enable plugins on a module by module basis, and lock the plugin versions to a consistent version across all of your modules.
Okay but what does it look like now
Well, the part where you declared the repositories for the plugins... that's moved, its now in your top level settings.gradle file
settings.gradle
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
This makes more sense when you realise the repositories for your dependencies are also now moved the settings.gradle file
settings.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
Loading the plugins
Loading the plugins (but not applying them), still takes place in the top level build.gradle file
build.gradle
plugins {
id 'com.android.application' version 'x.y.z' apply false
id 'org.jetbrains.kotlin.android' version 'x.y.z' apply false
}
Enabling the plugins
This takes place in whatever module you want to apply the plugin on, for example:
app/build.gradle
plugins {
id('com.android.application')
id('org.jetbrains.kotlin.android')
}
Thats all?
Well as with everything new, there's some gotchas here to be aware of. The most important of which is that not all plugins will work the new syntax.
Notice how before you would say something like:
apply plugin: 'kotlin-android'
and now you say something like:
id('org.jetbrains.kotlin.android')
The difference is the latter uses a particular id, and only plugins which are configured with Gradle Project Market Artifact will work out of the box with this syntax.
In particular I have found one popular plugin at this time which is not compliant and that is the Dagger Hilt Plugin.
You can track the support for it here, it's quite likely by the time you read this post that it will already have been released.
Is there any point if not all plugins work
Well there's a workaround, and for the plugins you do configure, you'll theoretically optimise your build time by adopting those.
Workaround
We'll use the case of Dagger as I imagine this to be the most common. For future proofing I have put the future syntax, commented out in the examples below.
Put the following in your top level build.gradle
build.gradle
// it will look like this once Dagger publishes the marker
// id 'com.google.dagger.hilt.android' version 'x.y.z' apply false
// for now
id("dagger.hilt.android.plugin") apply false
Then in your settings.gradle the following:
settings.gradle
pluginManagement {
resolutionStrategy {
eachPlugin {
if( requested.id.id == 'dagger.hilt.android.plugin') {
useModule("com.google.dagger:hilt-android-gradle-plugin:x.y.z")
}
}
... repository management config
}
Finally apply the plugin in your app modules build.gradle
app/build.gradle
plugins {
// id 'com.google.dagger.hilt.android' in the future
id 'dagger.hilt.android.plugin'
}
The above solution should work for any legacy Gradle plugin which lacks the marker you need.
Cool, so anything else?
This is the first in a three post series, the following two will cover:
Integration of the new plugin system and Gradles' new version catalog system, you can find it here
Creating your own pre compiled script plugins for tidying up your build.gradle config and give an example showcasing config for the popular the popular versions gradle plugin
Posted on January 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
January 26, 2023