DEV Community

Cover image for React Native: Multiple Environments Setup (Schemas/Flavors)
Leon Arantes
Leon Arantes

Posted on

React Native: Multiple Environments Setup (Schemas/Flavors)

Many times when developing an application, we developers need to create different builds with different configurations. Facilitating the maintenance and testing process. Usually 3 different builds are created: development, staging and production.

 

Installing react-native-config

Install the package

// yarn 
yarn add react-native-config

// npm 
npm install react-native-config --save
Enter fullscreen mode Exit fullscreen mode

For iOS also run pod install after package is installed.

And below line of code to android/app/build.gradle to apply plugin

apply plugin: "com.android.application"
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" // <- add this line
Enter fullscreen mode Exit fullscreen mode

 

Create .env files for each configuration

.env.development

ENV=development
API_URL=https://api.dev.com
Enter fullscreen mode Exit fullscreen mode

.env.staging

ENV=staging
API_URL=https://api.staging.com
Enter fullscreen mode Exit fullscreen mode

.env.production

ENV=production
API_URL=https://api.com
Enter fullscreen mode Exit fullscreen mode

 

Setup for Android

Now we need to define envConfigFiles in build.gradle associating builds with env files. To achieve this, add the below code before the apply from call, and be sure to leave the build cases in lowercase.

android/app/build.gradle

apply plugin: "com.android.application"

// add this block
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.gradl
Enter fullscreen mode Exit fullscreen mode

Adding Product Flavor on project below line compileSdkVersion

android/app/build.gradle

