• Kotlin + buildSrc for Better Gradle Dependency Management
  • Sam Edwards is Lead Android Engineer at Google Developer Expert for Android

To take full advantage of the Android Plugin for Gradle 3.0+, it is increasingly common to split Android projects into multiple modules. However, as the number of Modules increases, we quickly run into the messy problem of dependency management.

There are three different ways to manage Gradle dependencies:

  1. Manual management
  2. Use the Google recommended “Ext”
  3. Kotlin + buildSrc

1) Manual management

This is the way most people manage dependencies, but it requires a lot of manual change every time you upgrade the dependency library.

module_a/build.gradle

implementation "Com. Android. Support: support - annotations: 27.0.2"
implementation "Com. Android. Support: appcompat - v7:27.0.2"
implementation "Com. Squareup. Retrofit2: retrofit: 2.3.0." "
implementation "Com. Squareup. Retrofit2: adapter - rxjava2:2.3.0." "
implementation "IO. Reactivex. Rxjava2: rxjava: 2.1.9"
Copy the code

module_b/build.gradle

implementation "Com. Android. Support: support - annotations: 27.0.2"
implementation "Com. Android. Support: appcompat - v7:27.0.2"
implementation "Com. Squareup. Retrofit2: retrofit: 2.3.0." "
implementation "Com. Squareup. Retrofit2: adapter - rxjava2:2.3.0." "
implementation "IO. Reactivex. Rxjava2: rxjava: 2.1.9"
Copy the code

There is a lot of duplication of configuration, and it is difficult to manage version updates of dependent libraries when your project has many modules.

Google recommends: Use Gradle Extra

Google recommends this approach to managing dependencies in the Official Android documentation. Many projects such as ButterKnife, Picasso, etc are using this method.

This approach is great for updating versions of your Support Library, because each support Library has the same version number and you only need to change it in one place. The same is true of other third-party libraries such as Retrofit.

Root-level build.gradle

ext {
  versions = [
    support_lib: "27.0.2",
    retrofit: "2.3.0",
    rxjava: "2.1.9"
  ]
  libs = [
    support_annotations: "com.android.support:support-annotations:${versions.support_lib}",
    support_appcompat_v7: "com.android.support:appcompat-v7:${versions.support_lib}",
    retrofit :"com.squareup.retrofit2:retrofit:${versions.retrofit}",
    retrofit_rxjava_adapter: "com.squareup.retrofit2:adapter-rxjava2:${versions.retrofit}",
    rxjava: "io.reactivex.rxjava2:rxjava:${versions.rxjava}"]}Copy the code

module_a/build.gradle

implementation libs.support_annotations
implementation libs.support_appcompat_v7
implementation libs.retrofit
implementation libs.retrofit_rxjava_adapter
implementation libs.rxjava
Copy the code

module_b/build.gradle

implementation libs.support_annotations
implementation libs.support_appcompat_v7
implementation libs.retrofit
implementation libs.retrofit_rxjava_adapter
implementation libs.rxjava
Copy the code

This approach is an improvement over manual management, but without IDE support, the IDE can’t auto-complete when updating dependent libraries.

Kotlin + buildSrc == Android Studio Autocomplete 😎 🎉

You need to create a buildSrc module in your project, and then write kotlin code to manage the dependency libraries so that the IDE supports auto-completion.

Gradle documentThe following passage:

When you run Gradle, it checks to see if there is a directory named buildSrc in your project. Gradle then automatically compiles and tests this code and places it in the classpath of the build script. You do not need to provide any further instructions.

You only need to create two new files in the buildSrc Module:

  1. build.gradle.kts
  2. The file that writes Kotlin code (in this articleDependencies.kt)

buildSrc/build.gradle.kts:

plugins {
    `kotlin-dsl`
}
Copy the code

buildSrc/src/main/java/Dependencies.kt

object Versions {
    val support_lib = "27.0.2"
    val retrofit = "2.3.0"
    val rxjava = "2.1.9"
}

object Libs {
 val support_annotations = "com.android.support:support-annotations:${Versions.support_lib}"
 val support_appcompat_v7 = "com.android.support:appcompat-v7:${Versions.support_lib}"
 val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofit}"
 val retrofit_rxjava_adapter = "com.squareup.retrofit2:adapter-rxjava2:${Versions.retrofit}"
 val rxjava = "io.reactivex.rxjava2:rxjava:${Versions.rxjava}"
}
Copy the code

After the above two steps, execute a Gradle Sync task, and now we can access any value in Dependencies. Kt in Android Studio.

The result looks very similar to “ext”, but it supports auto-complete and one-click jump.

module_a/build.gradle

implementation Libs.support_annotations
implementation Libs.support_appcompat_v7
implementation Libs.retrofit
implementation Libs.retrofit_rxjava_adapter
implementation Libs.rxjava
Copy the code

module_a/build.gradle

implementation Libs.support_annotations
implementation Libs.support_appcompat_v7
implementation Libs.retrofit
implementation Libs.retrofit_rxjava_adapter
implementation Libs.rxjava
Copy the code

conclusion

I highly recommend using the “Kotlin + buildSrc” approach. It supports auto-complete and click-to-jump, eliminating the need to manually switch between files and managing Gradle dependencies.

Hands-on practice:

The new Module name must be buildSrc

In Android Studio, I right-click on the project and create a New Android Library named buildSrc. After trying it several times, I get a message saying “Gradle Sync failed: Plugin with id ‘com.android. Library ‘not found’ error

Later, I created the buildSrc module manually by following this example. The steps are as follows:

  1. Create a new folder under the project root named buildSrc (the same as the app folder in the project).
  2. Create a file named build.gradle. KTS in the buildSrc folder as described earlier.
  3. Create the SRC /main/ Java folder in the buildSrc folder, as shown below. Create a Dependencies. Kt file in this folder, referring to the previous description.