Chapter 13. Gradle, the New Build System

If you’ve been working through all the chapters using Android Studio—or if you have been working in Eclipse and have been wondering what this new build system is all about—this chapter aims to answer some of the questions you might have. While Gradle is different from any of the Java and Android programming we have dealt with before, it will prove to be a handy tool in your arsenal for creating a new generation of Android applications.

Gradle is an existing build system that Android has adopted to replace its previous build system. Gradle creates a unified build experience between the IDE and the command line. In its current form, Eclipse has a different build system from Ant, meaning that the things you can do in Ant don’t always translate to things that you can build from Eclipse. Android Studio was built with Gradle in mind, and when you make changes to the Gradle file, Android Studio will respect those changes and will always exhibit the same behavior whether built from the command line or directly in the IDE.

Anatomy of a Gradle File

As you’ve come to expect, each new project will be generated with two Gradle files: a top-level Gradle file, to which you can add configurations to be used on all projects in the folder; and an inner Gradle file, which contains information for building the specific project that it’s located in. Since nearly all cases of using your build file will be on the inner Gradle file, that’s the one we are going to focus on. Go ahead and create a new project in Android Studio, or open an existing one, and let’s take a look. This inner Gradle file is located in <ProjectName>/<ProjectName>/src/build.gradle.

buildscript {
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath 'com.android.tools.build:gradle:0.6.+'
   }
}
apply plugin: 'android'

repositories {
   mavenCentral()
}

android {
   compileSdkVersion 18
   buildToolsVersion "18.1.0"

   defaultConfig {
      minSdkVersion 8
      targetSdkVersion 16
   }
}

dependencies {
   compile 'com.android.support:appcompat-v7:18.0.0'
}

Your new project should look something like the code above. Let’s dive into this build file to understand exactly what’s going on.

Buildscript and Plug-Ins

The top of every Android Gradle file should contain the buildscript, which contains two fields—repositories and dependencies—that contain information about which repository to fetch Gradle from and which version of Gradle to use. In most cases, you will be using mavenCentral as your repository, and you’ll use whatever version of Gradle that the new project wizard chooses for you.

When the Gradle version says 0.6.+, the + tells the build system to use whatever the highest level of Gradle version 6 is on the system. If 6.2 is available, it will use that; if 6.3 is available, it will use that, and so on. This prevents you from having to modify your build file in between minor releases of the build system. This section should rarely have to be modified. It only needs to be updated if you wish to change major versions of the build system; for instance, changing from 0.6.+ to 0.7.+.

buildscript {
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath 'com.android.tools.build:gradle:0.6.+'
   }
}
apply plugin: 'android'

repositories {
   mavenCentral()
}

Below the buildscript is apply plugin: 'android', which tells Gradle that you intend to use the Android plug-in to build your project. This is a key line in case you ever want to build an Android library project. In which case, you replace android with android-library, letting Gradle know to build this as a library instead of as an APK. Android library projects (known as .aar files) are a great way to distribute library code containing Android-specific classes and resources. They are an advanced subject and out of scope for our purposes, but it’s worth knowing they exist.

Lastly, repositories appears again, because we can fetch libraries from a source other than where we retrieve Gradle from. As you might expect, in most cases you’ll never have to modify this, but it’s good to know that you can.

The Android Stuff

Finally we arrive at the Android-specific stuff, the things that we are all comfortable with by now. The primary purpose of this portion of the build file is to tell Gradle which versions of Android we want to build our project with. Ideally, this information should match the values set in your AndroidManifest.xml file.

android {
   compileSdkVersion 18
   buildToolsVersion "18.1.0"

   defaultConfig {
      minSdkVersion 8
      targetSdkVersion 16
   }
}

Image compileSdkVersion. The version of Android that your application will be compiled with. As when creating a new project, this should be set to the newest version of Android that you can support.

Image buildToolsVersion. The version of the build tools to use. This has the chance to become outdated as you update your Android SDK over time. Keep an eye on your build tools version when using the SDK Manager, and update this value accordingly.

