An advance build toolkit Gradle in Android Part-2



Welcome to Part 2 of the Gradle Tutorial. This part builds on Part 1, where we looked at basic understanding of build tools and Gradle features. In this article will discuss more on Gradle customization and its configuration with Android project.




Customize build configurations

Gradle customization and proper configuration can improve your Android development experience and speed.

A typical Android studio project has a project level build.gradle file and as many module-level build.gradle as there are modules.

Gradle and the Android plugin help you to configure lots of aspects of your build like: Build Types, Product Flavors, Build Variants, Manifest Entries, Dependencies, Signing of app, Obfuscation Rules, Multiple APK Support etc.

Let’s have look how to configure all of these and what all the benefit you can achieve via this customization:

Configure Build Types

For example, you want debug builds for developers, client builds that you share with our clients at the end of a sprint, and release builds that you upload to the Play Store. 

This is because you want certain features like logging or debugging enabled only during your development which you don’t want in the release build for security. So you can achieve this by using build type.

You can create and configure build types in the module-level build.gradle file using buildTypes block. When you create a new module, Android Studio automatically creates the debug and release build types for you.

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug {
            debuggable true
            shrinkResources false
            proguardFile '../debug-rules.pro'
        }
        client {
            debuggable true
            shrinkResources true
            proguardFile '../client-proguard-rules.pro'
        }
        release {
            debuggable false
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
}


Configure Product Flavors

You can use the productFlavors block in your module-level build.gradle file to define different variants of your product.

android {
    ...
    defaultConfig {...}
    buildTypes {...}
   
    productFlavors {
    prodFree {
        buildConfigField "String", "Flavour", "FREE"
        versionName = "1.0"
    }
      prodPaid {
        buildConfigField "String", "Flavour", "PAID"
        versionName = "2.0"
    }
    mock {
        buildConfigField "String", "Flavour", "MOCK"
        versionName = "3.0"
    }
   }
}

Build Variants

A build variant is a cross product of a build type and product flavor, and is the configuration Gradle uses to build your app. As you see above our possible build variants would be:

debugProdFree , clientProdFree, releaseProdFree
debugProdPaid, clientProdPaid, releaseProdPaid
debugMock, clientMock, releaseMock


Configure Signing Keys

When you have multiple build types, another thing you may want to do is use different signing keys for different build types. It is obvious that your signing keys would be different for different builds and you won’t want to edit your build.gradle file whenever you want to do a debug, client or release build.

To achieve this you can use the signingConfigs block in your module-level build.gradle file.

android {
    ...
    defaultConfig {...}
    // Define signing keys
    signingConfigs {
        debug {
            storeFile file('../keystore/debug.keystore')
        }
        client {
            storeFile file('../keystore/client.keystore')
        }
        release {
            storeFile file('../keystore/release.keystore')
        }
    }
   
    // Configure signing base on build types
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
            ...
        }

        client {
            signingConfig signingConfigs.debug
            ...
        }

        release {
            signingConfig signingConfigs.release
            ...
        }
    }


Configure ProGuard Rules

You can specify different ProGuard rules file for each build type or variant. To make smaller APK file, you should enable shrinking to remove unused code and resources in your release build. The build system can run ProGuard to shrink and obfuscate your classes during the build process.

You can again go through Build Type section, and notice that we already define different Proguard Rules for different build types. Same you can also configure for different build variant.


Configure Dependencies

Gradle makes easy to include external binaries or other library modules to your build as dependencies. The dependencies can be located on your machine or in a remote repository, and any transitive dependencies they declare are automatically included as well. Dependencies are usually managed at the Module-level inside dependencies block in build.gradle file.

android {
    ...
    defaultConfig {...}
    buildTypes {...}
    productFlavors {...}
}

dependencies {
    // Dependency on a local library module
    compile project(":mylibrary")

    // Dependency on local binaries
    compile fileTree(dir: 'libs', include: ['*.jar'])

    // Dependency on a remote binary
    compile 'com.android.support:appcompat-v7:25.0.0'
}


Dependency types

You can specify dependency configuration as:

Dependencies for test cases

testCompile - Compile dependency for local tests
androidTestCompile - Compile dependency for instrumented tests


Dependencies for different library variants to different app variants

debugCompile – Debug compile dependency for library variant
releaseCompile – Release compile dependency for library variant

When your dependencies are located at remote repository then you have to specify the repository location in the repositories block of your top-level build.gradle file. By default, Android Studio declare JCenter as the repository location. You can specify different repository location as mentioned below-

// Default JCenter as the repository location
allprojects {
    repositories {
        jcenter()
    }
}

// For Maven central repository add mavenCentral(), or for a local repository use mavenLocal():
allprojects {
    repositories {
        jcenter()
        mavenCentral()
        mavenLocal()
    }
}

// Specific repositories as follows:
allprojects {
    repositories {
        jcenter {
            url 'http://jcenter.bintray.com:80'
        }
        maven {
            url "file://local/repo/"
        }
        ivy {
            url "https://repo.example.com/ivy"
        }
    }
}


Source set

Gradle has many default configurations so that we don´t need to rewrite it every time we start a project. For instance, any module’s src/main/ source set includes the code and resources used by all its build variants. But we can alter this the way we want very 
easily from the sourceSets block:

src/main/
This source set includes code and resources common to all build variants.

src/buildType/
Create this source set to include code and resources only for a specific build type.

src/productFlavor/
Create this source set to include code and resources only for a specific product flavor.

android {
    ...
    defaultConfig {...}
    buildTypes {...}
    productFlavors {...}

sourceSets {
        main.java.srcDirs = ['src/main/java']

       // Socurce set based on product flavour
        prodFree.java.srcDirs = ['src/free/java']
        prodPaid.java.srcDirs = ['src/paid/java']       
        prodFree.res.srcDirs = ['src/free/res']
        prodPaid.res.srcDirs = ['src/paid/res']
    }  
 }

android {
    ...
    defaultConfig {...}
    buildTypes {...}
    productFlavors {...}

sourceSets {
        main.java.srcDirs = ['src/main/java']

       // Socurce set based on build variant    
        releaseProdFree.res.srcDirs = ['src/free/res']
        releaseProdPaid.res.srcDirs = ['src/paid/res']
    }   
}


Conclusion

As you can see Gradle is a very powerful build tool. With this article I have described a small part of customization that you can do with it. Hopefully I will come up with more interesting on this.

To find more interesting topics on Software development follow me at https://medium.com/@ankit.sinhal.


Comments

Popular posts from this blog

Android Performance: Avoid using ENUM on Android

Secure and smaller APK size using Proguard

Smart way to update RecyclerView using DiffUtil