#AndroidDev #Tip 4 – Managing Android dependencies versions

By -

Welcome to the 4th post on android best practices and tips/tricks.

A quick glimpse of all parts:

  • Part 1 – set android baselinealigned false on this element for better performance
  • Part 2 – Define constants for Bundle Keys used between two Activities
  • Part 3 – Don’t leave any exceptions behind

In this part

In this part, we are going to see how to manage and which are the different ways to manage dependencies versions.

Problem

In almost all the android projects, we use support libraries and dependencies, we update one dependency and sometimes we forget to update the related dependencies with the same version. Another problem is we are not following clean architecture.

Solution

To overcome this silly mistake, just declare a variable and use it for all the related libraries. 

How? 

ext {
    
   SUPPORT_LIB_VERSION = '25.3.1'
    
   PLAY_SERVICE_LIB_VERSION = '10.2.1'
    
   RETROFIT_LIB_VERSION = '2.0.2'
    
   BUTTERKNIFE_LIB_VERSION = '8.5.1'
    
   OKHTTP3_LIB_VERSION = '3.6.0'

}


dependencies {
    ------
    ------
    
    compile "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION"
    compile "com.android.support:design:$SUPPORT_LIB_VERSION"

    compile "com.squareup.retrofit2:retrofit:$RETROFIT_LIB_VERSION"
    compile "com.squareup.retrofit2:adapter-rxjava:$RETROFIT_LIB_VERSION"

    compile "com.squareup.okhttp3:logging-interceptor:$OKHTTP3_LIB_VERSION"
    compile "com.squareup.okhttp3:okhttp:$OKHTTP3_LIB_VERSION"

    compile "com.jakewharton:butterknife:$BUTTERKNIFE_LIB_VERSION"
    annotationProcessor "com.jakewharton:butterknife-compiler:$BUTTERKNIFE_LIB_VERSION"

    ------
    ------
}

What is the change?
If you look closely, you’ll notice that
compile “com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION” which is using a defined common variable for support library.

Practice 2: What should I do when I am having multiple modules?

When you are having a multiple modules in your project, you declare a library versions in your root gradle (i.e. project level)

ext {

    // sdk and tools

    minSdkVersion = 17

    targetSdkVersion = 25

    compileSdkVersion = 25

    buildToolsVersion = '25.0.2'

    SUPPORT_LIB_VERSION = '25.3.1'
    
    PLAY_SERVICE_LIB_VERSION = '10.2.1'
    
    RETROFIT_LIB_VERSION = '2.0.2'
    
    BUTTERKNIFE_LIB_VERSION = '8.5.1'
      
    OKHTTP3_LIB_VERSION = '3.6.0'

}

Now you can access these variables in your module level build.gradle files.

apply plugin: 'com.android.application'

android {

    ...

}

...



dependencies {

    // support libraries

    compile "com.android.support:appcompat-v7:$rootProject.ext.SUPPORT_LIB_VERSION"
    compile "com.android.support:design:$rootProject.ext.SUPPORT_LIB_VERSION"

    compile "com.squareup.retrofit2:retrofit:$rootProject.ext.RETROFIT_LIB_VERSION"
    
    compile "com.squareup.retrofit2:adapter-rxjava:$rootProject.ext.RETROFIT_LIB_VERSION"

    compile "com.squareup.okhttp3:logging-interceptor:$rootProject.ext.OKHTTP3_LIB_VERSION"
    
    compile "com.squareup.okhttp3:okhttp:$rootProject.ext.OKHTTP3_LIB_VERSION"

            
    compile "com.jakewharton:butterknife:$rootProject.ext.BUTTERKNIFE_LIB_VERSION"
    
    annotationProcessor "com.jakewharton:butterknife-compiler:$rootProject.ext.BUTTERKNIFE_LIB_VERSION"
}

Notice that we have referenced variable using $rootProject.ext.SUPPORT_LIB_VERSION, also note that you can reference variable using $rootProject.SUPPORT_LIB_VERSION

Also this practice would help you in managing minimum and maximum sdk versions in all the child modules, and same applies for all the libraries you are using in different modules, so we can make sure the same version is being used across all the modules. Another benefit of following this practice is it would be easier to update library version by just updating a single line and it will apply to all the child modules.

Practice 3: When having multiple modules, declare all the common dependencies in root level gradle

This practice is similar to Practice #2 described above, but this practice is about to declare a complete artifact ID in top level build.gradle, instead of only declaring versions.

For example:

