Deploying your React Native app to the stores manually can be a painful experience. It is time-consuming, error prone and not beginner-friendly. Fortunately, Fastlane helps you automate the process.

This article will explain how to use Fastlane in the specific case of a React Native app. To get started quickly with Fastlane, see this tutorial.

First, we'll need to setup a few things.

Set up your React Native app

Add icons to your app

Apple requires you to have icons for your app, so be sure to have some added to your project. See how to setup your React Native app icons in a single command line.

Set your bundle identifier

Be sure to change your bundle identifier, on the General tab in XCode.

Do not let XCode manage signing

On XCode 8 only, in the General tab, deselect Automatically manage signing:

For all XCode versions, in the Build Settings tab, under Signing, set iOS developer as the debug codesigning identitiy and iPhone distribution as the release codesigning identitiy.

Let the magic begin

Create the Fastlane config

For an easy setup on iOS, cd into the ios folder of your app and run:

fastlane init

Fastlane will ask for some info about your app, and automatically create a fastlane folder for you.

When asked to confirm the values, answer n . Fastlane hasn't guessed your app identifier and needs a little help.

Then, Fastlane will automatically create your app on the Apple developer member center and iTunes Connect. Neat, isn't it? It can take a few minutes to create it on iTunes Connect.

When asked for a scheme , you have to enter the name of your project. For instance, I started my app with react-native init AwesomeProject , my scheme name is thus AwesomeProject .

That's it! You now have a Fastlane configuration folder setup for your app.

You should have an Appfile with specific info about your app a bit like:

app_identifier " tech.bam.alex.fastlane.awesomeproject " # The bundle identifier of your app apple_id " alexandre@bam.tech " # Your Apple email address team_id " Z445H6455F " # Developer Portal Team ID

Checkout ios/fastlane/Fastfile , you should have a lane for the appstore:

desc " Deploy a new version to the App Store " lane :release do # match(type: "appstore") # snapshot gym( scheme: " AwesomeProject " ) # Build your app - more options available deliver( force: true ) # frameit end

Yes! We're close! You could run it with fastlane ios release but we still need to setup match for Codesigning.

Setting up match

Match is awesome for handling your team certificates and your provisioning profiles. It will store them in a private git repo for you. See the fastlane codesigning guide for more info.

Create a private repository for match if you haven't done so yet. Bitbucket is a well known free option.

Then change you release lane like so:

desc " Deploy a new version to the App Store " lane :release do # Uncomment match and add git_url match( type: " appstore " , # Use your own repository! git_url: " https://bitbucket.org/Almouro/awesome-certificates " ) gym( scheme: " AwesomeProject " ) # Build your app - more options available deliver( force: true ) end

This setup would now work with XCode 7. But with XCode 8, by running fastlane ios release , you would now encounter the dreaded error:

Code signing is required for product type 'Application' in SDK 'iOS 10.0'

Handling XCode 8

We have to specifically tell XCode which team and provisioning profile to build your app with.

The easy way

In your deployment lane, uncomment everything but the match step to create and retrieve a provisioning profile for your app. Then you can select it in XCode, under the General tab:

Don't forget to commit the changes to the XCode project!

The code way

We can also select the team and the provisioning profile with code in the Fastfile , by adding xcargs to gym :

gym( scheme: 'MyAwesomeApp', xcargs: "PROVISIONING_PROFILE_SPECIFIER='639b81fa-c63e-4127-a4ef-3e2b73de2033' DEVELOPMENT_TEAM='58628H666T'" )

Sure, you can find the development team in the Appfile but I don't really want to specify the uuid of the provisioning profile. Fortunately, match exports an environment variable to retrieve it easily.

Say your app identifier is com.myawesome.app , and you're building your app for the appstore , then sigh_com.myawesome.app_appstore will be an environment variable containing your provisioning profile uuid. More info is available on the Fastlane docs

You can then replace above code with:

gym( scheme: 'MyAwesomeApp', xcargs: "PROVISIONING_PROFILE_SPECIFIER='#{ENV[\'sigh_com.myawesome.app_appstore\']}' DEVELOPMENT_TEAM='58628H666T'" )

To improve that even more, you can actually retrieve values from your Appfile , with

# Fetching app identifier CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)

The code now becomes:

team_id = CredentialsManager::AppfileConfig.try_fetch_value(:team_id) app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier) profile = ENV["sigh_#{app_identifier}_appstore"] gym( scheme: 'MyAwesomeApp', xcargs: "PROVISIONING_PROFILE_SPECIFIER='#{profile}' DEVELOPMENT_TEAM='#{team_id}'" )

Reaping the rewards

You should now have a lane looking more or less like below, depending on which option you chose to handle XCode 8.

desc " Deploy a new version to the App Store " lane :release do match( type: " appstore " , git_url: " https://bitbucket.org/Almouro/bamlab-certificates " ) sh " printenv " team_id = CredentialsManager :: AppfileConfig .try_fetch_value( :team_id ) app_identifier = CredentialsManager :: AppfileConfig .try_fetch_value( :app_identifier ) profile = ENV [ " sigh_ #{ app_identifier } _appstore " ] sh " echo sigh_ #{ app_identifier } _appstore " gym( scheme: ' AwesomeProject ' , xcargs: " PROVISIONING_PROFILE_SPECIFIER=' #{ profile } ' DEVELOPMENT_TEAM=' #{ team_id } ' " ) deliver( force: true ) end

Run

fastlane ios release

And reap the rewards!

Anyone on your team can now use this command to deploy to the app store.

You can now select your build in iTunes Connect and submit it for review.

Automate all the things

At BAM, we regularly start new projects. We feel like this setup is still pretty long, checkout the Yeoman generator we built to do those steps for you!

Questions, comments?

If you have questions, comments, or any issue on this tutorial, feel free to use the comment section below! ;)