Setting up Different Environments in Android Studio using Build Variants (Native and React Native)
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:
- Enter your project and ensure your gradle is synced.
File > Project Structure
. ChooseBuild Variants
pane. ChooseBuild Flavors
tab.- Click the
+
and chooseAdd Flavor Dimension
. Name this the property you’ll be differentiating on (e.g.env
). - Click the
+
and chooseAdd Product Flavor
. Name it the environment you’ll be pointing . Do this for all of the environments (e.g. staging and production). - Edit any additional configurations inside and click
OK
when done. - 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.
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 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.
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.
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.
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
.
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
.
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.
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:
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.