//Top level (project level) build.gradle file
ext {
    //Android
    androidBuildToolsVersion = "25.0.2"
    androidMinSdkVersion = 15
    androidTargetSdkVersion = 25
    androidCompileSdkVersion = 25

    SUPPORT_LIB_VERSION = "25.3.1"
    BUTTERKNIFE_LIB_VERSION = "8.5.1"
    RETROFIT_LIB_VERSION = "2.1.0"

    supportDependencies = [
            designSupportLibrary:     "com.android.support:design:${SUPPORT_LIB_VERSION}",
            appCompat: "com.android.support:appcompat-v7:${SUPPORT_LIB_VERSION}",
            cardView: "com.android.support:cardview-v7:${SUPPORT_LIB_VERSION}",
            supportV4: "com.android.support:support-v4:${SUPPORT_LIB_VERSION}",

    ]

    retrofitDependencies = [
            retrofitLib: "com.squareup.retrofit2:retrofit:${RETROFIT_LIB_VERSION}",
            retrofitGsonConverter: "com.squareup.retrofit2:converter-gson:${RETROFIT_LIB_VERSION}",
            rxJavaAdapter: "com.squareup.retrofit2:adapter-rxjava:${RETROFIT_LIB_VERSION}",
    ]

    butterKnifeDependencies = [
            butterKnifeLib: "com.jakewharton:butterknife:${BUTTERKNIFE_LIB_VERSION}",
            butterKnifeAnnotationProcessor: "com.jakewharton:butterknife-compiler:${BUTTERKNIFE_LIB_VERSION}",
            butterKnifeCompiler: "com.jakewharton:butterknife-compiler:${BUTTERKNIFE_LIB_VERSION}",
    ]

}

Now let’s refer dependencies in module level build.gradle:

dependencies {
    …
    …
    // support libraries
    
    compile supportDependencies.designSupportLibrary

   // Retrofit
   compile retrofitDependencies.retrofitLib
   
   compile retrofitDependencies.retrofit_gson_converter
    
   compile retrofitDependencies.rxJavaAdapter

   //butterknife library
   
   compile butterKnifeDependencies.butterKnifeLib
   
   annotationProcessor butterKnifeDependencies.butterKnifeAnnotationProcessor
   
   apt butterKnifeDependencies.butterKnifeCompiler

    …
    …
}

Practice 4: declare a common dependencies.gradle file

Personally I used to follow this practice in my project. Following this practice, we need to create a separate gradle file, let’s say for example, dependencies.gradle. Later you need to apply this dependencies.gradle in your root level build.gradle file.

For example: dependencies.gradle

allprojects {
    repositories {
        jcenter()
    }
}

ext {
    //Android
    androidBuildToolsVersion = "25.0.2"
    androidMinSdkVersion = 15
    androidTargetSdkVersion = 25
    androidCompileSdkVersion = 25

    SUPPORT_LIB_VERSION = "25.3.1"
    BUTTERKNIFE_LIB_VERSION = "8.5.1"
    RETROFIT_LIB_VERSION = "2.1.0"

    supportDependencies = [
            designSupportLibrary:     "com.android.support:design:${SUPPORT_LIB_VERSION}",
            appCompat: "com.android.support:appcompat-v7:${SUPPORT_LIB_VERSION}",
            cardView: "com.android.support:cardview-v7:${SUPPORT_LIB_VERSION}",
            supportV4: "com.android.support:support-v4:${SUPPORT_LIB_VERSION}",

    ]

    retrofitDependencies = [
            retrofitLib: "com.squareup.retrofit2:retrofit:${RETROFIT_LIB_VERSION}",
            retrofitGsonConverter: "com.squareup.retrofit2:converter-gson:${RETROFIT_LIB_VERSION}",
            rxJavaAdapter: "com.squareup.retrofit2:adapter-rxjava:${RETROFIT_LIB_VERSION}",
    ]

    butterKnifeDependencies = [
            butterKnifeLib: "com.jakewharton:butterknife:${BUTTERKNIFE_LIB_VERSION}",
            butterKnifeAnnotationProcessor: "com.jakewharton:butterknife-compiler:${BUTTERKNIFE_LIB_VERSION}",
            butterKnifeCompiler: "com.jakewharton:butterknife-compiler:${BUTTERKNIFE_LIB_VERSION}",
    ]

}

Now you need to apply apply this dependencies.gradle into your root level build.gradle using:

apply from: "$project.rootDir/settings/dependencies.gradle"

Now you can refer dependencies in your module level build.gradle file as shown below:

dependencies {

    def supportDependencies = rootProject.ext.supportDependencies
    def retrofitDependencies = rootProject.ext.retrofitDependencies
    def butterKnifeDependencies = rootProject.ext.butterKnifeDependencies

    // support libraries
    compile supportDependencies.appCompat
    compile supportDependencies.supportV4
    compile supportDependencies.cardView

    compile retrofitDependencies.retrofitLib
    compile retrofitDependencies.retrofitGsonConverter
    compile retrofitDependencies.rxJavaAdapter

    compile butterKnifeDependencies.butterKnifeLib
    annotationProcessor butterKnifeDependencies.butterKnifeAnnotationProcessor
    apt butterKnifeDependencies.butterKnifeCompiler

Notes:

  • Practice 4 would help you managing dependencies in a separate file so easier to manage
  • It allows you to follow clean code architecture

References:

Wrapping up

That’s it for sharing best practices for managing android dependencies in Android app development. I am sure you have learnt from this article, if you have learnt then please give shout out to me over Twitter @pareshmayani, also please share this article.

Paresh Mayani

Lazy android developer, exploring the horizon of android development since 7 years, currently working as a Technical Lead - Android at Simform Solutions, India. Former Application Architect at KarConnect. He is the Head/Organizer of Google Developers Group (GDG), Ahmedabad

Loading Facebook Comments ...
Loading Disqus Comments ...