Build Flavor / scheme for React Native

Ujjwal Manandhar
6 min readOct 9, 2021

--

Photo by Oskar Yildiz on Unsplash

Ever wandered how we can build same applications with three different names and environments and install them simultaneously in our mobile device.
Answer might be yeah easiest one is just manually changing
package name and app name in android manifest.This seems easy but for different environments it’s just consumes a lot of time and time is money.

Recently I came across this problem and had to build an app with three different names and environment (These environment were Production, UAT (User Acceptance Testing), and Dev). After google search I found different articles. So this article also mainly discusses about how we can setup three different version of same app and simultaneously use these apps in our mobile device.
But why this article? Simple and effective.

What we’ll go through
How to setup multi-configuration to installed 3 or more different applications simultaneously on the Device.
In other words, setup build flavors for android and scheme for iOS.

So let’s get started and see how we setup for both android and iOS.

Let’s start with iOS first
Open your iOS workspace using XCode

Let’s make our app have different names based on different environment.
First open Project’s info.plist file and change the “bundle display name” to $(PRODUCT_NAME)

Now let’s add new configurations
- Select Project under “PROJECT” in XCode and in the Info tab, look for Configurations.
- There you should have two default configurations — Debug and Release.
- Click on the + button and duplicate both, name them DebugDev and ReleaseDev respectively and same for UAT and PROD like DebugUat and ReleaseUat and DebugProd and ReleaseProd respectively.

Now Select your app Target and in the Build Settings tab, search for Product Name.
And change the display name for Dev, Uat and Prod.

Now search for identifier in the same tab
This is the bundle identifier for your iOS app, and change the bundle id for different environment.

Now to run above configuration we need to setup new schemes
-
Click on your current active scheme and select manage scheme and look for your scheme and rename it to Dev such as AppNameDev.
- Now create new scheme for Uat and Prod and rename the scheme as AppNameUat and AppName (for Prod as we want use same for Prod).
- Now edit the scheme by double tapping the scheme name and change the configuration by clicking on each list.(i.e.
Change the Build Configuration of Run, Test and Analyze to use the DebugDev we created earlier. Change Profile and Archive to ReleaseDev. Similarly for Uat And Prod change build configuration.
- make sure your project should be shared

scheme

Now we need to update Pods file to specify which configuration belongs to each respective environments.

require_relative ‘../node_modules/react-native/scripts/react_native_pods’require_relative ‘../node_modules/@react-native-community/cli-platform-ios/native_modules’platform :ios, ‘10.0’# configuration nameproject ‘MyApp’, {‘DebugDev’ => :debug,‘DebugUat’ => :debug,‘DebugProd’ => :debug,‘ReleaseDev’ => :release,‘ReleaseUat’ => :release,‘ReleaseProd’ => :release,}

From React Native 0.63.3, react native moved flipper pods from pod file to react_native_pods script. So Change

use_flipper!()

to

use_flipper!(configurations: [‘DebugDev’, ‘DebugUat’,’DebugProd’,’ReleaseDev’,’ReleaseUat’,’ReleaseProd’])

After that pod install and Run project from XCode
or From CLI

npx react-native run-ios — scheme “schemeName” — configuration configurationName

npx react-native run-ios — scheme “MyAppName” — configuration DebugUat

Bonus — To let our app know which environment it is running in we’ll use Preprocessor Macros. Using this we can write conditional logic to use different environments.

Let’s create a new file RNENVConfig

We’ll be using this as a bridge to our RN code

Now edit RNENVConfig.h file

#import <React/RCTBridgeModule.h>@interface RNENVConfig : NSObject <RCTBridgeModule>@end

and edit RNENVConfig.m file

//here we’ll use preprocessor macros we defined earlier to separate the logic to use different environments.

#import "RNENVConfig.h"@implementation RNENVConfig`RCT_EXPORT_MODULE();- (NSDictionary *)constantsToExport{#if DEVNSString *env=@"dev";#elif UATNSString *env=@"uat";#elseNSString *env=@"prod";#endifreturn @{ @"env": env };}+ (BOOL)requiresMainQueueSetup{return YES;}@end

Now in React-Native , you can access env config like

import {NativeModule} from ‘react-native’;const environment = NativeModule.RNENVConfig.env;

Finally it’s time for Android

To make our app have different name let’s first comment our appName in strings.xml file inside android res/values i.e.

android/app/src/main/res/values

After let’s open build.gradle (project level) i.e. android/app/build.gradle
- Add a new section called productFlavors and put our flavor specific configuration here.
- Use a different applicationId for each flavor so we can have them all installed on the device at the same time.
- Don’t forget the add the flavorDimensions “env” line or the build will error.

android {flavorDimensions “env”productFlavors {dev {resValue “string”, “app_name”, “MyAppDev”applicationIdSuffix “.dev”}uat {resValue “string”, “app_name”, “MyAppUat”applicationIdSuffix “.uat”}prod {resValue “string”, “app_name”, “MyApp”applicationIdSuffix “”}}}

Now let’s run our android app from cli

To run the our dev version app in debug mode, we will use

npx react-native run-android — variant=targetRelease

npx react-native run-android — variant=devDebug — appIdSuffix=dev

to make release build

cd android && ./gradlew assembleDevRelease

cd android && ./gradlew assembleProdRelease

Similarly for android RNENVConfig we’ll bridge a module and packagename

Let’s create a new file RNENVConfigModule.java

package com.appName; // replace com.your-app-name with your app’s nameimport com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import java.util.Map;import java.util.HashMap;public class RNENVConfigModule extends ReactContextBaseJavaModule {RNENVConfigModule(ReactApplicationContext context) {super(context);}@Overridepublic String getName() {return “RNENVConfig”;}@Overridepublic Map<String, Object> getConstants() {final Map<String, Object> constants = new HashMap<>();constants.put(“env”, BuildConfig.FLAVOR);return constants;}}

Now create a new file RNENVConfigPackage.java

package com.appName; // replace your-app-name with your app’s nameimport com.facebook.react.ReactPackage;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.uimanager.ViewManager;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class RNENVConfigPackage implements ReactPackage {@Overridepublic List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {return Collections.emptyList();}@Overridepublic List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {List<NativeModule> modules = new ArrayList<>();modules.add(new RNENVConfigModule(reactContext));return modules;}}

Lastly update your MainApplication.java file

Overrideprotected List<ReactPackage> getPackages() {@SuppressWarnings(“UnnecessaryLocalVariable”)List<ReactPackage> packages = new PackageList(this).getPackages();// Packages that cannot be autolinked yet can be added manually here, for example:packages.add(new RNENVConfigPackage()); // This is the new linereturn packages;}

That’s all folks.

Reference:

Edit: Also Where to put google-service.json file in your structure. case

  • 1.) if you have no build_flavor just put it in inside /app/google-service.json folder. case
  • 2.) if you have multiple build_flavor and you have different-different google_services.json files put inside app/src/build_flavor/google-service.json. case
  • 3.) if you have multiple build_flavor and you have single google_services.json file put inside app/google-service.json
    (Credit to Andresh Singh)

If you found any value in this article, please give thumbs up, it would mean a lot. :)

--

--