Distribute your pre-release iOS builds faster with App Distribution and fastlane

1. Before you begin

4cddd34bd261cea0.png

In this codelab, you'll learn how to use Firebase App Distribution and its fastlane plugin to distribute an iOS app to testers, collect test device UDIDs, and register them to your app's provisioning profile, so you can get Ad Hoc builds quickly into testers' hands.

What you'll learn

  • How to upload and distribute a pre-release iOS app (Ad Hoc) to testers using Firebase App Distribution and fastlane.
  • How to sign up as a tester and download the distributed app on a test device.
  • How to quickly register test devices by exporting test device UDIDs with App Distribution's fastlane plugin.
  • How to update your app's provisioning profile and reupload it for distribution.

What you'll need

  • A Google account
  • An Apple machine with XCode 11.7+ installed
  • An Ad Hoc pre-release iOS app built in Xcode
  • A paid Apple Developer account
  • A physical iOS device for testing.

The iOS simulator app will work for most of the codelab, but simulators cannot download releases.

You can still verify that the setup worked by verifying that the "Download" button appears on the App Distribution tester web app.

2. Get Started

Set up fastlane

App Distribution integrates with fastlane to enable you to automate distributing pre-release builds of your app. App Distribution integrates with your fastlane configuration.

  1. Install and set up fastlane.
  2. Run fastlane init in your project's root directory during setup, and choose "Manual setup." You'll see a subdirectory called fastlane that contains a Fastfile, Appfile, and Pluginfile, which you'll use to configure fastlane.

Install the Firebase CLI

You will also need to install the Firebase CLI. If you are using macOS or Linux, you can run the following cURL command:

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

If you are using Windows, read the installation instructions to get a standalone binary or to install via npm.

Once you've installed the CLI, running firebase --version should report a version of 12.0.0 or higher:

$ firebase --version
12.0.0

3. Build your app with fastlane

Build your app

  1. Set some global variables for fastlane in your ./fastlane/Appfile. Include your app's ID and your Apple ID:
app_identifier("<your app's bundle identifier>")
apple_id("<your Apple id>")
  1. Create your first lane and use fastlane's build_app action (also known as gym) to build your app by adding the following to your ./fastlane/Fastfile:
default_platform(:ios)

lane :build do
    build_app(export_method: "ad-hoc")
end
  1. Sign your app for distribution.

For this codelab, you'll manage your own certification and profile using get_certificates (also known as cert), which generates signing certificates locally and stores everything in your macOS Keychain. Typically, however, you'll want to use fastlane sync_code_signing action (also known as match) to securely manage your team's code signing certificates and profiles.

lane :build do
    get_certificates()
    build_app(export_method: "ad-hoc")
end
  1. Set up a provisioning profile for your app using the get_provisioning_profile action (also known as sigh). This allows you to share your app with testers.
lane :build do
    get_certificates()
    get_provisioning_profile(adhoc: true)
    build_app(export_method: "ad-hoc")
end
  1. [Optional] If you've never run your app before, run the following command to create your app in the Apple developer console:

$ fastlane produce --skip_itc

  1. Finally, build your app by running the lane.

You'll be prompted for your Apple ID, password (which is stored in your Keychain), and your app's bundle ID.

$ fastlane build

If you hit any issues, please see the fastlane troubleshooting guide.

4. Upload your app to Firebase

Now that you've built your app, you're ready to upload it to App Distribution.

Create and set up a Firebase project

  1. Sign in to Firebase.
  2. In the Firebase console, create or add a new project, and then name your project "UDID Export Codelab."

You don't need to enable Google Analytics for this project.

  1. Click Create project.

Add your iOS app to the project

  1. Click the iOS icon to create a new Firebase iOS app, and enter your app's bundle ID.

9c26c130a6c42212.png

  1. Skip the next few steps, then click Continue to console. You'll add SDKs to your app later.

Your project and app are now available in the Project Overview page.

66f79cc8a97fa8e9.png

Enable App Distribution

  1. Under the Release & Monitor section, click App Distribution.
  2. After accepting the terms, click "Get started" to enable App Distribution for your app.

460213326c2784ae.png

Set up a distribution in fastlane

  1. Run the following command from the root of your iOS project to add App Distribution to your fastlane configuration.

If the command prompts you with an option, select Option 3: RubyGems.org:

$ fastlane add_plugin firebase_app_distribution

  1. Confirm that the plugin is installed:

$ fastlane

The output should show fastlane-plugin-firebase_app_distribution in the list of installed plugins.

  1. After confirming the plugin is installed, choose option 0 to cancel.

