Automating pre-production iOS app builds

How CheQ leveraged Firebase App Distribution and Xcode Cloud to automate their build pipelines and improve developer efficiency

Anush Shenoy
CheQ Engineering
5 min readJul 4, 2024

--

CheQ follows an agile development process, meaning multiple feature tracks are being developed, tested, and shipped in parallel. This resulted in us shipping about 4 unique builds on average every working day. Each build took roughly 15 minutes to make locally and share with the QA team and the stakeholders. We lost one developer hour per day in this cumbersome process which could be better utilised elsewhere.

The problem statement

Automate the build management process to improve developer experience and efficiency.

We already used Xcode Cloud at CheQ to share our release builds via Testflight. This was a no-brainer since it involved minor configuration for setting up the release workflow. Also, Apple gives 25 free compute hours per month for Xcode Cloud with every developer account. So shipping builds for startups and indie devs via Xcode Cloud made total sense.

But our preproduction builds had a caveat, we use FLEX, an open-source tool to observe detailed network request history among other functionalities. This SDK used Non-public APIs and the builds were rejected as soon as they were uploaded to App Store Connect.

Hence, we used to create builds locally and use Diawi, a developer tool to deploy development and in-house applications directly to the devices. The catch was that the uploaded builds expired after 24hrs on their self-service plan while it expired after 72 hrs on their free-account plan. Additionally, there are caps on the number of installs per build. This meant we shipped several duplicate builds, wasting more developer bandwidth.

Initial Explorations

We explored Firebase App distribution as we used it extensively to share our Android builds. It allowed us to upload long-term builds and had fewer restrictions on the build expiry. Firebase also offered an easy dashboard for managing testers and groups. But this still meant that we had to locally create the build and then upload it to Firebase App distribution via their easy drag-and-drop functionality. So this only partially addressed our original concern

The Implementation

The solution to our original problem statement came in the form of using a combination of Firebase App distribution and Xcode Cloud. Firebase provides a convenient Command line interface(CLI) to upload builds. Here are the steps used for setting up the entire workflow:

Visualizing the entire Workflow

Xcode Cloud Initial Setup

Apple has done a fantastic job of documenting the entire setup process here. You can get started easily and set up a basic workflow. We used this to create a debug workflow by selecting ‘none’ in the Distribution Preparation options.

Xcode Cloud Additional Setup

Xcode Cloud gives you the flexibility to run custom scripts. You can refer to this handy developer doc by Apple. For our use case, we identified that we had to create a ci_post_xcodebuild.sh script file in the ci_scripts folder.

Download the Firebase MacOS tool

Download the Firebase MacOS CLI tool from here. It is about 150 MB in size. Xcode Cloud doesn’t support git-lfs. To workaround any git-lfs issues, we will compress this file and copy the zip file into our ci_scripts folder. This compressed file should be around 45 MB in size.

Create a Firebase Service Account

Firebase has deprecated the use of tokens for authenticating and using service accounts is recommended. You can follow the steps mentioned here to generate the credentials.json file.

Add the credentials to the Xcode Cloud workflow

Now that we have the credentials.json, we must integrate it into the workflow. Please note that this is a private key and is not recommended to be kept under source control. Instead, add it to an environment variable named CREDENTIALS. Also, do note that we need to escape the newline character in the private key in the JSON file. To do this replace all occurrences of \n in the file with \\n. Also, mark the environment variable as a secret. Doing so will prevent anyone else from reading it and remove it from any logs.

Adding the private key as a secret environment variable in the Xcode Cloud workflow

Editing the ci_post_xcodebuild.sh script

Now that we have all our pieces ready, we need to add a post-build script executing it.

if [ "$CI_WORKFLOW" = "WORKFLOW_NAME" ]; 
then
echo "Uploading Firebase UAT Debug Build"
unzip firebase-tools-macos.zip
chmod +x ./firebase-tools-macos
echo "$CREDENTIALS" > credentials.json
export GOOGLE_APPLICATION_CREDENTIALS=./credentials.json
./firebase-tools-macos appdistribution:distribute $CI_DEVELOPMENT_SIGNED_APP_PATH/APP_NAME.ipa --app FIREBASE_APP_ID
echo "🚀 End uploading ipa"
fi

This script is quite straightforward. We first unzip the compressed Firebase MacOS CLI tool and then install it. Next, we read the service key from the environment variables and save it to a file named credentials.json. We then use this JSON file to authenticate with Firebase and lastly, we execute
the Firebase app distribution CLI command.

Replace APP_NAME, FIREBASE_APP_ID and WORKFLOW_NAME in the above script with the actual values
You can get your FIREBASE_APP_ID from the project settings on the Firebase Console as shown below.

Project settings page on the Firebase Console

Workaround for Git-LFS issues

If the compressed Firebase MacOS CLI tool is still too big for your source control, you can download it as a part of the post-build script using the following:

curl -sL https://firebase.tools | bash

Testing the Setup

The next step is to start a build and check if everything works as expected.

Bonus tips

  • You can add release notes to builds using the Firebase CLI.
  • You can also share builds with particular testers or a group of testers using the Firebase CLI.
  • You can add setup alerts in the Xcode cloud post actions to inform you about build success or failure.

Results

With this development, we managed to fully automate build pipelines for all our use cases. This has helped us ship builds faster while allowing developers to concentrate on coding for awesome new features.

CheQ roughly saved 4% of its total iOS developer bandwidth leading to higher developer efficiency and shorter feature development times

I hope this article was helpful and as always, like, comment & share the article so that it can reach a wider audience.

--

--