Back to Home

A few Gradle chips for your Android application / Rambler Group Blog

android gradle

Several gradle chips for your Android application



    One of the latest Android Weekly newsletters included an article that mentioned interesting features of the project’s assembly organization. After reading it, I wanted to share some of what I use to configure the assembly of the Android project.


    Getting rid of code duplication in your build.gradle files


    It would seem a simple idea, but this approach is used quite rarely.

    Suppose you have several modules in the application, in each of which you need to register buildToolsVersion. Often this problem is solved by putting a specific version into an ext-variable.
    In addition, you can optimize the code by setting this value in only one place.

    Let me remind you of the possibility of using code from another gradle file in your build.gradle:

    apply plugin: 'com.android.application'
    apply from: "$buildSystemDir/application.gradle"
    

    And in the application.gradle file, you can already specify the necessary versions:

    android {
       compileSdkVersion 24
       buildToolsVersion "24.0.1"
       defaultConfig {
           minSdkVersion 15
           targetSdkVersion 24
           testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
       }
       compileOptions {
           sourceCompatibility JavaVersion.VERSION_1_7
           targetCompatibility JavaVersion.VERSION_1_7
       }
    }
    

    Here you can make any settings for the entire project. Then, in each specific module, you can override the values ​​(if necessary).

    In a separate gradle file, you can take out not only the android - extension configurations, but also test dependencies, jacoco, findbugs, pmd settings, etc. etc.

    Add properties to the project


    You may have already noticed the $ buildSystemDir variable. It is specified in the build.gradle file of the root project:

    allprojects {
       it.extensions.add("buildSystemDir", "$rootProject.projectDir/buildSystem/")
    }
    

    After that, in each module, you can use this property without any prefixes. Which, again, slightly reduces the code;)

    Signature apk


    The topic of securely storing keys and passwords for a certificate is very interesting, and I will be very happy if someone tells me a good solution (with ci, safe), but for now I’ll give you my version.

    Information about each certificate is stored in a * .properties file. It may or may not be present on the project assembly machine.

    sign.gradle:
    Properties signProp = new Properties()
    try {
       signProp.load(rootProject.file('signForTest.properties').newDataInputStream())
       project.ext {
           forTest = new Object() {
               def storeFile = signProp.get("forTest.storeFile")
               def storePassword = signProp.get("forTest.storePassword")
               def keyAlias = signProp.get("forTest.keyAlias")
               def keyPassword = signProp.get("forTest.keyPassword")
           }
       }
    } catch (IOException e) {
       project.ext {
           forTest = new Object() {
               def storeFile = "/"
               def storePassword = ""
               def keyAlias = ""
               def keyPassword = ""
           }
       }
    }
    android {
       signingConfigs {
           forTest {
               storeFile file(project.ext.forTest.storeFile)
               storePassword project.ext.forTest.storePassword
               keyAlias project.ext.forTest.keyAlias
               keyPassword project.ext.forTest.keyPassword
           }
       }
    }
    

    That's all. It remains to apply this file in the build.gradle of our application and use the configured signingConfig in our buildType.

    buildSrc


    What to do when the build system needs complete code, and there is no time to write your plugin? To do this, you can use the buildSrc directory.

    In the root directory of your project (where gradlew lies), create a new buildSrc module. This module should be a regular java project (or groovy or something else), with the following build.gradle file:

    apply plugin: "groovy"
    repositories {
       mavenCentral()
    }
    dependencies {
       compile localGroovy()
       compile gradleApi()
    }
    // START SNIPPET addToRootProject
    rootProject.dependencies {
       runtime project(path)
    }
    // END SNIPPET addToRootProject
    

    Now in this project you can create some class Awesome.groovy, and import and use this class in the build.gradle Android module.

    When you start building your project, the buildSrc module will be executed first. After that, the remaining modules will be configured.

    I can’t say that I recommend using this solution, because this slightly increases the build time of the project from scratch. But in extreme cases it can come in handy.

    Flavor dimensions


    This feature for configuring a project is well described in the docks (// tools.android.com/tech-docs/new-build-system/user-guide#TOC-Multi-flavor-variants
    ). But either not everyone knows about it, or they don’t understand in what cases it can be used, so I decided to talk about it.

    Suppose you need to create a paid and free application. At the same time, your application is released for TVs, tablets and phones. Moreover, your application is published in different markets.

    Add the following code to your build.gradle:

    android {
       flavorDimensions "device", "paid", "market"
       productFlavors {
           tv {
               dimension 'device'
           }
           tablet {
               dimension 'device'
           }
           phone {
               dimension 'device'
           }
           free {
               dimension 'paid'
           }
           premium {
               dimension 'paid'
           }
           google {
               dimension 'market'
           }
           amazon {
               dimension 'market'
           }
       }
    }
    

    By announcing 7 flavors in three different groups, you get as many as 12 different application options. We add here buildTypes, and we get a huge amount of apk-shek.

    phoneFreeGoogleDebug
    phoneFreeGoogleRelease
    phoneFreeAmazonDebug
    phoneFreeAmazonDebug
    phonePremiumGoogleDebug
    .... etc.

    Each flavor you declare creates its own sourceSet. For example, if you selected the phoneFreeAmazonDebug flavor, the following sourceSets will be used:

    src / phoneFreeAmazon
    src / phoneFree
    src / phoneAmazon
    src / freeAmazon
    src / phone
    src / free
    src / amazon

    Thus, there are great opportunities for customizing assemblies.

    Specify minSdkVersion for buildType


    To speed up the assembly of the application at the development stage, it is often recommended to create a separate flavor “develop” and specify minSdkVersion = 21 for it. However, this is not very convenient, and you often want to specify this parameter in buildType debug. Initially, the build plugin does not allow this, however, if necessary, this problem can be solved by the following hike.

    For the desired buildType, you need to add the ext variable:

    …
    buildTypes {
    ...
       debug {
    ... 
           ext.minSdkVersion = 21
       }
    }
    

    Below you need to add the following code:

    preBuild.doFirst {
       android.applicationVariants.all {
           if (it.buildType.hasProperty("minSdkVersion")) {
               int i = it.buildType.ext.minSdkVersion;
               it.mergedFlavor.setMinSdkVersion(new com.android.builder.core.DefaultApiVersion(i))
           }
       }
    }
    

    Now for all your flavors in the debug assembly, minSdkVersion will be 21. However, there is a tight tie to the plugin's inside, so something might break when updating the plugin version. Therefore, I can not recommend using this hack - the choice is yours.

    Instead of a conclusion, I want to note that Gradle is a very powerful tool for building a project. If you pay a lot of attention to the quality of the code of your application, then do not forget to tidy up the code in the build.gradle files as well.

    Read Next