Using Android Studio and Gradle to build Android packages for both Google Play and the Amazon App Store

Subscribe
17
Sep

Using Android Studio and Gradle to build Android packages for both Google Play and the Amazon App Store

A blog posted by Ryan

Gradle, the new build system for Android Apps if you are using Android Studio (if you're not you're missing out on a lot of great features) is a huge help if you need to build multiple versions of you apps.

Maybe you offer a free and a paid version, or you distribute your apps in multiple stores, and each version is slightly different. In the past, under the Ant build system, there was little help if you needed to do this. Usually the best option was to split your codebase into libraries, and then have a separate project for each version that links to the common code between the libraries.

But now, you can easily use Gradle to setup as many builds as you need, all from one codebase.

As an example, I had a project that needed a simple change between the build for the Google Play Store and the Amazon App Store. The app contained a link to the app stores, showing other related apps. To meet the app stores terms, and provide the best experience for the user, the link should link back to the store the app was downloaded from, either Google Play or the Amazon App Store. Also, the signing requirements were different between the stores.

To achieve this, you can use Gradle to setup new build types, which is as easy as adding a new build type under the buildTypes container in you build.gradle file.

Here's my build types, to support both Amazon and Google Play.

buildTypes {
      // This one happens automatically so you can leave it commented out.
      // debug {
      //    signingConfig signingConfigs.debug
      // }

      //
      // Release build for default store (Google Play)
      //
      release {
          signingConfig signingConfigs.release
          runProguard true
          proguardFile 'proguard.cfg'
      }

      //
      // Debug build for amazon store
      //
      amazonDebug {
          signingConfig signingConfigs.debug
      }

      // 
      // Release build for Amazon app store.
      // Notice, it is not signed which is what we want for Amazon
      //
      amazonRelease {
          runProguard true
          proguardFile 'proguard.cfg'
      }
  }

This has added an extra two build types, namely amazonDebug and amazonRelease, to the default build, so when building we will now get 4 apk's, debug, release, amazonDebug, and amazonRelease. This is all good, but you may be wondering why bother with amazonDebug, isn't it the same as the default debug build? Yes, good spot. But the really powerful part comes next.

You can now create a new source folder for each build type you have defined. The files that you put in these folders get picked up depending on the build type. In this way you can customise the source for each build type. You can also do the same for resources, and assets.

If you are using the new Gradle project structure, then the default place it will look for the new source folders is under src, and you can add a folder for each build type. E.g. src/amazonDebug. You can also override the default, which I did as I wanted the 2 Amazon builds to share the same source, and I was using the old Eclipse project structure. To do this add the following to the sourceSets container in you Gradle file, choosing the folder that suits you.

sourceSets {
    ...
    debug.java.srcDirs = ['src-default']
    release.java.srcDirs = ['src-default']
    amazonDebug.java.srcDirs = ['src-amazon']
    amazonRelease.java.srcDirs = ['src-amazon']
}

Now, any source files under src-default will get picked up for debug and release builds, and files under src-amazon will get ignored. But for amazonDebug, and amazonRelease build the files under src-amazon will get picked up and the files under src-default will get ignored.

Then it was a simple case of adding a helper class to both folders, that sent the user to the correct stores.

In my case, I added the following to src-default folder.

public class IntentUtils {
    /**
     * Creates a intent that can be used to view more maps.
     * @return intent to fire to show more maps
     *
     */
    public static Intent createMoreMapsIntent() {
        Intent intent = new android.content.Intent(
                android.content.Intent.ACTION_VIEW,
                Uri.parse("http://market.android.com/search?q=pub:\"pub_name_goes_here\""));
        return intent;
    }
}

And in the src-amazon folder I added the same class as follows.

public class IntentUtils {
    /**
     * Creates a intent that can be used to view more maps.
     * @return intent to fire to show more maps
     *
     */
    public static Intent createMoreMapsIntent() {
        Intent intent = new Intent(
                Intent.ACTION_VIEW,
                Uri.parse("http://www.amazon.com/gp/mas/dl/android?s=search_term_goes_here"));
        return intent;
    }
}

And that's it, now whenever I build a release pack I get the Google Play, and Amazon App Store, apk's, both with the correct signatures and links back to their respective stores.

This is just touching the surface of the true flexibility of Gradle. You can also use the same technique to swap resources between builds, and much more complicated sections of code. But I hope this gives you a taste of what's possible, and some of the benefits of switching to the new build system.