Continuous deployment of React Native app using Fastlane
React Native has gained a lot of popularity since it was introduced and open-sourced by Facebook early this year. The framework uses JavaScript to build mobile apps and now supports both iOS and Android.
After playing with the framework, I decided to write a simple iOS app using react native and the first thing I wanted to do was to setup an automated deployment pipeline so that everytime I push new changes to my git repository, my continuous integration server can run the tests and upload the new app build to TestFlight.
I decided to use Fastlane which is an iOS automation toolset, recently acquired by Twitter and is now a part of Fabric.
In this post I will go through the steps of creating a very simple React Native app and configuring Fastlane to deploy the app to TestFlight.
Create Hello World React Native App
Lets start by creating a simple React Native app which will show ‘Hello World’ text.
If you do not have React Native installed on your machine, please follow these instructions.
After installing React Native, you can use the CLI to create a new project ‘helloWorldApp’ by running following command.
1 | $ react-native init helloWorldApp |
This command will fetch all the dependencies, including React Native source code and will create a new Xcode project for iOS and gradle project for Android.
Open ios/helloWorldApp.xcodeproj in Xcode and hit run button or press ⌘+r to run the project.
React Native entry file for the iOS app is index.ios.js . Open this file in your favourite editor and change the content of the render function to
1 | render: function() { |
You can press ⌘+r to reload the app in the simulator for quick feedback cycle.
Setup Fastlane for automated deployment
Now we have the hello world app working, we will setup Fastlane to work with our app.
Create offline bundle
The AppDelegate class initialise the app and load React Native JavaScript code. When the app is running in iPhone simulator, AppDelegate loads the JavaScript code from development server. To run the app without development server, we have to create an offline bundle and pack all the JavaScript code within the app. For this we can use React Native CLI bundle command, which will minify and bundle the JavaScript code to main.jsbundle
1 | $ react-native bundle --entry-file ./index.ios.js --platform ios --bundle-output ios/main.jsbundle |
Now update the AppDelegate.m (ios/helloWorldApp/AppDelegate.m).
replace1
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
with1
2
3
4
5#ifdef DEBUG
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
Initialise Fastlane
Follow these instructions to install Fastlane.
Once Fastlane is installed, run ‘fastlane init’ command to setup fastlane and create all the necessary files and folders. For this example, I have skipped delivery and snapshot steps.
Update fastlane/Fastfile file and replace beta config with this.
1 | lane :beta do |
Updated on 8 December 2015
While Fastlane will take care of most of the stuff, we still need to register our app in Apple’s developer center. Login to developer center and setup the app in iOS Provisioning Portal and iTunes Connect with an explicit app id.
We are using Fastlane produce to register our app on Dev portal and iTunes Connect.
We also need to setup our app to auto increment app’s build and version number.
Follow these two steps to enable agvtool and set up version and build number.
While you have the Xcode open, also set the bundle identifier (com.amitkothari.helloworldapp) and team under the general tab.
We also need to add app icon and launch screen images before uploading the app to TestFlight.
We can now create another entry in the package.json scripts, to bundle and deploy the app in a single command.
1 | { |
Additional steps
If your apple id is associated with multiple teams. You may get a prompt to select the team while running Fastlane command. To avoid this update fastlane/Appfile and enter team id and name.
If you get exportArchive or IDEDistributionErrorDomain error similar to this issue, add ‘use_legacy_build_api: true’ under gym configuration.
1 | gym( |
- If you get the following error
“Invalid Provisioning Profile. The provisioning profile included in the bundle com.amitkothari.helloWorldApp [Payload/helloWorldApp.app] is invalid. [Missing code-signing certificate]. A Distribution Provisioning profile should be used when submitting apps to the App Store. For more information, visit the iOS Developer Portal.”
Open the app in Xcode and under the build setting tab, set code signing provisioning profile to “$(PROFILE_UUID)” . See the image below or read this for more details.