Adding multiple target pipelines for React Native Apps (and Fastlane CircleCI deployment) pt. 1

Mark Ian Jackson
6 min readDec 5, 2017

--

Why should we add multiple targets to our apps?

For anyone that is dealing with React Native projects that has moved on from a “side project”, has encountered questions about separating development, staging, and production builds.

Here is a useful guide that describes in detail the 12 Factor methodology:

This guide will help easily integrate #3, Config on both iOS and Android mobile applications using React-Native.

Why should we care about making multiple target pipelines in our mobile applications?

  • Allows easy testing of features without disrupting production application.
  • Able to swap API urls, API keys, constants, etc without constantly changing them by hand or using logic to infer the config at run-time.
  • Multiple app installation of different environments on same device
  • Because it’s slick, and we are putting on our big kid pants

For this example, I will be creating a RN app called Simplicity with 2 target pipelines: Production and Development. This can be expanded into any number of targets, just use the references from the Development pipeline to create additional targets. Usually Staging, Beta, or QA is included, but will be omitted in this blog post for “simplicity”.

Lets Get Started!

To get started, initialize a new RN project with

react-native init Simplicity

After verifying the project runs fine with either react-native run-ios or react-native run-android lets get started configuring a npm package called react-native-config

This package allows us to specify .env configuration files for each pipeline, that include constants that are dynamic between targets. Our goal is to include 2 env files in our project: .env.prod and .env.dev .

To install the package run npm install react-native-config .

Once installed, we can link the library to both platforms with react-native link react-native-config

Now lets create out env files.

$ touch .env.dev
$ touch .env.prod

In each env file, lets just add one constant called ENV to differentiate between the 2 pipelines.

In .env.dev add

ENV=dev

And in .env.prod

ENV=prod

Note: This env file will usually include API endpoints for each pipeline, API Keys, etc. Whatever needs to be dynamic between each pipeline.

I changed my App.js to the following to show which environment is running on the component:

Use Config from react-native-config to extract those environment variables!

Lets get started configuring Android first, since it is a short process compared to iOS.

Android Configuration

Here is the resulting android/app/build.gradle that I will break down each feature:

As per the react-native-config instructions, we need to add this line right after apply plugin:

apply from: project(‘:react-native-config’).projectDir.getPath() + “/dotenv.gradle"

Next, I set versionCode 1 and versionName 0.0.1 (This will be the same in iOS, so we can keep both in sync.)

Since we are adding a suffix to our app ID through productFlavors we have to explicitly set the default identifier with this line in defaultConfig

resValue “string”, “build_config_package”, “com.simpicity”

Now for settings our dev and prod product flavors

productFlavors { 
dev {
// Pre-compile run ENVFILE=.env.dev
applicationIdSuffix “.development”
}
prod {
// Pre-compile run ENVFILE=.env.prod
}
}

This creates 2 flavor configurations for our Android application. The // Pre-compile run note is for setting the envfile reference before compiling. Otherwise, react-native-config won’t know which .env file to use for our flavor.

Now lets get ready to test our new Android flavors:

$ cd android/ && ENVFILE=.env.dev ./gradlew installDevDebug
$ cd android/ && ENVFILE=.env.prod ./gradlew installProdDebug
$ adb reverse tcp:8081 tcp:8081
$ npm start

Both apps installed!
Our dev product flavor
The default flavor

iOS Configuration

For iOS, we are going to open up the Xcode project for Simplicity
open ios/Simpicity.xcodeproj/

Right as you open the project, you will see the default Bundle Identifier set as org.reactjs.native.example.Simpicity with the Version as 1.0 . Lets change these to com.simplicity and 0.0.1 like our Android set up.

Instead of multiple schemes for the same target, we are going to add a target for each pipeline (This will allow for multiple bundle ids, and installing the different target apps to iOS at the same time). Simplicity will be the prod target, and SimplicityDev will be the dev target.

  • Right click the Simplicity target
  • Click Duplicate and select Duplicate Only
  • Rename the target to SimplicityDev
  • In SimplicityDev , change the display name to the target name, and edit the bundle identifier to com.simplicity.development
  • In Build Settings > Packaging > Info.plist File > Set to SimplicityDev-Info.plist . Rename the generated plist copy Simplicity copy-Info.plist to SimplicityDev-Info.plist
  • Rename the newly generated scheme to SimplicityDev and click Edit Scheme . Once the dropdown appears, make sure to set the Build and Run process as follows
Make sure to add React and uncheck Parallelize Builds
Set the Executable to SimplicityDev.app

Lets wrap up our targets by integrating react-native-config for iOS. Follow along here or check out the documentation.

  • Expand the Build settings on left side of the window for your target (i.e Simplicity and SimplicityDev )
  • Click “Pre-actions”, and under the plus sign select “New Run Script Action”
  • Add echo ".env.dev" > /tmp/envfile as the script.

Make sure to add echo ".env.prod" > /tmp/envfile for theSimplicity scheme also.

Almost done! Follow these final steps:

  • Go to your project -> Build Settings -> All
  • Search for “preprocess”
  • Set Preprocess Info.plist File to Yes
  • Set Info.plist Preprocessor Prefix File to ${BUILD_DIR}/GeneratedInfoPlistDotEnv.h
  • Set Info.plist Other Preprocessor Flags to -traditional
  • If you don’t see those settings, verify that “All” is selected at the top (instead of “Basic”)

That’s it!

Now lets try running both Simplicity and SimplicityDev on the simulator:

Two apps show up on the screen
Simplicity
SimplicityDev

Most of you will not want to read through this post in its entirety each application, so here is a concise gist of the instructions included in this blog post. This will help configure both pipeline deployments for both iOS and Android, with detailed instructions on the setup.

Also, here is the complete project on Github if someone wants to dig into the code themselves.

For part 2, we will be integrating our multiple pipelines into CircleCI 2.0, utilizing Fastlane for deployment to testers. I feel everyone has had those late night horror stories of having to get a build uploaded manually to TestFlight or Google Play. This next part will focus on deployment based on which branch on Github has been updated.

If you have any questions, message me on Twitter or give a response on this post

Thanks for stopping by!

Follow this link for React Native Fastlane CircleCI deployment pt. 2.

^ COMING SOON! ^

--

--