Setting up Different Environments in Android Studio using Build Variants (Native and React Native)

Chloe Mcmullan
easyfundraising.org.uk
6 min readNov 11, 2021
Photo by Dan Stark on Unsplash

As developers, we all know that there’s typically an easy way to do something and a right way to do something. I’ve seen some crazy implementations of swapping between environments, and some simple implementations too. I’m here to let you know that setting up different environments for your Android project is (thankfully) simple. In fact, Android Studio makes it straightforward to swap between highly secure production code and less secure debug code too — but that’s a topic for another day!

Although I’ve included React Native in this guide, you may not even need to split out your Android environments if your native code is particularly straightforward or follows the same flow for both production and staging. At easyfundraising, we needed this to swap between API keys required by the native code bases. Just know that it isn’t wrong to use the same set up for both environments where they use the same logic and keys. But even in that scenario, it can be useful to use Build Variants to allow a staging and a production version of the same app to be installed on a device.

A Quick Guide

If you want a picture tutorial with clear step by step, scroll down to “Getting Started”. If you want ideas of how they can be used, scroll down to “Examples of Things to Change”. Here’s the TLDR:

  1. Enter your project and ensure your gradle is synced.
  2. File > Project Structure. Choose Build Variants pane. Choose Build Flavors tab.
  3. Click the + and choose Add Flavor Dimension. Name this the property you’ll be differentiating on (e.g. env).
  4. Click the + and choose Add Product Flavor. Name it the environment you’ll be pointing . Do this for all of the environments (e.g. staging and production).
  5. Edit any additional configurations inside and click OK when done.
  6. Resync your gradle. You should now see two options in your Build Variants tab.

Getting Started

Open up your project in Android Studio. For a native Android application, this will be opening the entire project folder. For a React Native application, this will be opening your android folder. If you’re having trouble getting your project to open without errors (a surprisingly common issue), try File > Invalidate Caches / Restart and click Invalidate and Restart. If that fails, you’ll need to resort to StackOverflow.

The `Invalidate Caches / Restart` functionality which has gotten me out of many “Why isn’t it building?” situations
The magic `Invalidate Caches / Restart` option.

Assuming all has gone well up to now (it doesn’t always), you should be able to sync your gradle files and get started.

Build Variants and Product Flavors

Open File > Project Structure, or press Control + Alt + Shift + S on Windows or Command + ; on Mac. When the Project Structure dialog appears, choose the Build Variants pane.

The Project Structure dialog, opened to the Build Variants pane. Two settings already exist: release and debug.
The Project Structure dialog opened to the Build Variants pane.

The Build Variants allows control over the way your application is built. In the Build Types tab, you already have two created: release and debug. This allows you to control if the app should be built differently depending on this state, or if functionality should be exposed that otherwise wouldn’t have. However, to allow for different environments, the tab that we’re interested in is the Flavors tab.

A close up of the Project Structure dialog, with the Build Variants pane open and the Flavors tab selected. The ‘+’ has been clicked and ‘Add Flavor Dimension’ is being hovered over.
The dropdown to add a new Flavor Dimension or a new Product Flavor.

Add a new Flavor Dimension to hold the type of flavor you’re going to be differentiating on. For the purpose of this guide, that’s environments(or env for short). Next, choose Add Product Flavor and create a flavor for both staging and production.

Take a look at the different configurations available and decide if you want to add any extra configurations here. For example, I want my staging app to end with .staging so I set that on the staging Application ID Suffix. This allows me to have both the staging and the production version of the application downloaded to the same android device without overriding each other.

Project Structure dialog opened on the Build Variants pane. The Flavors tab is opened, with the Flavor Dimension env added. Under env, there are two Product Flavors: staging and prod. The staging flavor is selected and an Application ID Suffix of ‘.staging’ was added.
Setting the Application ID Suffix to .staging to allow for both the production and staging application to be installed on one device.

Once you have completed the configurations (which can always be changed at a later date), click Apply or OK. You’ll need to sync your Gradle files again as this will have applied changes to the build.gradle (:app) file.

flavorDimensions 'env'
productFlavors {
staging {
dimension 'env'
applicationIdSuffix '.staging'
}
prod {
dimension 'env'
}
}

You should also have two new options in your Build Variants pane (opened bottom left of your Android Studio Window). You can use this to swap between the different variants.

A close up of the Build Variants pane, showing the different types of Build Variants available. ‘stagingDebug’ is hovered.
The different Build Variants available.

If you’re using React Native, you may notice that react-native run-android no longer works. To fix this, you just need to add the variant you wish to build and any suffix it now has:

react-native run-android --variant StagingDebug --appIdSuffix staging

Tah-dah! The process is complete and you can now use these to differentiate however you want.

Examples of Things to Change

App Icon

So you now have both your staging and production app installed on the same device. The problem is they have the same icon so how can you tell them apart? You could add Staging to the end of its name, but it’s already cut off with ellipsis so you wouldn’t see it unless you put it at the start (which you can!). At easyfundraising, we differentiate using different app icons.

Right click the app > res folder, and add a new Image Asset.

The file structure is shown. The app > res folder is right clicked, ‘New’ is highlighted and ‘Image Asset’ is hovered.
Adding a new Image Asset in the app > res folder.

This will present you with a dialog for adding a new Image Asset. For the purposes of this demo, I’ve just chosen to make my staging app use the text feature, but you can do an image of your choice instead. Once you’re happy that your asset appears as you want it to, click Next.

The ‘Configure Image Asset’ dialog, with the ‘Text” tab chosen and the word ‘Staging’ used.
The Configure Image Asset dialog used to set the icon to the word ‘Staging’.

From the Res Directory dropdown, choose the correct flavor for your staging environment. Then click Finish.

Now, when you rebuild your application, it should show you the new icon on the environment you updated it for.

Two different icons for the same application. One is the default icon, and the other is the word ‘Staging’
Two different icons depending on the build. Much harder to get confused between them.

Data Unique to the Environment

Need to flip between data (for example, API IDs) depending on which environment you’re pointing at? No problem!

Open up your build.gradle (:app) file and locate where the product flavors are defined. Next, add a line of code to each of the flavors to indicate what value it should be using, in the format:

buildConfigField "{data type}", "{config name}", '{config value}'

For example, my API resource might look like this:

flavorDimensions 'env'
productFlavors {
staging {
dimension 'env'
applicationIdSuffix '.staging'
buildConfigField "String", "API_ID", '"API_ID/staging"'
}
prod {
dimension 'env'
buildConfigField "String", "API_ID", '"API_ID/production"'
}
}

Notice that for string fields, you need to double enclose the value: '"{value}"'.

Once you’re happy with the values, sync your gradle and Build > Make Project. You can now access this field inside the Android native codebase using the BuildConfig field:

Typing `BuildConfig.` presents a list of options from the BuildConfig file, including the new API_ID value.
Like magic, it’s appeared!

There are many other ways to use the Build Variants, but hopefully, this has helped you get started in some of the more fundamental ways.

--

--

Chloe Mcmullan
easyfundraising.org.uk

React Native (TypeScript) and Android Native (Kotlin) Developer. Greyhound enthusiast.