Holiday clean up or cute versioning in android šŸ§¹

Marius Merkevičius
Treatwell Engineering
3 min readDec 14, 2018

--

TL;DR;

Cool versioning style for android or any project using gradle. Define all versions and dependencies to separate files and use those instead of hardcoding values into project modules. Clean, all in one place and lifesaver whenever dealing with project with multiple modules. Example project šŸ‘‰https://github.com/marius-m/versioning_love

Preface

So one day I was trying to clean-up our *.gradle files. As we use multiple modules in our project + patched libraries, we have versions of various dependencies that we need to reuse through out all the project modules. I was not happy about how we were using the versioning and remembered that there was a very cute naming used in one library ā€” https://github.com/facebook/screenshot-tests-for-android. So Iā€™ve taken the inspiration to clean-up our playground as well and make a post about it, as I thought of it ā€” it was TOO COOL šŸ¤˜ not to be shared with the internet. So here we go šŸš—.

The code

Iā€™ve split the naming into two parts.

  • File version_generic.gradle would have most commonly used version numbers throughout the main project and its modules / libraries
ext {
versions = [
minSdk : 19,
testMinSdk : 26,
debugMinSdk: 26,
compileSdk : 28,
targetSdk : 28,
buildTools : "28.0.3",
support: "27.1.0",
androidGradlePlugin: "3.0.1",
kotlin: "1.3.0",
]
}
  • File version.gradle would have all the library namings and dependencies used. And this is how an example versions.gradle might look like
ext {
apply from: rootProject.file("versions_generic.gradle")
final versionAndroidSupport = versions.support
final versionKotlin = versions.kotlin
plugs = [
gradleBuildTools: "com.android.tools.build:gradle:${versions.androidGradlePlugin}",
gradleVersioning: "com.github.ben-manes:gradle-versions-plugin:0.13.0",
kotlin: "org.jetbrains.kotlin:kotlin-gradle-plugin:$versionKotlin",
detekt: "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0.RC9.2",
]
coreDeps = [
ui: project(":app-ui"),
components: project(":app-components"),
models: project(":app-models"),
twPrinter: project(":tw-printer"),
kotlin: "org.jetbrains.kotlin:kotlin-stdlib:$versionKotlin",
rxJava: "io.reactivex:rxjava:1.2.0",
rxAndroid: "io.reactivex:rxandroid:1.2.1",
]
androidDeps = [
appCompatV7: "com.android.support:appcompat-v7:$versionAndroidSupport",
supportV4: "com.android.support:support-v4:$versionAndroidSupport",
design: "com.android.support:design:$versionAndroidSupport",
cardView: "com.android.support:cardview-v7:$versionAndroidSupport",
multiDex: "com.android.support:multidex:1.0.3",
]
unitTestDeps = [
junit: "junit:junit:4.12",
mockito: "org.mockito:mockito-core:2.8.9",
kotlin: "org.jetbrains.kotlin:kotlin-test-junit:$versionKotlin",
kotlinMockito: "com.nhaarman:mockito-kotlin:$versionKotlinMockito",
assertj: "org.assertj:assertj-core:2.5.0",
mocksFactory: project(":app-mocks-factory"),
]
}

Here are a couple of things that might be interesting to mention.

  • To include simple dependency: rxJava: ā€œio.reactivex:rxjava:1.2.0ā€
  • To include a project that is a part of the project, you could define it like this: components: project(ā€œ:app-componentsā€)
  • This also can be used when including plugins for the project: gradleVersioning: ā€œcom.github.ben-manes:gradle-versions-plugin:0.13.0ā€
  • The versions, defined in versions.gradle can be used dynamically like this: gradleBuildTools: ā€œcom.android.tools.build:gradle:${versions.androidGradlePlugin}ā€
  • Whenever you have same version needed to be applied in multiple dependencies, you can define it into a variable like this: final versionJUnit = ā€œ4.12ā€
  • Also the cool thing about this, you could ā€œcategorizeā€ dependencies for easier tracking what goes where!

After we finished defining versioning files, we need to include them into main project builds.gradle file like this:

buildscript {
apply from: rootProject.file('versions.gradle')
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath plugs.gradleBuildTools
classpath plugs.gradleVersioning
classpath plugs.kotlin
}
}

The important part there is only apply from: rootProject.file(ā€˜versions.gradleā€™). This will associate the versions file with the build files. Whenever we do this, we can include the plugins for the project like this: classpath plugs.gradleBuildTools. Including dependencies and versioning names to modules of the project is as simple as this:

android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
implementation coreDeps.coreUtils
implementation coreDeps.components
implementation coreDeps.models
implementation coreDeps.kotlin
implementation coreDeps.rxJava
testImplementation unitTestDeps.mocksFactory
testImplementation unitTestDeps.junit
testImplementation unitTestDeps.mockito
}
  • Providing compile/build tools/sdk versions is as easy as just linking back to versions_general.gradle like this: compileSdkVersion versions.compileSdk
  • And same thing goes for dependencies, šŸ‘‰implementation coreDeps.coreUtils. Clean and simple.

Summary

Cleaning up project dependencies moved me to look through all the project and remove unused dependencies and remove duplicates whenever iā€™ve found it. Thatā€™s what I call a bit of refreshment for the holidays šŸŒ² and for our lovable playground ā¤ļø.

And what would be a post without an example project ? šŸ‘‰ https://github.com/marius-m/versioning_love

Cheers šŸ¤˜

--

--