HomeGet in touch

Automate your React Native iOS app deployments with Fastlane

This is the process I use to deploy Stryde. I have this run in GitHub actions which is massively overkill, but it works well.

Before you start

You should follow Fastlane's guide on getting your environment set up.

Match

Apple has a kind of convoluted system of provisioning profiles and signing certificates. Fastlane has a tool called match which abstracts away some of this complexity, and stores your profiles and certificates encrypted in a GitHub repo.

If you've messed around inside the Apple developer portal and you'd like to clean things up, you can use match nuke to do so. This is an optional step, but if you want to do it you'll need to do it separately for each type of certificate/profile. Let's just do the app store certificates for now.

fastlane match nuke appstore

Now everything's tidy, we can set up match

fastlane match init

This will walk you through setting up your GitHub repo to store your certificates and profiles.

After that, we can run match for each kind of profile we'd like to create. I'll just focus on the appstore type which is used to deploy apps to the app store.

fastlane match appstore

Once that's done, we can start with Fastlane.

Fastlane

Add the below at the very top of your Fastfile

before_all do
  ensure_git_branch(branch: 'main')
  ensure_git_status_clean
  git_pull
end

This basically says to make sure you're on the main branch, that you don't have any uncommitted changes, and then to pull down the latest version of the branch from GitHub. If you don't want to use the main branch here, you can change it.

Now we'll define our :ios platform

platform :ios do
end

Now add the below inside that new block.

lane :certs do
  match(app_identifier: {APP IDENTIFIER}, type: 'appstore', readonly: true)
end

Replace {APP IDENTIFIER} with your app's bundle identifier. This code uses match to fetch your app store certificates and profiles from the GitHub repo you set up earlier.

Next, let's add our build lane inside the platform too. This is the real meat on the bone.

private_lane :build do
  app_store_connect_api_key(
    key_id: ...,
    issuer_id: ...,
    key_filepath: ...,
  )

  certs
  increment_build_number(xcodeproj: {XCODE PROJECT})
  build_app(scheme: {APP NAME}, workspace: {WORKSPACE}, configuration: 'Release')
end

The app_store_connect_api_key bit depends on what Apple authentication method you've decided to use. I'd recommend the App Store Connect API key method as that's what I've used here. Next we run our certs lane, and then increment our build number. Finally we build the app, be sure to set your scheme name and workspace locations.

Finally, all that remains is to put the pieces together

lane :distribute do
  build
  pilot
  commit_version_bump(message: "Version bump", xcodeproj: {XCODE PROJECT})
  push_to_git_remote
end

This adds a distribute lane which runs our build lane, pushes the build to the app store with pilot, then commits the version bump we did earlier and pushes it to GitHub.

Here's the full code for our Fastfile

before_all do
  ensure_git_branch(branch: 'main')
  ensure_git_status_clean
  git_pull
end

platform :ios do
  lane :certs do
    match(app_identifier: {APP IDENTIFIER}, type: 'appstore', readonly: true)
  end

  private_lane :build do
    app_store_connect_api_key(
      key_id: ...,
      issuer_id: ...,
      key_filepath: ...,
    )

    certs
    increment_build_number(xcodeproj: {XCODE PROJECT})
    build_app(scheme: {APP NAME}, workspace: {WORKSPACE}, configuration: 'Release')
  end

  lane :distribute do
    build
    pilot
    commit_version_bump(message: "Version bump", xcodeproj: {XCODE PROJECT})
    push_to_git_remote
  end
end

All that remains now is to run Fastlane and build our app!

fastlane ios distribute