It is fairly common in enterprise development to support multiple environments, be it development, a multitude of testing, performance testing, beta and production environments. This requirement is no different for Android development. My current client has close to 20 pre-production environments that support development, various forms of QA, performance, and production support environments.

It is typical to have a different URL or set of URLs to connect to, specific to each environment. Until the new gradle build system came along, creating an APK for a specific environment was a chore. It required manual changes to files or a bunch of scripting in ANT. There is a very powerful, but little documented feature of the Android DSL for gradle for adding additional fields to the generated BuildConfig class. By leveraging this feature and product flavors, there's no more swapping out of URLs and doing a build manually. Your different APKs will be built with the appropriate configuration.

Let's look at example. The following gradle snippet shows 3 product flavors: "dev", "qa", and "prod." Each of these has a "base url" defined for each environment.

 productFlavors {
 def BASE_ENDPOINT = "BASE_ENDPOINT"

 dev {
 applicationId "com.captechconsulting.unanet.dev"
 buildConfigField "String", BASE_ENDPOINT, '"http://my-dev-url.fakehost.com/"'
 }

 qa {
 applicationId "com.captechconsulting.unanet.qa"
 buildConfigField "String", BASE_ENDPOINT, '"http://my-qa-url.fakehost.com/"'
 }

 prod {
 applicationId "com.captechconsulting.unanet"
 buildConfigField "String", BASE_ENDPOINT, '"http://my-pro-durl.fakehost.com/"'
 }
 }

Each product flavor contains a buildConfigField identifying the appropriate URL. This field consists of three parts:

  1. The first value will be the Java type that is used (java.lang.String here)
  2. The second value is what the variable name will be (so follow valid variable naming standards)
  3. The third value is the actual value that will be created in the file.

Let's take a quick look at the generated output of a BuildConfig for the qa product flavor, debug build type:

public final class BuildConfig {
 public static final boolean DEBUG = Boolean.parseBoolean("true");
 public static final String APPLICATION_ID = "com.captechconsulting.unanet.qa";
 public static final String BUILD_TYPE = "debug";
 public static final String FLAVOR = "qa";
 public static final int VERSION_CODE = 10001;
 public static final String VERSION_NAME = "1.0.0";
 // Fields from product flavor: qa
 public static final String BASE_ENDPOINT = "http://my-qa-url.fakehost.com";
}

Now we can reference a single variable within our java code that will be the appropriate environment specific URL. In this example, we're setting up a REST adapter for Retrofit:

 RestAdapter.Builder builder = new RestAdapter.Builder();
 builder.setEndpoint(Endpoints.newFixedEndpoint(BuildConfig.BASE_ENDPOINT));
 return builder.build();

By leveraging the custom build config fields and product flavors, we can create environment specific APKs with no change to our Java code. This can be leveraged for all sorts of environment specific configuration such as turning logging on/off for included libraries, Play Services configuration, or other enterprise configuration specific to your application.