Authenticate your Firebase project

To use the fastlane plugin, you'll first authenticate your Firebase project.

  1. Run the following command to connect the CLI to your Google account:

$ firebase login

  1. When the command prints an authentication link, open the link in a browser.
  2. When prompted, sign in to your Google Account and grant permission to access your Firebase project.

Distribute your app

You're now ready to distribute your app.

  1. At the top of your ./fastlane/Fastfile, define a variable called firebase_app_id. Replace <your_app_id> with the Firebase App ID for the app you created (this can be found in the project settings page).

The Fastfile is written in Ruby, so use Ruby syntax to define variables.

firebase_app_id = "<your_app_id>"
  1. Add a new lane called distribute that calls the build lane, and then distributes your app using the firebase_app_distribution action.
lane :distribute do
    build
    firebase_app_distribution(
        app: firebase_app_id,
        release_notes: "Try out this app!",
    )
end
  1. Run the new lane to build your app and create a distribution.

$ fastlane distribute

At this point, your Fastfile should look like the following:

firebase_app_id = "<your Firebase app ID>"

default_platform(:ios)

lane :build do
    get_certificates()
    get_provisioning_profile(adhoc: true)
    build_app(export_method: "ad-hoc")
end

lane :distribute do
    build
    firebase_app_distribution(
        app: firebase_app_id,
        release_notes: "Try out this app!",
    )
end

After you refresh the Firebase console, you'll see the new release for your app.

c59dc1a94de3bf3c.png

5. Invite testers to download your app

When a tester accepts an invitation to test an Ad Hoc build, they are asked for permission to share their UDID. If they agree, App Distribution collects their device information and notifies you via email. In this section, you'll add yourself as a tester to download and test the app you distributed.

Add yourself as a tester to the release

  1. Under firebase_app_id at the top of your Fastfile, create a variable to hold testers and include your own email address, as well as other optional email addresses you'd like to try.
firebase_app_id = "<your Firebase app ID>"
app_testers = [
  "your@email.com",
  "another@email.com",
]
  1. Apply Ruby's Array#join method to turn the app_testers array into a comma-separated string, which the testers parameter expects. Then, pass the result to the testers parameter of firebase_app_distribution.
lane :distribute do
    build
    firebase_app_distribution(
        app: firebase_app_id,
        release_notes: "Try out this app!"
        testers: app_testers.join(","),
    )
end

At this point, your Fastfile should look like this:

firebase_app_id = "<your Firebase app ID>"
app_testers = [
  "your@email.com",
  "another@email.com",
]

default_platform(:ios)

lane :build do
    get_certificates()
    get_provisioning_profile(adhoc: true)
    build_app(export_method: "ad-hoc")
end

lane :distribute do
    build
    firebase_app_distribution(
        app: firebase_app_id,
        release_notes: "Try out this app!",
        testers: app_testers.join(","),
    )
end
  1. Run the lane again.

$ fastlane distribute

Once you run the lane, testers you added will receive an invitation email from App Distribution notifying them of the newly available release. In the Firebase console, you can now see the testers you added under your app's release.

2e0fc9603b868af8.png

Since you included your email address, you'll receive an email from Firebase App Distribution inviting you to test the app. You're now the first tester! Continue the section below to get set up as a tester on your test device.

Register your test device

As a tester, you'll need to sign in to Google on your test device in order to access app releases you've been invited to test. Because your test build is an Ad Hoc release, you'll need to also register your test device by installing the Firebase profile. Afterwards, releases that become available to you can be accessed from the App Distribution tester web app, using the web clip that's added to your device's home screen.

  1. On your iOS test device, open the email sent from Firebase App Distribution and tap the Get Started link. Make sure to open the link in Safari.
  2. You are now in the App Distribution tester web app. In the page that appears, sign in with your Google account and tap Accept invitation.

d833407de251b89f.png

  1. You can now see the releases you've been invited to. Tap Register device under one of the releases.

fd141215e54a938d.png

  1. When prompted, download the Firebase profile, then install the profile in the Settings app.

Installing the profile gives Firebase permission to:

  • Register the test device by collecting the device's unique device ID (UDID).

Firebase sends all Owners and Editors of the Firebase project an email that includes the test device's UDID.

  • Install a web clip to the test device's home screen. The web clip opens the App Distribution tester web app, which allows you to install and access all of your test apps.

In the App Distribution tester web app, your test device is now registered for your app's release.

fe93d649dfa25877.png

Now that you've shared your test device's UDID to Firebase, you can now resume as a developer. In the Testers tab of the App Distribution dashboard, your tester information now appears under your app's release with the status as "Accepted":

