Continuous Delivery in iOS Apps using Bitrise

Includes humble notes to help you overcome possible challenges for setting up an iOS Continuous Delivery pipeline.

Dogan Altinbas
Plus Minus One
12 min readDec 21, 2020

--

In PlusMinusOne, we develop, maintain, and deploy many iOS applications. As we have more apps we need to automate some processes. To achieve that, the following services are lined up for a Continuous Delivery (CD) pipeline:

Bitbucket: a hosting service where we host our repositories.

Bitrise: Offers a collection of tools and services that assist us with the development and automation of our iOS app.

Firebase App Distribution: a platform that we manage our iOS pre-release distributions.

Slack: a channel-based messaging platform that we’ve already used for team communication. Here, we also use trigger a Bitrise build and get notified if the build is successful or failed.

In this article, I will focus on the procedure of adding an iOS app in Bitrise. Also, I will introduce some ways to troubleshoot problems that we’ve already faced during this integration. If you need further information for creating a repository in Bitbucket and adding Firebase to your iOS App, you may follow the links in the prerequisites section.

Prerequisites

Create a Git Repository

We use Bitbucket to collaborate and manage our iOS projects since it offers unlimited private repositories (up to 5 users is free). If you don’t have any repository yet, you can create one by following the instructions here.

Add Firebase to your iOS project

If you don’t any other Firebase products (e.g. Crashlytics, Cloud Functions), you only have to create a Firebase project and register your app. To do that, you can follow Raja’s tutorial and add Firebase capabilities to your iOS application.

Get Started

Adding New App to Bitrise

Creating a new app on Bitrise is really simple. Go to Bitrise dashboard and choose Add New App. You can select one of the options from the dropdown list. I’ll go with the Add New App on web UI.

Adding New App To Bitrise

Once you make your selection, we’ll look at the configuration for your app. Let’s take a look at those settings!

Choose Account
  • Select your Bitrise Account (Depending upon your current plan, it can be an organization or developer account) and set it to private.
  • Then, you need to select the repository for which you want to automate processes. In PlusMinusOne, we use Bitbucket to take obvious advantage of hosting unlimited private repositories.
  • The next step is setting repository access. Click No, auto-add SSH key.

Note: If you do not have admin permissions to the repository, you will not be able to auto-add the key to it. In such a case, copy the public key and add it to your repository on Bitbucket.

  • After setting up the SSH key for your project, enter the name of the branch of your repository. This branch should include configurations of your project. Once you hit enter, the project scanner starts to validate your project.
  • If the validation is successful, it detects schemes of your project. Select one of them.
  • Following that, you will be asked to select one of the IPA export methods. Pick one and hit confirm.

Note: You can still update your settings whenever you need after you successfully add your new app.

  • In the second last step, you can add your app icon or skip that.
  • Lastly, you can skip webhook registration for now, we will implement it later on.

If you do everything right, the following will be prompted:

Note:Please make sure that application scheme's Shared attribute is enabled in Xcode. Otherwise you will not be able to get successful builds.

Workflow & Steps

Once you set up the application, Bitrise has already triggered a build. As you click the Builds tab, you can monitor your current or previous build attempts. You will probably get an error on your first build. Don’t worry! After you configure steps in your workflow, things going to work out properly and you will start getting successful builds.

Workflow and steps are two important definitions in Bitrise. A Bitrise Workflow is a collection of Steps. When a build of an app is triggered, the Steps will be run respectively. Speaking of, each Step performs a different task like cloning your application or signing your profiles, and each Bitrise build consists of several steps defined in the workflow. When you add a new application, Bitrise provides some default steps in a workflow.

Let’s take a brief look at what has been done in the default steps. In addition, we will add a few new steps towards our goal. Finally, our list will take its final form above.

Activate SSH Key

This Step makes sure Bitrise has access to your repository and been authorized to clone your application to its virtual machines. No need to modify input variables, leave it as it is.

Git Clone Repository

As the step’s name suggests, it is used to target your application repository and create its clone.

Bitrise.io Cache:Pull

Downloads the build cache from bitrise.io, Aims to shorten build time.

