Deploy Flutter (iOS) Apps to Testers using Firebase App Distribution with Semaphore

Deploying iOS apps to early testers helps you get feedback for improvements or detect issues that came out from early on during the development. Firebase App Distribution, or App Distribution, is a service that helps you deploy your Flutter apps to testers.

This article focuses on automating deployments for Flutter (iOS) apps using ad-hoc releases in App Distribution. If you’re interested in implementing this for Android, you can read this.

  • An existing Flutter project; you can use our starter app or create one by running
  • A Firebase account; you can create one here
  • An Apple Developer Account ($99 / year) for the developer certificates and provisioning profiles

Deploying iOS apps is more complex than in Android. Unlike in Android, most of the time, you can create an android package (APK), and users can directly install and use them on their devices. But for iOS, it’s a different story. You can only install apps from the Apple Apps Store or signed ad-hoc releases from tools like App Distribution.

App Distribution and Apple Apps Store

App Distribution is an alternative service to deploy iOS apps to a limited number of testers to get early feedback or detect issues, and it’s not a complete replacement for the Apple Apps Store if you are planning to release your apps to the public.

Creating a Firebase Project

In the console, create a new project by tapping Add project.

Assign a project name and unique ID (optional).

You can also enable Google Analytics (Optional). For now, we’ll disable this setting.

Authentication with Firebase CLI

Firebase CLI contains tools that allow you to manage, view, and deploy to Firebase. We will use Firebase CLI to authenticate CI later when deploying builds to Firebase projects.

Setting up Firebase CLI

There are at least two ways to set up Firebase CLI on your machine. Either by downloading the standalone binary or via the npm package manager.

If you already have npm, you can go ahead and install Firebase CLI using the package manager, as shown below:

Testing and logging in with Firebase CLI

Authenticate Firebase CLI using the email associated with your Firebase account:

For more information, see Firebase CLI reference.

Setting up App Distribution

App Distribution in Firebase is where deployed builds show up and where you can manage your app testers.

Setting up an iOS project

If you have an existing Flutter project that uses Firebase, please skip this step. Otherwise, do the following if you are using the starter app or have created a new project using .

In the Firebase console’s sidebar, navigate to and open App Distribution.

Tap the iOS logo to create a new iOS project.

Then, enter the details of your iOS project. Optionally, you can download the file and put them to your root iOS project directory.

If you use the starter app, replace with your desired bundle identifier.

Setting up group testers

App Distribution allows you to configure multiple test groups depending on the build you deploy, for example, for internal or private beta builds.

Navigate to the App Distribution page and select the Testers & Groups tab.

Add a group named “testers”, then click Save.

Last, to deploy your build to the users, add their emails to the group.

fastlane is an open-source platform with a wide range of tools and APIs for simplifying deployment for Android and iOS projects. We will use fastlane to automate our workflow, communicate with Firebase, and ultimately deploy the project.

Setting up Ruby

Ruby is a must-have to use fastlane in your project. Here’s an exhaustive list of ways to install Ruby on your machine.

Setting up Bundler

Bundler and Gemfile are for defining dependencies in fastlane. Run the following command to install bundler:

Setting up fastlane

If you’re on macOS and have Homebrew installed, run the following:

If you have gems installed on macOS/Windows/Linux, run the following:

Setting up fastlane with your Flutter iOS project

Set up fastlane in the directory of your Flutter project.

To initialize fastlane, run the following:

  1. Select manual setup:

Then, wait for all the packages and dependencies to be installed properly.

You should now have a fastlane directory containing the and .

Adding the Firebase App Distribution Plugin to Fastlane

We will need the plugin to upload the build artifacts to Firebase.

Install the fastlane plugin with the following command:

Then, when asked to modify the Gemfile for the current path (ios), type .

Depending on your Ruby setup, you might be asked to enter your password and provide temporary root privileges when installing the dependency:

Setting up Fastfile with Firebase


Fastfile stores the configuration for automation using fastlane.