Image minSdkVersion. Used for filtering your application in Google Play. Only devices running at least the minimum version supported will be able to search for and download the application.

Image targetSdkVersion. The version of Android you designed the application for. This has an impact on various compatibility features that are enabled, so set this to the highest SDK possible so that you are never caught by surprise by the compatibility features that are enabled. For example, if you set your target SDK version to 11 (Honeycomb), all your EditTexts and ProgressBars will look as if they are on a version 11 device, even when it’s running something newer.

At the end of your Gradle file, depending on whether you selected some of the optional libraries (such as the support modes) when creating your project, you will see a section for dependencies. This is where some of Gradle’s great flexibility comes in, allowing you to add libraries easily and seamlessly to your project.

dependencies {
   compile 'com.android.support:appcompat-v7:18.0.0'
}

If you’ve been using Android Studio in the prior chapters, then you’re already vaguely familiar with this process. In this area, you can add new libraries, library projects, Java JAR files, and even locally added .aar files. After you add or remove a library, just select Tools > Android > Sync Project with Gradle Files to update your project to reflect the new configurations.

Build Types

Now that you have a general understanding of the different parts of a Gradle file, let’s see how to take it a step further and do some interesting things.

Build types is a concept that allows you different build configurations of a specific build. By default, Gradle uses two types—debug and release—but you can add as many types as you see fit for your purposes. In the following code, you can see where we are referencing the two default variants as well as adding our own third variant, named customType.

buildTypes {
   debug {
     ...
   }
   release {
     ...
   }
   customType {
     ...
   }
}

After adding the variants you wish, sync your project with the Gradle file, and the variants you added will be available for you to work with. In the lower-left corner of Android Studio, you can click the Build Variant tab (Figure 13.1), which will show you all the variants available to you. If you select one, Android Studio will install this variant onto your device or emulator when you run it.

Image

Figure 13.1 Select the build type you would like to run.

You might want to use a custom build type if you want a debug build that uses a different debug URL for your application’s content, or if you are making a different release build for different Android marketplaces, such as a release build for Google Play and a release build for the Amazon Appstore.

Another great feature of build types is their ability to programmatically affect the application at build time, thus allowing things like giving debug versions a different package name. This is particularly useful because it allows a debug version and a release version to be installed side by side.

android {
   compileSdkVersion 18
   buildToolsVersion "18.1.0"

   defaultConfig {
      minSdkVersion 8
      targetSdkVersion 16
   }

   buildTypes {
      debug {
         packageNameSuffix ".debug"
         versionNameSuffix ".debug"
      }
   }
}

As the highlighted code suggests, .debug will be added to both the package name and the version name, and this doesn’t require further modification to any other code in your project to make it work. Figure 13.2 shows all the options that can be overridden in the build types.

Image

Figure 13.2 Build type options you can override

Adding Values to BuildConfig

BuildConfig is a class generated by Android that contains information determined at build time. Previously, we have been able to use only BuildConfig to determine if the build you were running was a debug build, by checking the BuildConfig.DEBUG variable. This has limited usage. But with Gradle, we can add our own variables to BuildConfig. For example, let’s say you want to have a different logging tag for debug versions than for release versions. You could do this by checking the BuildConfig.DEBUG flag, but instead let’s add a variable to BuildConfig.

buildTypes {
   debug {
      packageNameSuffix ".debug"
      versionNameSuffix ".debug"
      buildConfig "public static final String TAG = "DEBUG";"
   }
   release {
      buildConfig "public static final String TAG = "RELEASE";"
   }
}

With these lines in your file, you can reference BuildConfig.TAG to get the appropriate tag, depending on whether it’s a release build or a debugging build. The buildConfig property is adding this string to the build file, which means that quotation marks need to be escaped, and if you want to add multiple properties, they are all added onto this one buildConfig. Here is what it would look like if you wanted to add multiple properties:

buildConfig "public static final String TAG = "RELEASE";" +
"public static final int AUTHORITY = "content://com.peachpit.release";"

Product Flavors