android {
    ndkVersion rootProject.ext.ndkVersion
    compileSdkVersion rootProject.ext.compileSdkVersion

    // add this block
    flavorDimensions "default"
    productFlavors {
        production {
            minSdkVersion rootProject.ext.minSdkVersion
            applicationId "com.zenix"
            targetSdkVersion rootProject.ext.targetSdkVersion
            resValue "string", "build_config_package", "com.zenix"
        }
        staging {
            minSdkVersion rootProject.ext.minSdkVersion
            applicationId "com.zenix.staging"
            targetSdkVersion rootProject.ext.targetSdkVersion
            resValue "string", "build_config_package", "com.zenix"
        }
        development {
            minSdkVersion rootProject.ext.minSdkVersion
            applicationId "com.zenix.development"
            targetSdkVersion rootProject.ext.targetSdkVersion
            resValue "string", "build_config_package", "com.zenix"
        }
    }
   // ---
...
Enter fullscreen mode Exit fullscreen mode

Names should match based on productFlavors, so productiondebug will match debug in this case and generate debug build of App with configuration from .env.production.

Also add matchingFallbacks in buildTypes as shown below:
android/app/build.gradle

 buildTypes {
        debug {
            signingConfig signingConfigs.debug
            matchingFallbacks = ['debug', 'release'] // <- add this line
        }
        release {
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
Enter fullscreen mode Exit fullscreen mode

Create scripts on package.json

"android:staging": "react-native run-android --variant=stagingdebug",
"android:staging-release": "react-native run-android --variant=stagingrelease",
"android:dev": "react-native run-android --variant=developmentdebug",
"android:dev-release": "react-native run-android --variant=developmentrelease",
"android:prod": "react-native run-android --variant=productiondebug",
"android:prod-release": "react-native run-android --variant=productionrelease",
Enter fullscreen mode Exit fullscreen mode

Android Change App name and App Icon

Just copy the android/app/main folder and rename it to the referring names placed in the flavors in our case we put it
development and staging.

  • Duplicate main file
    Image description

  • Rename file to development or staging and remove file java
    Image description

  • To change the app icons, just add it inside the specific mipmap of the build development, staging or main(production).

  • To change app name, open file and rename

android/app/src/development/res/values/strings.xml

<resources>
    <string name="app_name">zenix dev</string>
</resources>
Enter fullscreen mode Exit fullscreen mode

android/app/src/staging/res/values/strings.xml

<resources>
    <string name="app_name">zenix stg</string>
</resources>
Enter fullscreen mode Exit fullscreen mode
  • The result should be like

Image description

 

Setup for iOS

  • Duplicate schema on Xcode 2 times

duplicate schema on Xcode

  • Click on duplicate only

click on duplicate only

  • Rename target to TargetDev and TargetStg
    rename target

  • The result should be like:
    Result

  • Next step open manage schemas
    open manage schemas

  • Check that the names have been changed correctly
    zenix copy to zenixDev
    Image description

  • Now we
    Image description

  • Select schema build settings same as selected schema and add this script
    cp "${PROJECT_DIR}/../.env.development" "${PROJECT_DIR}/../.env.development"

Edit schema > Build > Pre-actions
Select schema build settings same as selected schema and add this script

  • Repeat the same process for the debug mode pre-actions
    Repeat the same process for the debug mode pre-actions

  • Finishing the development configuration, we need to do the same process for staging, changing the script from development to staging
    staging configuration
    staging configuration

  • Correctly name the info.plist files of each schema

Image description

  • Rename info.plist on dev build settings
    Schema*Dev* > Build Settings > Search filter > info.plist File
    zenix dev-Info.plist
    Image description

  • Rename info.plist on dev build settings
    Schema*Stg* > Build Settings > Search filter > info.plist File
    zenix stg-Info.plist
    Image description

  • Open Podfile and change target to abstract_target and rename abstract_target to ProjectName+CommonPods like:

target 'zenix' do // <- Remove this

abstract_target 'zenixCommonPods' do // <- Add this
Enter fullscreen mode Exit fullscreen mode
  • Inside the abstract_target add the targets
 target 'zenixDev' do
 end

 target 'zenixStg' do
 end

 target 'zenix' do
 end
Enter fullscreen mode Exit fullscreen mode
  • Now just give a pod install in the ios folder Image description

iOS Change App Icon and App Name

  • Select the target name and go to general and search for Display name

Image description

  • Further down there will be the app icon, just select another app icon
    Image description

  • The result should be like:

Image description

See the source code

https://github.com/LeonArantes/react-native-multilpe-enviroments

Top comments (20)

Collapse
 
thangvannguyen profile image
ThangVanNguyen • Edited

In IOS, I add in file Podfile:

  pod 'react-native-config', :path => '../node_modules/react-native-config'
  # For extensions without React dependencies
  pod 'react-native-config/Extension', :path => '../node_modules/react-native-config'
Enter fullscreen mode Exit fullscreen mode

=================================AND======================

cp "${PROJECT_DIR}/../.env.development" "${PROJECT_DIR}/../.env.development"
Enter fullscreen mode Exit fullscreen mode

change to

echo ".env.development" > /tmp/envfile
Enter fullscreen mode Exit fullscreen mode

so this run well ^^

Collapse
 
dinhduongson profile image
dinhduongson

thank you so much, it works

Collapse
 
quincodes profile image
Quin

Great help!

Collapse
 
gautham495 profile image
Gautham Vijayan

Extremely Informative article!!!!!!!

Collapse
 
gamble2020 profile image
gamble2020 • Edited

As per the documentation for react-native-config the line...

cp "${PROJECT_DIR}/../.env.development" "${PROJECT_DIR}/../.env.development"

should be...

cp "${PROJECT_DIR}/../.env.development" "${PROJECT_DIR}/../.env"

Because...react-native-config reads the .env file by default.

Collapse
 
sammysmart95 profile image
sammysmart95 • Edited

Please i'm having issues running the the IOS. I keep getting this error

cp: /Users/samueladeoye/Documents/open_source/client/infotech-mobile/ios/../.env.development and /Users/samueladeoye/Documents/open_source/client/infotech-mobile/ios/../.env.development are identical (not copied).
I followed all the steps but still having issues

What could be the possible solution?

Collapse
 
itsme_prakash profile image
Prakash Chandra Awal • Edited

I did the same as mentioned above. But, its not working when i build app from xcode. It only take dev environment even if i chose staging enviornment. However, it works fine when i build app from terminal.

Collapse
 
daskaloff profile image
Yavor Daskalov • Edited

Hi there! Thank you for the detailed explanation. It worked!
There is one problem on android though: If I first try to run the staging app on a blank simulator (it hasn't been installed yet), using the android:staging script, the app does get built and installed correctly, but it isn't run and I get the following error:

Error type 3
Error: Activity class {com.miles/com.miles.MainActivity} does not exist.

I am able, however, to manually run the app by tapping on its icon and it runs as expected.
The production app works properly (builds and starts as expected).
Now that I've run the production app, the staging app starts behaving normally as well.
Could you help me resolve this?

Collapse
 
daskaloff profile image
Yavor Daskalov

found a solution:
add "--appId=com.yourAppName.yourEnv" to the end of the script that fails. Of course ".yourEnv" should actually be ".staging" or ".development" or whichever environment fails with this error.

Collapse
 
jcedborger profile image
Johan

Hi! I'be been using this method for previous projects without any issue! Really like the approach, so I thought I'd use it in a newer project as well.

However, it seems that when building the targets locally, I need to clean the build folders for the different .env files to load during build.

Anyone else having this issue?
xcode 14.2
RN 0.71.2
react-native-config 1.5.0

Collapse
 
adrianorodrigues99 profile image
Adriano Rodrigues • Edited

I found a solution:

echo ".env.production" > /tmp/envfile
touch "${PROJECT_DIR}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildDotenvConfig.rb"

Collapse
 
mnaumanshafique profile image
Nauman Shafique • Edited

Hi @leon_arantes

  1. Can you please also share the command to generate Android APKs with the specific environment?
  2. Do we need to add .env file as on the terminal it says "Missing .env file"
  3. How we can access/ use the data from .env files?
Collapse
 
hamzaxeros profile image
Hamza Hussain

1: To run app
`- "ios": "react-native run-ios --simulator=\"iPhone 14 Pro\" --scheme \"app-development\" ",

  • "ios:stage": "react-native run-ios --simulator=\"iPhone X\" --scheme \"app-staging\"",
  • "ios:prod": "react-native run-ios --simulator=\"iPhone X\" --scheme \"app\"",
  • "android": "cd android && ./gradlew clean && cd .. && react-native run-android --variant=developmentDebug --appIdSuffix 'development'",
  • "android:stage": "cd android && ./gradlew clean && cd .. && react-native run-android --variant=stagingDebug --appIdSuffix 'staging'",
  • "android:prod": "cd android && ./gradlew clean && cd .. && react-native run-android --variant=productionDebug --appIdSuffix 'production'"`

2: To Generate APK or AAB
`- "apk": "cd android && ./gradlew clean && ./gradlew assembleDevelopmentRelease",

  • "apk:prod": "cd android && ./gradlew clean && ./gradlew assembleProductionRelease",
  • "apk:stage": "cd android && ./gradlew clean && ./gradlew assembleStagingRelease",
  • "aab": "cd android && ./gradlew clean && ./gradlew bundleDevelopmentRelease",
  • "aab:prod": "cd android && ./gradlew clean && ./gradlew bundleProductionRelease",
  • "aab:stage": "cd android && ./gradlew clean && ./gradlew bundleStagingRelease",`
Collapse
 
sobanarshad85 profile image
Sarcasm

Video explaination if anybody interested in it.

I was also going through this issue, this video helped me alot. Though still you'll have to manage env variables separately but flavours are well explained in this video in a very simple way. youtu.be/TvBm7UZNyy8

Collapse
 
andrewbaisden profile image
Andrew Baisden

So in depth good read.

Collapse
 
tanjil72 profile image
Tanjil Hossain

Followed all the steps still my xcode opening the same app for dev, uat. How can I resolve this?

Collapse
 
soban1234 profile image
soban1234

Superb!!! Please allow me to copy this article on my own website informativehouse.com I won't copy without your permission.

Collapse
 
kienlv58 profile image
Kiên Cocktails

How can I run .env.stg from Xcode (not the build) directly instead of the command line react-native run?

Collapse
 
gamble2020 profile image
gamble2020

You just choose the scheme you want to run?

Collapse
 
franka10019 profile image
frank.ni@vanyi.com.tw

@leon_arantes, what is resValue means in android productFlavors setting? Thanks.