Build / Gradle

Gradle Revisited

Back in May 2013 Google announced at IO that they were working on a completely new IDE based upon IntelliJ IDEA which would be based upon the Gradle build system. At the end of June in the same year I began a series of posts which ended up as a series of 9 posts (the longest in the history of Styling Android) covering various aspects of the Gradle build system for Android. Looking back at the code it used Gradle 1.6 and V 0.5.x of the Android Gradle plugin. Now that Android Studio is fully released along with V1.x of the Android Gradle plugin, we’ll revisit this project, take a look at what has changed, and bring it up-to-date so that it works with the latest build tools.

gradle_logoThe obvious first thing that we need to look at is the versions of both Gradle and the Android Gradle plugin that we’re going to use for the build. For Gradle we simply need to update the gradle-wrapper.properties file:

#Sun Dec 21 09:59:32 GMT 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-2.2.1-all.zip

All we need to do here is update to the latest version of Gradle (which is 2.2.1 at the time of writing).

Next we need to update to the latest Android build tools. Back in the original series we looked at how we could define certain build attributes such as target and minimum SDK versions in one place so that we only needed to change things one in order to apply those changes to all sub-projects. This is where we reap the benefits of that – we can change things in one place and it will change both of the child projects:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.0.0'
    }
}

ext.compileSdkVersion=21
ext.buildToolsVersion="21.1.2"
ext.minSdkVersion=7
ext.targetSdkVersion=21

While we’re at it, we’ll also switch the repository that we’re using to jcenter instead of Maven Central.

The next thing that we need to do is change the name of the plugins that we’re going to apply to the two child projects. This is because the plugin names were changed from android and android-library to com.android.application and com.android.library respectively. The other things worth doing is updating the version of the support library that we’re using:

apply plugin: 'com.android.library'

dependencies {
    compile 'com.android.support:support-v4:21.0.3'
}

android {
    compileSdkVersion rootProject.compileSdkVersion
    buildToolsVersion rootProject.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.minSdkVersion
        targetSdkVersion rootProject.targetSdkVersion
    }
}
apply plugin: 'com.android.application'

dependencies {
    compile 'com.android.support:support-v4:21.0.3'
}
.
.
.

That’s the basic changes done, but if we run this we get a failure:

gradle git:(master) ✗ gradle clean assemble

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/markallison/Dropbox/StylingAndroid/mia/AndroidStudio/gradle/GradleTest/build.gradle' line: 18

* What went wrong:
A problem occurred evaluating project ':GradleTest'.
> Could not find method packageName() for arguments [com.stylingandroid.gradle.simple] on GroupableProductFlavor_Decorated{name=simple, minSdkVersion=null, targetSdkVersion=null, renderscriptTargetApi=null, renderscriptSupportModeEnabled=null, renderscriptNdkModeEnabled=null, versionCode=null, versionName=null, applicationId=null, testApplicationId=null, testInstrumentationRunner=null, testHandleProfiling=null, testFunctionalTest=null, signingConfig=null, resConfig=null, mBuildConfigFields={}, mResValues={}, mProguardFiles=[], mConsumerProguardFiles=[], mManifestPlaceholders={}}.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 6.991 secs

It’s complaining that packageName is no longer supported, and this has since changed to applicationId so we need to change this accordingly:

apply plugin: 'com.android.application'

dependencies {
    compile 'com.android.support:support-v4:21.0.3'
}

android {
    compileSdkVersion rootProject.compileSdkVersion
    buildToolsVersion rootProject.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.minSdkVersion
        targetSdkVersion rootProject.targetSdkVersion
    }

    productFlavors {
        simple {
            applicationId "com.stylingandroid.gradle.simple"
        }

        complex {
            applicationId "com.stylingandroid.gradle.complex"
            dependencies {
                complexCompile project(':GradleLibrary')
            }
        }
    }
}
.
.
.

If we now run this again, we get a new error – it complains that the storeFile for the signingConfig does not exist:

FAILURE: Build failed with an exception.

* What went wrong:
Some problems were found with the configuration of task ':GradleTest:packageSimpleDebug'.
> No value has been specified for property 'signingConfig.storeType'.
> File 'task ':GradleTest:android.injected.signing.store.file'' specified for property 'signingConfig.storeFile' does not exist.

Here I must confess to a bug in the code in the original article. In the code where we add custom tasks to the existing dependencies, the piece of code which defines the task we wish to add appears outside of the check that the taskName matches a specific pattern – so we’ll effectively replace the implementation of all tasks which get added after we set up this handler. In the current Android Gradle plugin the debug signing credentials get inject via a custom task – and this bug was blocking that. So we need to change this:

task custom(description: 'This is our custom task') << { task ->
    println "Running task ${task.name}"
}

assemble.dependsOn(custom)
assemble.dependsOn('customAssemble')

project.tasks.addRule("Pattern: customAssemble<TaskName>") { taskName ->
    if (taskName.startsWith("customAssemble")) {
        println "Creating task ${taskName}"
        android.applicationVariants.all { variant ->
            println "Adding dependency to assemble${variant.name}"
            def targetTask = project.tasks.findByName("assemble${variant.name}")
            if(targetTask != null) {
                targetTask.dependsOn("customAssemble${variant.name}")
            }
        }
        task(taskName) << { task ->
            println "Running custom task ${task.name}"
        }
    }
}

And with that, our project will now build with the current (at the time of writing) Android build tools – Android Gradle plugin V1.0.0 and Android Studio V1.0.2.

Although the project from the previous series now works, we’re not quite finished yet. I recently had to align an existing, rather more complex project with the release build tools and had some additional issues to resolve. In the final few Android Gradle plugin releases prior to the full 1.0.0 release, there were a number of tidy ups which removed some deprecated stuff. This meant that stuff which was working perfectly with the old deprecated methods suddenly failed. An example of this was the packageName deprecation which we encountered earlier. After I had updated all of these in the build config for the project I was still getting errors and I suspected that there were the build configs for third party libraries which were causing this.

The way to track this down was first to comment out all of the third party dependencies, and gradually re-add them one at a time to establish which of these libraries were causing the problem. Then it was a case of checking for a newer version of the libraries that were failing – and in each problem case I found a newer version was available which was compliant with 1.0.0 – so it was simply a case of changing the version number in the dependency declaration. Once all of these has been identified and updated, the build worked perfectly!

That concludes our Gradle update. The source code for this article is available here.

Many thanks to Sebastiano Poggi for the conversation which prompted this article.

© 2014, Mark Allison. All rights reserved.

Copyright © 2014 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.