Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 Release
  • change your AppDelegate.m to load the correct bundle
  • change your Info.pList 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 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):

  1. Open up your Xcode project and select your project in the Project navigator window

  2. Ensure the project node is selected, as opposed to one of your targets

  3. Select the Info tab

  4. Click the + button within the Configurations section and select which configuration you want to duplicate

Xcode configuration screenshot

Then you can define keys with different values according to your configuration.

  1. Select your app target

  2. Chose Build Settings

  3. Go to User-Defined section (at the bottom of the scroll area)

  4. 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 :

  1. Open your Info.plist file

  2. Create a new value and give it a name (ApiEndpoint)

  3. 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).

like image 334
Aymeric Bouzy aybbyk Avatar asked Jul 13 '16 14:07

Aymeric Bouzy aybbyk


People also ask

What is release configuration?

The release configuration of your program has no symbolic debug information and is fully optimized. For managed code and C++ code, debug information can be generated in . pdb files, depending on the compiler options that are used. Creating . pdb files can be useful if you later have to debug your release version.

How do I enable debugging in react?

You can also use the ⌘D keyboard shortcut when your app is running in the iOS Simulator, or ⌘M when running in an Android emulator on macOS and Ctrl+M on Windows and Linux. Alternatively for Android, you can run the command adb shell input keyevent 82 to open the dev menu (82 being the Menu key code).

How do I connect to React Native debugger?

On Android emulator, you need to press command + M. Debug JS Remotely − Used for activating debugging inside browser developer console. Enable Live Reload − Used for enabling live reloading whenever your code is saved. The debugger will open at localhost:8081/debugger-ui.


1 Answers

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"];
#else
  jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif

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.

like image 101
Daniel Basedow Avatar answered Oct 31 '22 08:10

Daniel Basedow