First, navigate to your directory and replace the default content with the following:

here is the name of the fastlane workflow. To run the command in your terminal, run .

Next, below team_id variable, add the following:

These are for creating temporary keychains and downloading developer certificates, and provisioning profiles on the CI.

Then, inside the lane, add the following:

App ID

To get your App ID, click Project Overview, then Project Settings.

Next, select the current app’s Project Settings and copy your App ID.

Replace in your .

Generating Firebase CLI token

Earlier you authenticated Firebase CLI with your Firebase account; mainly for testing tooling installation. Now, we will authenticate and generate a token for CI.

To generate a token for CI run:

This should give a hashed string like this:

Replace in your .

Setting up fastlane match

fastlane match, or match, simplifies the complex code signing for your iOS apps, and Semaphore has an in-depth documentation on how to deal with iOS code signing using fastlane match. I will explain the setup here succinctly.

Configuring match

Initialize match by running

Next, select to store the developer certificates and provisioning profiles:

Then, enter the URL of your git repository, for example:

Finally, replace to in your

Generating certificates and profiles

Create ad-hoc certificates and profiles by running. When prompted, enter your Apple Developer Credentials.

Use the match provisioning profile in your project settings using Xcode:

Downloading certificates and profiles in fastlane

In most cases, you should be able to clone your match’s git private repository on your local machine. But in CI, we have to provide appropriate authorization to allow access.

Create your Github personal access token by following this.

Use the personal access token generate and replace the in your :

Last, add the command

Deploying to Firebase using fastlane locally

That’s it for Firebase and fastlane for now. Let’s test the Firebase deployment by running fastlane locally.

Ensure the project is in clean state:

Then, build the Flutter iOS app:

To deploy your app, run the following:

This should give you a success message for deploying your app to Firebase.

Great! Your latest iOS build should be displayed on App Distribution’s releases dashboard.

Before proceeding, I recommend reading core concepts that make Semaphore intuitive and powerful. I also explained the Visual Builder for iOS continuous integration in this article.

Setting up a Semaphore project for your app

Log in with your Semaphore account, then create a new project.

Choose the repository for your project, then click Continue to workflow set up.

Then for the workflow set up, click Customize.

Setting up blocks to integrate and build your apps

Configuring the workflow pipeline

We’ll be using a Mac Based Virtual Machine environment with a macos-xcode13 image.

Setting up your blocks for Continuous Integration (CI)

Create a block named Install Dependencies, then add a job Install and cache Flutter:


Then, add a new block named Lint, then add jobs Format and Analyze:




Finally, add a block to run your Flutter tests.

Run unit and widget tests


Optionally, you can test your workflow by clicking Run the workflow.

Setting up a new promotion

Promotions help us create conditions around our workflows and whether or not we have to run another workflow or set of workflows. Also, they can be triggered manually or automatically.

After configuring the visual builder, we can merge the set-up-semaphore branch to the default branch for continuous deployment to Firebase using automatic promotions. In our case, the Deploy to Firebase promotion gets triggered once the condition is satisfied by the workflow run.

Configuring the deployment pipeline

Similar to the Main pipeline, we will use a Mac Based Virtual Machine environment with a macos-xcode13 image.

Next, in this pipeline, you will also need a Install Dependencies block set up with a job Install and cache Flutter:

Last, create a block named Deploy to Firebase with a job Run Fastlane:

This block is responsible for executing your lane in fastlane.

Click Run the workflow and commit the changes.

Awesome, your workflow should be ready for automatic deployments.

Testing continuous deployment

To check automatic promotions and deployments, we should merge it to the working branch to master:

Now, push the changes to trigger the build.

Setting up a continuous deployment pipeline for iOS takes more time than Android, but it’s worth the investment. Creating new releases every time a developer merges a pull request using this approach saves you half the time if you’re doing all the steps mentioned above manually, especially dealing code-signing for your teams.

Originally published at on January 20, 2022.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store

Supporting developers with insights and tutorials on delivering good software. ·