Configuring git submodules on a Gradle Android project can be painful when shared dependencies need to be updated. I’ve lost count of how many times I’ve had to reconfigure my project and its submodule dependencies after updating my Android SDK. I encountered this annoyance again recently and decided that there must be a better way to handle the matter. Enter Gradle extra properties extension.

After updating my Android framework, I compiled my project in Android Studio and immediately got this error:

Error:The SDK Build Tools revision (23.0.3) is too low for project ':standardlib'. Minimum required is 25.0.0  
<a href="fix.build.tools.version">Update Build Tools version and sync project</a><br><a href="openFile:/root_project_path/standardlib/build.gradle">Open File</a>

I found this to be quite aggravating, and my initial reaction was to manually increment the submodule’s build tools version. This turned out to be a poor decision because I saved little time in the moment to maintain my momentum with the feature I was working on. I suffered the consequence from the decision because I encountered the same issue again when I started a new feature before merging the one I’d just finished.

I decided to pay the cost and implement Gradle extra properties extension (read more here) in my project’s root build.gradle. This allows me to configure the submodule from my root project so hopefully, I won’t encounter this again. I also won’t need to modify the submodule’s build.gradle again. Well, not for this reason, anyway.

In my root project’s build.gradle I added an ext block at the root level:

buildscript {  
    ...  
}

ext {  
    buildToolsVersion = "25.0.2"  
    compileSdkVersion = 25  
}

In my submodule’s build.gradle I had to reference those properties:

android {  
    compileSdkVersion rootProject.ext.compileSdkVersion  
    buildToolsVersion rootProject.ext.buildToolsVersion

    ...  
}

And my work is done, right? Well, sort of – I had another submodule that needed to be updated. I can also use these same properties in my app module’s build.gradle file so that I only need to update this value in one place. Configuring the app module works exactly the same as configuring a library submodule. I just replaced the values for compileSdkVersion and buildToolsVersion in the android block with the references to rootProject.ext.compileSdkVersion and rootProject.ext.buildToolsVersion respectively.

Related: Level-up with Android Studio Shortcuts and Live Templates

This feature of Gradle can be quite useful. I am also using it to configure support library versions in use throughout the project. I added a value to the ExtraPropertiesExtension for the support libraries, androidSupportLibraryVersion and gave it a value corresponding to the latest support library version, "25.3.0". Now, my ext block in my root build.gradle file looks something like this:

buildscript {  
    ...  
}

ext {  
    buildToolsVersion = "25.0.2"  
    compileSdkVersion = 25  
    androidSupportLibraryVersion = "25.3.0"  
}

I only had to make the appropriate references in my other build.gradle files to get everything compiled and using the same support library version. Here is an excerpt from my app’s build.gradle with that change in place:

dependencies {  
    compile project(':standardlib')

    compile "com.android.support:support-v4:$rootProject.ext.androidSupportLibraryVersion"  
    compile "com.android.support:appcompat-v7:$rootProject.ext.androidSupportLibraryVersion"  
    compile "com.android.support:recyclerview-v7:$rootProject.ext.androidSupportLibraryVersion"  
    compile "com.android.support:cardview-v7:$rootProject.ext.androidSupportLibraryVersion"  
    compile "com.android.support:design:$rootProject.ext.androidSupportLibraryVersion"

    ...  
}

Note that in this case, you need to ensure that the string is in double quotes instead of single quotes and lead the reference with a dollar sign $ so that the string interpolation will function correctly. Now I have all of my modules using the same support library version.

It is important to understand that the names I’ve chosen for my extra properties are for my convenience only and could have been anything. You can add whatever extra properties you like and use them any way that best suits your project.

For example, I am using a Gradle plugin called GrGit to help me set my versionName in a reasonable fashion based on the contents of source control:

import org.ajoberstar.grgit.Grgit

buildscript {  
    dependencies {  
        ...  
        classpath 'org.ajoberstar:grgit:1.6.0'  
    }
    ...  
}

ext {  
    git = Grgit.open()  
    gitVersionName = "${git.describe()}"  
    buildToolsVersion = "25.0.2"  
    compileSdkVersion = 25  
    androidSupportLibraryVersion = "25.3.0"  
}

Now, in my app module’s build.gradle I can easily set the version name based on the most recent tag and the number of commits since then:

android {  
    compileSdkVersion rootProject.ext.compileSdkVersion  
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {  
        ...  
        versionName rootProject.ext.gitVersionName  
    }
    ...  
}

These are just a few of the ways you can use the Gradle extra properties extension to help improve your project configuration and make your life easier. This approach minimizes the effort used to bump my project’s commonly updated dependency versions, and I love being able to control that in exactly one place. Of course, this may not be ideal for all projects. Let me know if you have a project configuration this approach doesn’t work for. I’d love to see the ways you can find to improve your project!

Leave a Reply

Your email address will not be published. Required fields are marked *