Script

Run any custom script you want. However, we don’t need it for our case. Click on the step and select Delete Step: Script on the right side bottom.

Deleting Script Step

The next step is not included in the default steps. For this reason, click the plus (+) symbol between two Steps to insert a Step at that position.

Adding New Step

Get Xcode Project Version

Gets Bundle Version and Build Number of the project. This step requires .xcodeproj and info.plist paths. In our case, It is as follows:

Get Xcode Project Version

As we change input variables for the first time, I should mention environment variables. Environment Variables (Env Vars) consist of a key and a value and appear like $VARIABLE_NAME in Bitrise. Env Vars can be exposed by Bitrise CLI, added manually from inside the Env Vars Tab, or generated as an output of a step. Moreover, When a step generates an output variable, it can be used in latter steps.

As you can see in the picture above,$BITRISE_SOURCE_DIR is one of the environment variables that is exposed by Bitrise (There are more here). By default, it’s the directory where Bitrise runs. Also, this step generates output variables. That means we can use them in the next steps if we need to.

Set Xcode Project Build Number

Set the value of your iOS app’s bundle version in the Info.plist file to the specified version number.

Set Xcode Project Build Number

$BITRISE_BUILD_NUMBER: Build number of the build on Bitrise. You can see we set Version Number to $XBV_PROJECT_VERSION which is generated from the previous step. Thanks to this step, you can auto-increment your build number. For example:

If Info.plist has the following values in the project:

  • CFBundleVersion: 3
  • CFBundleShortVersionString: 4.1.1

and you have the following setup in Set Xcode project build number step:

  • Build Number: $BITRISE_BUILD_NUMBER (let’s say it’s your 4th build you run on this app)
  • Build Number Offset: 3
  • Version Number: $XBV_PROJECT_VERSION (which is also 4.1.1)

So the 4th build version will be:

$BITRISE_BUILD_NUMBER + Build Number Offset → 4.1.1 (7)

Certificate and profile installer

Installs .p12 certificate files and provisioning profiles. You can use codesigndoc tool to export and upload appropriate files.

  1. Open the Terminal
  2. Go to your project’s folder
  3. Enter the following command

4. Tool scans the directory for project files (.xcodeprojor .xcworkspace). Once a project is found, you will be prompted to select a scheme from the list. Select one among them that targets your app.

5. Then, select the IPA export method and Enter. In our case we use ad-hoc

6. You can type No if you don’t need to collect another IPA export code sign files.

7. Immediately after exporting, you will be asked if you want to upload the exported files to Bitrise. Type Yes and press Enter.

8. To upload signing files, you must create a personal access token and as it is described below:

9. Once you enter the token, your signing files will be imported to Bitrise. You can view them in the Code Signing tab.

Your signing files are all set!

Run CocoaPods install

executes pod install command to install your dependencies. No change is required for this step.

Xcode Archive & Export for iOS

Runs xcodebuild archiveand exports the archive into an IPA file. You should set Scheme Name, Configuration Name and Export Method.

Note:Please make sure that the Configuration and Scheme you specify actually exist in your Xcode Project.

[BETA] Firebase App Distribution

Uploads your app binaries with an optional release note to Firebase and sends an email to your testers. In this step, you need to modify some variables.

Firstly you must add Firebase Token, so Bitrise can access it.

Adding Firebase Token
  1. Open Terminal
  2. type firebase login:ci and press Enter, then you will be redirected to Firebase in the browser.
  3. After you successfully log in, the token will be prompted in Terminal.
  4. Copy that access token.
  5. Go Bitrise and Click the Firebase Token field. Since it is sensitive data, Bitrise will force you to add it as a secret variable:
Adding New Secret Variable

6. Now, you must add Firebase App ID. Go to Firebase Console and get click the settings icon and select Project Settings.

Firebase Console

7. Copy App ID and paste it to the field in step.

Firebase App ID

8. Assign Test Groups. Go to App Distribution in Firebase. Select the Testers & Groups tab.

9. Copy the tester group alias name and paste it to the Test Groups field in step.

