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:
- Gradle’s extra properties https://docs.gradle.org/current/userguide/writing_build_scripts.html#sec:extra_properties
- Clean Architecture example by Fernando Cejas https://github.com/android10/Android-CleanArchitecture
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.