Product flavors are similar to build types in that they give you a different way of building your application; they are dissimilar in that they allow you to go further with build customization and add different source code and assets, depending on the build type. For example, let’s say you have an application that has a free version and a paid version. You could accomplish this with a build type by setting some buildConfig flags and adding a special .free or .paid suffix to your package name. But what if you want to change the application icon? Or, what if you want to add more graphics or code for the paid version? That’s where a flavor really starts to shine.

You can define a new flavor by adding a productFlavors section in the android section of your build file.

android {
   compileSdkVersion 18
   buildToolsVersion "17"

   defaultConfig {
      minSdkVersion 8
      targetSdkVersion 18
   }

   productFlavors{
      free {
         packageName "com.peachpit.free"
      }

      paid {
         packageName "com.peachpit.paid"
      }
    }
 }

With the product flavors defined in the manifest file, you can now add different source folders for them. For each flavor you want to support, you can add a new source directory in <ProjectName>/<ProjectName>/src/<FlavorName>. This directory will directly mimic the src/main folder for everything you would like to replace. If you would like a different application icon for your free version, then you can add it in flavorName/res/drawable-xhdpi/ic_launcher.png. The file must have the same name and be located in the same path location as where the original is located, or else it will not be properly overridden. Figure 13.3 shows the potential project structure supporting our two flavors and overriding the launcher icon. It’s important to note that all flavors will be based on the main source folder, differing only where you override the files.

Image

Figure 13.3 Project with separate source folders for flavors

Build Variants

Now that you know what you can accomplish with build types and product flavors, let’s bring them together to explain the concept of a build variant. A build variant is the combination of flavors and types. It is probably best explained by referring back to the Build Variants tab in the lower-left corner of Android Studio. Before we do that, go ahead and modify your build.gradle (located in <project name>/<project name>/build.gradle) to have the following types and flavors.

android {
   buildTypes{
      debug {
      }

      release {
      }

      amazon {
      }

  }
  productFlavors{
      free {
      }
      paid {
      }
  }
}

After syncing your Gradle file, check out the Build Variant tab. Click the Build Variant drop-down in the tab, and you should see six options. The relationship between build types and product flavors should now be immediately obvious (Figure 13.4). Each product flavor will build all of the different build types. This means that the example code will have debug, release, and Amazon builds for both your paid and free versions.

Image

Figure 13.4 Each product flavor builds each of the build types, resulting in a build variant.

Signing and Building

One of the last key pieces to building your applications for release is adding your signing key to the build file. There are many way to accomplish this, but one of the simplest is to add a signingConfig section to your build file.

android {
   signingConfigs {
      release {
          storeFile file("my-release-key.keystore")
          storePassword "****"
          keyAlias "****"
          keyPassword "****"
      }
   }
}

This keystore can be the same keystore we generated for publishing our application to Google Play from Chapter 12, “Publishing Your Application,” or it can be a new one. Refer back to Chapter 12 if you need a refresher on how to generate one. By adding this, you are saying “use this signing key when generating the release build type.” Be careful when you’re adding your credentials to this file; you want to make sure that you don’t accidentally commit your keystore’s password and other information to your version control system.

With everything in place, the last thing you need to do is run the following command from the root directory of your project:

./gradlew build

gradlew stands for Gradle Wrapper, and build will kick off all the tasks necessary to build all the variants in your project. After the build is finished, you’ll find all of your APKs in the <projectName>/<projectName>/build/apk folder of your project, and all of them will be named appropriately for their product flavor and build type.

Wrapping Up

I’ve covered only the tip of the iceberg of what is possible using the new Gradle build system. Pulling in specific versions of libraries, modifying build variables to be referenced in your projects, and creating your own build variants are just some of the things that were never possible before. If you want to explore more, read the official Gradle Plugin User Guide, located at http://tools.android.com/tech-docs/new-build-system/user-guide, where you will find a lot of the information provided in this chapter, plus so much more.

By following along through this chapter, you are leaps and bounds ahead of the game because you understand the basics of how Gradle works. As the Gradle plug-in for Android continues to evolve, you will have a better understanding of how the pieces are supposed to fit together, and you’ll be at the forefront of the Android build technology.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset