React Native | Set up flavours — dev, staging, prod using react-native-config | Update app icon | 2023

Balamurugan V
6 min readJun 18, 2023

--

Hello everyone! Hope you’re all doing great. Happy to share yet another development experience, which would be useful for fellow react native engineers who wants to set up different flavours for a react native app.

This app has been built from the boilerplate — Check out my article here: https://medium.com/@svbala99/react-native-typescript-boilerplate-2023-useful-git-tools-husky-with-commitlint-ohmyzsh-e0800b8e3b0d that has git commit hook and ohmyzsh.

Android Part:-

In mobile applications, we have something called “mode” and “flavour” — just the categorisation of the apps. They have their variants as follows:-

Mode:-

  1. debug mode : the one that requires metro bundler to run along (apps in this mode can’t work stand alone when detached from metro). Typically released in APK format.

2. release mode : the one that can run independently without the suppport of metro bundler. Typically released in APK format.

Flavour:-

It depends on our needs. Typically production grade apps would have three flavours:-

1. development (Used by dev’s during the development phase)

2. staging (Used by QA team to do all rounds of testing just before releasing out to LIVE)

3. production (the one that goes LIVE on Google Play or App Store)

Step 1: Install react-native-config

yarn add react-native-config

Step 2: Update root > android > app > build.gradle

apply plugin: "com.android.application"
.......
project.ext.envConfigFiles = [
productiondebug: ".env.production",
productionrelease: ".env.production",
developmentrelease: ".env.development",
developmentdebug: ".env.development",
stagingrelease: ".env.staging",
stagingdebug: ".env.staging"
]
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"

.......
import com.android.build.OutputFile

......
......
......
android{
compileSdkVersion .....
flavorDimensions "default"
productFlavors {
production {
applicationIdSuffix "rn2023reduxdetox.production"
resValue "string", "build_config_package", "com.rn2023reduxdetox"
}
staging {
applicationIdSuffix "rn2023reduxdetox.staging"
resValue "string", "build_config_package", "com.rn2023reduxdetox"
}
development {
applicationIdSuffix "rn2023reduxdetox.development"
resValue "string", "build_config_package", "com.rn2023reduxdetox"
}
}
buildTypes{
signingConfig .....
matchingFallbacks = ['debug', 'release']
}
}

project.ext.envConfigFiles = […] instructs the android system that it has different files for different configuration. In this case, we have development, production and staging. The builds are associated with the corresponding configuration for flavours.

apply from: project(‘:react-native-config’)….. line of code tells android system to fetch the path for the project and append .env files to the gradle.

Step 3: Create .env files for each configuration

— At the root level of the project, create four files:

.env

ENV=root

.env.development

ENV=development
URL=https://reqres.in

.env.staging

ENV=staging
URL=https://jsonplaceholder.typicode.com

.env.production

ENV=production
URL=https://dummyjson.com

Step 4: Update scripts in package.json

        "android:staging": "react-native run-android --mode=stagingdebug --appId rn2023reduxdetox.staging",
"android:staging-release": "react-native run-android --mode=stagingrelease --appId rn2023reduxdetox.staging",
"android:dev": "react-native run-android --mode=developmentdebug --appId rn2023reduxdetox.development",
"android:dev-release": "react-native run-android --mode=developmentrelease --appId rn2023reduxdetox.development",
"android:prod": "react-native run-android --mode=productiondebug --appId rn2023reduxdetox.production",
"android:prod-release": "react-native run-android --mode=productionrelease --appId rn2023reduxdetox.production"

