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.
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.
Be sure to change your bundle identifier, on the General tab in XCode.
For an easy setup on iOS, cd into the ios folder of your app and run:
++pre>++code>fastlane init
++/code>++/pre>
Fastlane will ask for some info about your app, and automatically create a ++code>fastlane++/code> folder for you.
When asked to confirm the values, answer ++code>n++/code>. 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 ++code>scheme++/code>, you have to enter the name of your project. For instance, I started my app with ++code>react-native init AwesomeProject++/code>, my scheme name is thus ++code>AwesomeProject++/code>.
That's it! You now have a Fastlane configuration folder setup for your app.
You should have an ++code>Appfile++/code> with specific info about your app a bit like:
++pre>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++/pre>
Checkout ++code>ios/fastlane/Fastfile++/code>, you should have a lane for the appstore:
++pre>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++/pre>
Yes! We're close! You could run it with ++code>fastlane ios release++/code> but we still need to setup match for Codesigning.
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 ++code>match++/code> if you haven't done so yet. Bitbucket is a well known free option.
Then change you ++code>release++/code> lane like so:
++pre>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++/pre>
This setup would now work with XCode 7. But with XCode 8, by running ++code>fastlane ios release++/code>, you would now encounter the dreaded error:
++pre>++code>Code signing is required for product type 'Application' in SDK 'iOS 10.0'
++/code>++/pre>
We have to specifically tell XCode which team and provisioning profile to build your app with.
In your deployment lane, uncomment everything but the ++code>match++/code> 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!
We can also select the team and the provisioning profile with code in the ++code>Fastfile++/code>, by adding ++code>xcargs++/code> to ++code>gym++/code>:
++pre>++code>gym(
scheme: 'MyAwesomeApp',
xcargs: "PROVISIONING_PROFILE_SPECIFIER='639b81fa-c63e-4127-a4ef-3e2b73de2033' DEVELOPMENT_TEAM='58628H666T'"
)
++/code>++/pre>
Sure, you can find the development team in the ++code>Appfile++/code> but I don't really want to specify the uuid of the provisioning profile. Fortunately, ++code>match++/code> exports an environment variable to retrieve it easily.
Say your app identifier is ++code>com.myawesome.app++/code>, and you're building your app for the ++code>appstore++/code>, then++code>sigh_com.myawesome.app_appstore++/code> 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:
++pre>++code>gym(
scheme: 'MyAwesomeApp',
xcargs: "PROVISIONING_PROFILE_SPECIFIER='#{ENV[\'sigh_com.myawesome.app_appstore\']}' DEVELOPMENT_TEAM='58628H666T'"
)
++/code>++/pre>
To improve that even more, you can actually retrieve values from your ++code>Appfile++/code>, with
++pre>++code># Fetching app identifier
CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
++/code>++/pre>
The code now becomes:
++pre>++code>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}'"
)
++/code>++/pre>
You should now have a lane looking more or less like below, depending on which option you chose to handle XCode 8.
++pre>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++/pre>
Run
++pre>++code>fastlane ios release
++/code>++/pre>
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.
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! ;)