React Native: Multiple Environments Setup (Schemas/Flavors)
Tags: reactnative, environments, javascript, programming
Published: 2022-05-18 14:33:43


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_**.

&nbsp;
## Installing react-native-config
Install the package
```bash
// yarn 
yarn add react-native-config

// npm 
npm install react-native-config --save
```
For iOS also run **pod install** after package is installed.

And below line of code to **android/app/build.gradle** to apply plugin
```gradle
apply plugin: "com.android.application"
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" // <- add this line
```
&nbsp;
## Create .env files for each configuration

`.env.development`
```
ENV=development
API_URL=https://api.dev.com
```

`.env.staging`
```
ENV=staging
API_URL=https://api.staging.com
```

`.env.production`
```
ENV=production
API_URL=https://api.com
```

&nbsp;
## 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`
```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
```
Adding Product Flavor on project below line `compileSdkVersion`

`android/app/build.gradle`
```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"
        }
    }
   // ---
...
```

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`
```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"
        }
    }
```
Create scripts on `package.json`

```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",
```

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9mudwxn57m3puga1g698.png)

* Rename file to `development` or `staging` and remove file `java` 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/al7sumomfwa8j6nspbuu.png)
 
* 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_
```xml
<resources>
    <string name="app_name">zenix dev</string>
</resources>
```

_android/app/src/staging/res/values/strings.xml_
```xml
<resources>
    <string name="app_name">zenix stg</string>
</resources>
```

* The result should be like

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9l98zxg57wlqbhrkxlst.jpg)

&nbsp;
## Setup for iOS
* Duplicate schema on Xcode 2 times

![duplicate schema on Xcode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ad450kc1uyfratfnbsc.png)
 
* Click on duplicate only

![click on duplicate only](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0xqsc5kdks1c5kzpizdm.png)

* Rename target to **Target**Dev and **Target**Stg
![rename target](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rzn4xw9caf97cp0mv8y.png)


* The result should be like:
![Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rhe3wyehdd5w5x2xvhgy.png)
 

* Next step open manage schemas
![open manage schemas](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2t500o4hqm5ar5g13xgl.png)
 
 
* Check that the names have been changed correctly
**zenix copy** to **zenixDev**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqs32912zsiqrfqcaksb.png)

* Now we
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3cf51v6sehwol0f4tipv.png)


* 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h1j9rkryru8xft0cme7.png)


* Repeat the same process for the debug mode pre-actions
![Repeat the same process for the debug mode pre-actions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w86qnt6bltm1xmbbr8f4.png)
 
* Finishing the development configuration, we need to do the same process for staging, changing the script from `development` to `staging`
![staging configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2l55ymx7dz3h23d3yre0.png)
![staging configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/30yod7kucvw1olp1btic.png)
  

* Correctly name the info.plist files of each schema

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o8hqxlvp04xk3dh314tu.png)

* Rename info.plist on dev build settings
Schema**Dev** > Build Settings > Search filter > info.plist File
`zenix dev-Info.plist`
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bt8kih956dkzdoszlpyo.png)


* Rename info.plist on dev build settings
Schema**Stg** > Build Settings > Search filter > info.plist File
`zenix stg-Info.plist`
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3gkdi8fsusudglnl7vg.png)
 
* Open `Podfile` and change target to abstract_target and rename abstract_target to **ProjectName**+CommonPods like:

```Podfile
target 'zenix' do // <- Remove this

abstract_target 'zenixCommonPods' do // <- Add this
```

* Inside the abstract_target add the targets

```
 target 'zenixDev' do
 end

 target 'zenixStg' do
 end

 target 'zenix' do
 end
```

* Now just give a pod install in the ios folder
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6dpft53uo3gerxoy4ba8.png)
 

## iOS Change App Icon and App Name
* Select the target name and go to general and search for Display name

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tptcpgth6u4gzodjemcx.png)

* Further down there will be the app icon, just select another app icon
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a66jvf6thmb5nz77s7w0.png)
 

* The result should be like:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bgtvbqf95qlq71tpef4.png)


## See the source code
[https://github.com/LeonArantes/react-native-multilpe-enviroments](https://github.com/LeonArantes/react-native-multilpe-enviroments)