Automatic iOS App Deployment with Bitrise and Fastlane

Michał Międlarz
nomtek
Published in
7 min readSep 15, 2020

--

Save time, deliver faster, focus on real development.

Photo by Jake Blucker on Unsplash

In the life of every iOS app developer, there is a time when some important feature is finished and a new shiny build has to be delivered to the QA team (or the client directly).

The simplest way to do it is by using the Archive option from the Xcode — after setting valid provisioning profiles, it will create an IPA file that can be installed on the test devices.

This approach is simple and suitable for small projects, but it’s time-consuming and repetitive. It also requires your attention. For larger projects, spending several minutes every day just to archive and upload the app may be annoying.

But automating the whole process will save you a lot of time.

Here are some assumptions which we will follow during the automation process:

  1. A new app build should be created and sent to QA automatically after each push to develop branch
  2. There are unit tests in the project, so build should be created only if they all pass
  3. The build will be signed using the AdHoc provisioning profile (we don’t want to wait for TestFlight review)

And tools that will make it possible:

  1. Fastlane —command-line platform created to simplify app development. Originally it was designed for iOS, but now it can handle Android builds too.
  2. Bitrise — cloud CI which allows to set up a virtual machine with OSX, Xcode, and most common tools used in mobile app development (like ruby, npm, bundler…)
  3. Visual Studio AppCenter — deployment and release platform with support for different destination groups, UDID collection and build management.

Fastlane configuration

Let’s start with Fastlane because it can be configured, tested, and used to make developer life easier without any CI. It has several built-in functions (called actions) from which we will use:

  • scan — will be used to configure and run tests
  • match — a helper tool to make whole codesigning easier in general. It requires a separate git repository to store Development and Distribution Certificates and Provisioning Profiles. The whole process is fully automated, and we will optimize it to be run with a single terminal command to recreate all profiles and related certs
  • gym — will be used to archive the app

You can install Fastlane using homebrew:

brew install fastlane

then go to your project directory and call:

fastlane init

You will be asked the following question:

What would you like to use fastlane for?
1. 📸 Automate screenshots
2. 👩‍✈️ Automate beta distribution to TestFlight
3. 🚀 Automate App Store distribution
4. 🛠 Manual setup - manually setup your project to automate your tasks

Select 4 as we will prepare our configuration manually.

Match

Let’s start with the match.
Create a new git repository, then trigger match setup by calling:

fastlane match init

Select git storage mode and provide URL to the freshly created repo.

At this moment, there should be a new fastlane directory in your project folder with three files: Fastfile, Matchfile and Appfile. We will use only the first two — the Appfile can be safely removed.

Open Matchfile — by default it should contain git_url, storage_mode, and a list of commented available options. To make everything clear it has to be updated with team_id (from Apple Developer portal) and app_identifier (Bundle Identifier from Xcode)

Next, start match using:

fastlane match

It will trigger a nice command-line based wizard to create certificates and provisioning profiles. During the configuration you will be asked for:

  • Apple Id username and password — those credentials will be only used to create the Distribution and Development certificates with related provisioning profiles in the Apple Developer portal. The password will be stored in your local keychain for future use.
  • Password (called Match Password) to encrypt P12 cert files.

After that, in your match repository, you should see some new content:

Certificates and Provisioning Profiles stored in match repository

Now, make sure that all your team members can access this repo. And if they call:

fastlane match development --readonly

Fastlane will set up codesigning for the dev environment in just a few seconds without any access to the Apple Developer portal.
That means that there might be only one person in your team added to the Apple Developer program (i.e. team lead, architect, or CTO) which will be responsible for dangerous certificate operations.

Basic match configuration is completed, but there is still some room for improvement. Switch your editor to the Fastfile. We haven’t touch it yet, so there should be only initial content — let’s add helper functions (called lanes) for fetching certs:

There are two new lanes: recreate_certificates and fetch_certificate which can be called directly from the terminal:

fastlane recreate_certificates
# or
fastlane fetch_certificates

The first one will recreate provisioning profiles and certificates for all available types (Development, AdHoc, and AppStore) with all registered devices. The latter will fetch all certs and profiles only from the git repo.

Create an archive

Match configuration is finished and we should be ready to build the app. Open Fastfile and add a new lane:

So, we’re installing CocoaPods, then running tests (scan) and if they pass, we update the build number, fetch the latest AdHoc provisioning profile and finally build the binary (gym).

Notice: as for build number I used to set timestamps for QA builds. It was clearer for the QA to see what build exactly they’re testing and to check how old it is. But if you prefer to use integer values, you can remove build_number variable to increment build number by one.

Now you can run:

fastlane build_adhoc

and when it finishes, you should see MyApp.ipa in your project directory!

Visual Studio AppCenter

We have .ipa ready, so the next step would be to send it to our testers. Go to https://appcenter.ms/create-account to sign up and create an iOS app.
Next, head to Distribute > Groups to create one group — i.e. AppTesters.

Next, head to Distribute > Groups to create one group — i.e. AppTesters.

Then, go to https://github.com/microsoft/fastlane-plugin-appcenter. Use provided installation and API token instructions to get all necessary data. Installing it will also update Gemfile so make sure to commit it.

The last step is to update the Fastfile:

As you can see, we are using appcenter_upload action together with last_git_commit to fill the release notes of the build.

The distribution script is ready, so you can test it by:

fastlane build_adhoc

Bitrise setup

With Fastlane configured, we just need a CI server to call it after a push to the git repository. We will use Bitrise, but with Fastlane in place, you can change it to whatever you prefer. The whole deployment script lies in your repo, so there is almost nothing to migrate.

The free plan allows us to run 200 builds every month with max 30 minutes of build time. This should be enough for small iOS projects, but for something more complicated you should consider a paid plan (check https://www.bitrise.io/pricing).

Just notice that MacOS machines are quite slow (2x 2.7 GHz with 4 GB of ram), so for larger projects, you might need an Elite plan.

To start, you just need to go to their Sign Up page. After creating an account you will be able to connect it to your repository, setup triggers, edit the workflow, and create webhooks.

Notice: We will use two repositories for our code, so during configuration you might need to setup SSH connection between Bitrise and repositories manually.

Notice #2: Bitrise can create the basic workflow for you, but for this tutorial we will create it manually. So in Project build configuration just select OTHER / MANUAL with Xcode version used in your project.

In the end, you should see something similar to this:

Default Bitrise dashboard after initial configuration.

Workflow setup

Select the Workflow menu from the top toolbar and then select bitrise.yml option. There should be a default config stored as a yml file. Update it with the following:

Then open the Secrets tab and add a new secret: MATCH_PASSWORD with the same value as you set during match configuration.

Build triggers

The final step is to add a trigger, to start the build after each push to the develop branch. You can do it in the Triggers tab:

Congratulations, you have fully working CI now 👏

I’m pretty sure that it will save you a lot of hours, and after some time, you won’t even start any new project without continuous deployment.
You can find the final versions of Matchfile and Fastfile saved here.

--

--

Michał Międlarz
nomtek

I do apps… and other stuff too. iOS developer at nomtek.com