Upgrading to Gradles modern plugin configuration
Tags: android, kotlin, gradle
Published: 2022-01-26 21:40:37

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](https://developer.android.com/studio/releases/gradle-plugin#settings-gradle)

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:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gha5pckm4c2b0h2albci.png)

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`**
```groovy
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:

1. 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.

2. 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`**
```groovy

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`**
```groovy

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`**
```groovy

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`**
```groovy
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`**
```groovy

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:

```groovy
apply plugin: 'kotlin-android'
```


and now you say something like:

```groovy
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](https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_markers) 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](https://github.com/google/dagger/issues/2774), 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`**
```groovy

// 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`**
```groovy

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`**
```groovy

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](https://dev.to/charlietap/gradle-versions-catalog-integration-27l0)

- 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](https://github.com/ben-manes/gradle-versions-plugin)