Currently in React-Native, according to the documentation, to build your iOS app for production, you need to :
- change your scheme to
Release - change your
AppDelegate.mto load the correct bundle - change your
Info.pListfor 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 react-native-config, 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 react-native-config 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.
EDIT:
Fastlane makes deployment a lot easier through its gym 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 Info.plist, 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. react-native-config'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.
EDIT 2:
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>
@end
// RNScheme.m
#import "RNScheme.h"
@interface RNScheme()
@end
@implementation RNScheme
{
}
RCT_EXPORT_MODULE()
- (NSDictionary *)constantsToExport
{
NSString *schemeName = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"SchemeName"];
NSLog(@"%@", schemeName);
return @{
@"scheme_name": schemeName,
};
}
@end
and then in my JS code:
import {NativeModules} from 'react-native'
let scheme = NativeModules.RNScheme.scheme_name
EDIT 3:
There is actually another way than using schemes. You can create new "configurations" ("Release" and "Debug" are called configurations) with the following steps (thanks CodePush):
Open up your Xcode project and select your project in the Project navigator window
Ensure the project node is selected, as opposed to one of your targets
Select the Info tab
Click the + button within the Configurations section and select which configuration you want to duplicate
Then you can define keys with different values according to your configuration.
Select your app target
Chose Build Settings
Go to User-Defined section (at the bottom of the scroll area)
You can define constants with a different value according to your configuration (for instance
API_ENDPOINT)
You can then reference this value in your Info.plist file :
Open your
Info.plistfileCreate a new value and give it a name (
ApiEndpoint)Give it the value
$(API_ENDPOINT)or whatever name you gave to your constant
Now you can reference this value in your code using the code I gave you in my second edit to this question.
You can create one scheme per configuration to switch quickly from one to the other, or change the build configuration each time (option click on the run button).

fastlane deployworks nicely for android. You can add config files using react-native-config. A nice alternative is expo.io : all the native code is abstracted for you, all the configuration is centralized and available using a single file for both Android and iOS.