7b9f665a63a384cf.png

In the next section, you'll add the device UDID to your app's provisioning profile and then build a version of your app that works with your test device.

Export your tester device UDIDs

As the developer, you'll get an email from Firebase containing the test device's UDID. As an option, App Distribution makes it easy to gather multiple new device UDIDs at once by letting you export them directly from the Firebase console as a raw text file.

  1. To export all UDIDs, open the Testers & Groups tab.

241a9936898a2fc0.png

  1. Click Export Apple UDIDs.

bcf0c26c522d9b4e.png

The file should contain the UDID of your test device.

Device ID            Device Name                            Device Platform
1234567890     udid.codelab.tester@gmail.com - iPhone SE 2nd Gen        ios

The UDIDs can also be exported from the command line using fastlane, which you'll do in the next section.

6. Update your app's provisioning profile and rebuild it

Now, you'll add your test device UDID to your app's provisioning profile, rebuild a version of your app that works for your device, and distribute the new version.

Add UDID export lane

  1. Add another variable at the top of your Fastfile, and set it to a file path where your testers' device UDIDs will be downloaded.
firebase_app_id = "<your Firebase app ID>"
app_testers = [
  "your@email.com",
  "another@email.com",
]
tester_udids_file = "tester_udids.txt"
  1. Set up a new lane that uses the App Distribution plugin's UDID export action to download the tester UDIDs, just like you did from the console.
lane :download_udids do
    firebase_app_distribution_get_udids(
        app: firebase_app_id,
        output_file: tester_udids_file,
    )
end
  1. Run the following lane to download the UDIDs.

$ fastlane download_udids

  1. Print out the downloaded file, which should contain the test device UDIDs.

$ cat tester_udids.txt

Add devices to Apple developer console

  1. Create the following lane to add the UDIDs to your devices list in the Apple developer console, so you can add them to your provisioning profile using fastlane's register_devices action:
lane :add_new_devices do
    register_devices(devices_file: tester_udids_file)
end
  1. Then, run the lane:

$ fastlane add_new_devices

You should then see the new devices in your developer console's devices list.

Add devices to your provisioning profile

  1. Add the force argument to the provisioning profile step in your build lane, in order to force it to pick up new devices every time you build.
lane :build do
    get_certificates()
    get_provisioning_profile(adhoc: true, force: true)
    build_app(export_method: "ad-hoc")
end

Re-run lane to build and upload

Now, you'll update your distribute lane with the new lanes in order to add the devices to the provisioning profile, re-build the app, and then distribute it.

  1. Call the new lanes from distribute:
lane :distribute do
    download_udids
    add_new_devices
    build
    firebase_app_distribution(
        app: "1:123456789:ios:abcd1234",
        release_notes: "Try out this app!"
        testers: app_testers.join(","),
    )
end
  1. Run the distribute lane:

$ fastlane distribute

At this point, your Fastfile should look like this:

firebase_app_id = "<your Firebase app ID>"
app_testers = [
  "your@email.com",
  "another@email.com",
]
tester_udids_file = "tester_udids.txt"

default_platform(:ios)

lane :build do
    get_certificates()
    get_provisioning_profile(adhoc: true, force: true)
    build_app(export_method: "ad-hoc")
end

lane :distribute do
    download_udids
    add_new_devices
    build
    firebase_app_distribution(
        app: firebase_app_id,
        release_notes: "Try out this app!",
        testers: app_testers.join(","),
    )
end

lane :download_udids do
    firebase_app_distribution_get_udids(
        app: firebase_app_id,
        output_file: tester_udids_file,
    )
end

lane :add_new_devices do
    register_devices(devices_file: tester_udids_file)
end

Download the release from the test device

Now that your app includes the test device UDIDs, they can be installed onto the test devices.

e275f73d57cc8fb1.png

  1. On your test device, return to the App Distribution tester web app using the link in the email, or the icon on the device's home screen.

When you navigate to the UDID codelab app, you can see that the release is ready to download.

dad6d03b6ad78746.png

  1. If you are on a physical device, press download, then install and run the app!

7. Congratulations

You've now configured App Distribution and fastlane to automate your pre-release testing process. Now, when you want to invite additional testers, or add their UDIDs to your app, you'll only need to run one command: fastlane distribute.

So no more individually collecting UDIDs from testers, or going to the Apple developer console to update devices lists or provisioning profiles. You don't even need to open XCode!

This workflow is easy to set up to run hourly or daily in your continuous integration environment.

Further reading