Aymeric Bouzy aybbyk Aymeric Bouzy aybbyk - 1 year ago 112
iOS Question

release-debug configuration in React-Native

Currently in React-Native, according to the documentation, to build your iOS app for production, you need to :

  • change your scheme to

  • change your
    to load the correct bundle

  • change your
    for ATS

This is a strong violation of 12 factor config recommandation, and it leads to mistakes being made in a continuous integration process.

RN does not provide either out-of-the box strategies to know the configuration environment in the JS code, leading to the existence of the package
, which does a great job already, but is not perfect (Xcode is not fully supported).

Why is it so? Is it because there are actually so few RN app in production today that nobody cares about this? Can we do better than
so that steps listed above are not required? I would like a command line that archives my app in the same way that I can run
cd android && ./gradlew assembleRelease
, without changing anything to my config.


Fastlane makes deployment a lot easier through its
command (thank you Daniel Basedow). Apparently, the philosophy of Xcode is to call environments "schemes", only you cannot store variables in them, or know which scheme you're running in your code... Anyway, David K. Hess found a great way to export your scheme name in your
, and then in your Objective C code, which means I'm now able to chose my bundle according to the current scheme, and not touch my code.

Here is my code:

NSString *schemeName = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"SchemeName"];
if ([schemeName isEqualToString:@"scheme1"]) {
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
} else if ([schemeName isEqualToString:@"scheme2"]) {
jsCodeLocation = [NSURL URLWithString:@"http://<my_local_ip_address>:8081/index.ios.bundle?platform=ios&dev=true"];
} else if ([schemeName isEqualToString:@"scheme3"]) {
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

Now my problem is : I also want to know which scheme I'm running in my JS code.
's way is self-described as hacky, and overly complicated considering the fact the information is already in my Objective C code. Is there a way to bridge this information to my JS code?

Only knowing which scheme I'm running is not as good as being able to set environment variables, but at least I'll be able to switch between environments only by changing my scheme.


I managed to export my scheme to my JS code. I created a cocoa touch class with the following code:

// RNScheme.h

#import <Foundation/Foundation.h>
#import "RCTBridgeModule.h"

@interface RNScheme : NSObject <RCTBridgeModule>


// RNScheme.m

#import "RNScheme.h"

@interface RNScheme()


@implementation RNScheme



- (NSDictionary *)constantsToExport
NSString *schemeName = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"SchemeName"];
NSLog(@"%@", schemeName);
return @{
@"scheme_name": schemeName,


and then in my JS code:

import {NativeModules} from 'react-native'
let scheme = NativeModules.RNScheme.scheme_name

Answer Source

In your AppDelegate you can use the correct bundle like this

#ifdef DEBUG
  jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
  jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

When you do a release build, the DEBUG flag is not set. You can also use different files as your Info.plist depending on build type. There will probably be situations where you want an Xcode debug build with a production JS bundle or vice versa. In that case you need to touch code.

Building ios apps from command line can be a bit tricky. The problems you're describing are not specific to react-native but the Xcode build system. If you haven't already, check out fastlane especially the gym command. It is much simpler than using xcodebuild directly.

But you still have to define your schemes.