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

Discussion (7)

Collapse
gautham495 profile image
Gautham Vijayan

Extremely Informative article!!!!!!!

Collapse
gamble2020 profile image
gamble2020 • Edited on

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
daskaloff profile image
Yavor Daskalov • Edited on

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
andrewbaisden profile image
Andrew Baisden

So in depth good read.

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?