10. You can also add a release note. It will be attached to the email that is sent to testers.

All done with Firebase!

Deploy to Bitrise.io — Apps, Logs, Artifacts

Deploys build artifacts to make them available for the user on the build’s APPS & ARTIFACTS tab. Like below:

Deploy to Bitrise.io — Apps, Logs, Artifacts

Send a Slack Message

Here, we would like to send a message to the Slack channel that the build is successful or failed. To do that, we should register a Slack Webhook URL or Slack API Token. I’ll go with the incoming webhook URL since I am more familiar to use them.

Note: Please do not register both URL and Token; otherwise Bitrise will not be able to deliver the message to Slack.

  1. Go to https://api.slack.com/apps
  2. Choose to Create New App
  3. Set app name and select your Slack workspace. Press Create New App

Now, you should configure an incoming webhook for your app. Choose the following feature:

4. After that, activate incoming webhooks.

Activate Incoming Webhooks

5. Click Add New Webhook to Workspace button at the bottom of the page

6. Choose a channel from the dropdown list to post to as an app and press Allow

You’ve successfully created an incoming webhook URL.

Webhook URL

7. Copy Webhook URL, then go to your Bitrise setup page. Create a secret variable and assign it to the Slack Webhook URL field in the Send a Slack Message Step.

Slack Webhook URL

8. Set Target Slack Channel

You can leave the rest of the variables as they are. Later on, you can change it and see the results by trial and error.

All good with Slack!

Bitrise.io Cache:Push

Updates the cache, if required.

Running a Build

Now, you can start a build in app dashboard.

  1. Select Start/Schedule a Build
Start/Schedule a Build

2. Set your branch and choose your workflow (primary as default) and Press Start Build

Build Configuration

You fired the build! You can monitor its status and logs in the Builds tab.

Once it is successfully built, your tester will get an email from Firebase like below:

Firebase App Distribution

Also, your chosen Slack channel will receive a message similar as follows:

Slack Message from Bitrise

Everything works well but wouldn’t be better if we also trigger a build from Slack?

Trigger a Build with a Slack Message

Currently, we can start a build from the Bitrise dashboard. So now, we will use Slack as a mediator to start a build. To do that:

  1. Get a Bitrise Incoming Webhook URL
  • Go to the Code tab.
  • In the INCOMING WEBHOOKS section, Select Setup Manually and choose Slack from the dropdown list.
  • Copy the URL generated below.
Bitrise — Setup Webhook

2. Create a Slack Outgoing Webhook

  • Go to Slack App, select your workspace and from the dropdown list select Administration → Manage Apps
Manage Apps
  • That opens up the Slack app directory. Choose Browse from the top bar and then search for Outgoing Webhooks.

Outgoing webhooks allow you to listen for triggers in Slack chat messages. So, when you send a message that begins with a defined trigger word(s), it will post your request to the specified webhook URL.

  • Let’s configure an outgoing webhook. Press Add to Slack and then press the Add Outgoing WebHooks integration.
  • On the next page, set the channel to listen on, add trigger word(s) and finally paste Bitrise Incoming Webhook URL — which you had it above — into the URL(s) section. You can also customize the name and icon. Lastly, press Save Settings. You will see your webhook URL under the configurations like below:
Outgoing WebHook Configuration

Let’s test it on Slack!

As it is described here, your message should follow rules below.

The Message Format

As I write the following message in the target channel, the build is triggered from my default branch(develop) and notified me also with a message.

Triggering Build from Slack

As you can see there is an extra parameter called RELEASE_NOTE which is also sent to Bitrise to be used as an Env Var. In the Firebase App Distribution step, we set the Release Notes variable to that $RELEASE_NOTE. Thanks to that, we can dynamically change our release note for a Firebase Release.

Release Notes Environment Variable

I have tried to share the practices we have learned from Bitrise so far. I hope it may motivate and encourage you to integrate a CD pipeline into your applications.

To learn more about our development experiences you can look at our medium page. At Plus Minus One, we love to learn and share our experiences. We hope this article makes your life easier 🙏🏻

--

--