"ba": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res",
"ra": "rm -rf android/app/src/main/res/drawable-hdpi && rm -rf android/app/src/main/res/drawable-mdpi && rm -rf android/app/src/main/res/drawable-xhdpi && rm -rf android/app/src/main/res/drawable-xxhdpi && rm -rf android/app/src/main/res/drawable-xxxhdpi && rm -rf android/app/src/main/res/raw && npx jetify",
"androidProductionReleaseBundle": "yarn clean && cd android && ./gradlew bundleProductionRelease && killall -9 java && open ./android/app/build/outputs/bundle/production/release",
"androidDevelopmentDebugAPK": "yarn clean && cd android && ./gradlew assembleDevelopmentDebug && killall -9 java && open ./android/app/build/outputs/apk/development/debug",
"androidDevelopmentReleaseAPK": "yarn clean && cd android && ./gradlew assembleDevelopmentRelease && killall -9 java && open ./android/app/build/outputs/apk/development/release",
"androidProductionDebugAPK": "yarn clean && cd android && ./gradlew assembleProductionDebug && killall -9 java && open ./android/app/build/outputs/apk/production/debug",
"androidProductionReleaseAPK": "yarn clean && cd android && ./gradlew assembleProductionRelease && killall -9 java && open ./android/app/build/outputs/apk/production/release",
"androidStagingDebugAPK": "yarn clean && cd android && ./gradlew assembleStagingDebug && killall -9 java && open ./android/app/build/outputs/apk/staging/debug",
"androidStagingReleaseAPK": "yarn clean && cd android && ./gradlew assembleStagingRelease && killall -9 java && open ./android/app/build/outputs/apk/staging/release"
  • These set of commands quickly help us to run the app in particular flavour, also to open the file explorer once the APK is generated of each type of flavour.

Step 5: In react native app, retrieve it like this:-

import Config from 'react-native-config';
...
...
...
console.log(Config.URL) // prints URL from whichever flavour you run the app

Step 6: Create folders inside android > app > src folder

  • Copy paste “main” folder thrice, and rename them as the same name we provided in build.gradle : development, staging, production
  • Delete “java” folder inside all those 3 folders
  • Inside each of these 3 folders, > res > values > strings.xml — update the app name with whatever required like this : “My Dev App”, “My Staging App”, …
  • Delete AndroidManifest.xml files inside “development” and “production” folders.
  • Don’t disturb these folders : debug, release, main

Step 7: Get the icon set for all sizes from websites like https://www.appicon.co/

  • You will get a zip file like this:
  • Unzip it and you will find icons for all sizes like this.
  • Go inside android folder, you can see the following folders:
  • Now copy paste these folders onto the three folders: development, staging, production — res folder. Replace the existing folders of same names.
  • You can create rounded icons too from the same website and thus the folders could contain images : “ic_launcher.png” and “ic_launcher_rounded.png” under each folder.

Step 8 : Issue the appropriate command to run the app in debug mode or release an APK from required flavour

yarn androidDevelopmentDebugAPK // run app in dev flavour, debug mode
yarn androidDevelopmentReleaseAPK // Generate dev APK
yarn androidProductionDebugAPK // run app in prod flavour, debug mode
yarn androidProductionReleaseAPK // Generate prod APK
yarn androidStagingDebugAPK // run app in staging flavour, debug mode
yarn androidStagingReleaseAPK // Generate staging APK
yarn androidProductionReleaseBundle // generate bundle of prod flavour

Step 9: Now it’s turn for iOS counterpart

In the podfile inside iOS folder, add this line:
…..

pod ‘react-native-config/Extension’, :path => ‘../node_modules/react-native-config’

……..

Create Different scheme for different flavours:

In Xcode, select Product>Scheme>New Scheme. Select the project in dropdown and enter scheme name. And click ok to create the same.

Create two Pre-actions in Xcode -> scheme > Edit scheme. To create env file inside ios folder and use the same. Select project in provide build settings drop down.Add below scripts and close.

Script 1:

rm "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
echo ".env.development" > /tmp/envfile

Script 2:

"${SRCROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb" "${SRCROOT}/.." "${SRCROOT}/tmp.xcconfig"

Do the same for Production also.

To change iOS app icon, from the same app icons website, you would’ve got a folder of images that is required for iOS — different file sizes. Add it inside the Xcode > Projects > Images > Double click different sizes such as 20 x 20, 40 x 40, etc.

Re-install the app freshly now, you should be able to see the new app.

Voila!!! 👏 👏 We’ve completed different env setup for IOS too.🥳

TL DR;

You can find my repo here for the aforementioned items : https://github.com/svbala99/RN2023-redux-detox

Woohoo…! We’ve completed the flavours set up and icon set along with the quick and handy commands to run to generate APKs or to run app on the required flavour.

See you next time in yet another useful write up. Until then, stay healthy, Cheers!!!

--

--

Balamurugan V

Javascript enthusiast | Front end Engineer | Proud Tamilian