Adding multiple target pipelines for React Native Apps (and Fastlane CircleCI deployment) pt. 1
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:
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
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 selectDuplicate Only
- Rename the target to
SimplicityDev
- In
SimplicityDev
, change the display name to the target name, and edit the bundle identifier tocom.simplicity.development
- In
Build Settings
>Packaging
>Info.plist File
> Set toSimplicityDev-Info.plist
. Rename the generated plist copySimplicity copy-Info.plist
toSimplicityDev-Info.plist
- Rename the newly generated scheme to
SimplicityDev
and clickEdit Scheme
. Once the dropdown appears, make sure to set theBuild
andRun
process as follows
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.eSimplicity
andSimplicityDev
) - 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
toYes
- 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:
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
Follow this link for React Native Fastlane CircleCI deployment pt. 2.
^ COMING SOON! ^