iOS Beta deployment using fastlane

Building your app

fastlane takes care of building your app using a feature called gym, just add the following to your Fastfile:

lane :beta do
  gym(scheme: "MyApp")
end

Additionally you can specify more options for building your app, for example

lane :beta do
  gym(scheme: "MyApp",
      workspace: "Example.xcworkspace",
      include_bitcode: true)
end

Try running the lane using

fastlane beta

If everything works, you should have a [ProductName].ipa file in the current directory. To get a list of all available parameters for gym, run fastlane action gym.

Codesigning

Chances are that something went wrong because of code signing at the previous step. We prepared our own Code Signing Guide that helps you setting up the right code signing approach for your project.

Uploading your app

After building your app, it's ready to be uploaded to a beta testing service of your choice. The beauty of fastlane is that you can easily switch beta provider, or even upload to multiple at once, without any extra work.

All you have to do is to put the name of the beta testing provider of your choice after building the app using gym:

lane :beta do
  match(type: "appstore")       # see code signing guide for more information
  gym(scheme: "MyApp")          # build your app
  testflight                    # upload your app to TestFlight
  slack(message: "Successfully distributed a new beta build")
end

fastlane automatically passes on information about the generated .ipa file from gym to the beta testing provider of your choice.

To get a list of all available parameters for a given action, run

fastlane action slack

Supported beta testing services

TestFlight

You can easily upload new builds to TestFlight (which is part of iTunes Connect) using fastlane. To do so, just use the built-in testflight action after building your app

lane :beta do
  # ...
  gym
  testflight
end

Some example use cases

lane :beta do
  # ...
  gym

  # Variant 1: Provide a changelog to your build
  testflight(changelog: "Add rocket emoji")

  # Variant 2: Skip the "Waiting for processing" of the binary
  #   While this will speed up your build, it will not distribute
  #   the binary to your tests, nor set a changelog
  testflight(skip_waiting_for_build_processing: true)
end

If you used fastlane init to setup fastlane, your Apple ID is stored in the fastlane/Appfile. You can also overwrite the username, using testflight(username: "[email protected]").

To get a list of all available options, run

fastlane action testflight

With fastlane, you can also automatically manage your beta testers, check out TODO for more information.


Crashlytics

lane :beta do
  # ...
  gym
  crashlytics(api_token: "[insert_key_here]",
              build_secret: "[insert_key_here]")
end

To get your API token, open the organizations settings page and click on the API key and build secret links.

To get a list of all available options, run

fastlane action crashlytics

TODO: Also mention the other onboarding method


HockeyApp

lane :beta do
  # ...
  gym
  hockey(api_token: "[insert_key_here]")
end

To get your API token, open API Tokens in Account Settings. From there, you can find your existing API token, or create a new one.

To get a list of all available options see the hockey action docs, or run

fastlane action hockey

TestFairy

lane :beta do
  # ...
  gym

  testfairy(api_key: "[insert_key_here]")

  # Variant 1: Provide a changelog
  testfairy(api_key: "[insert_key_here]", 
            comment: "Add rocket emoji")

  # Variant 2: Specify tester groups
  testfairy(api_key: "[insert_key_here]", testers_groups: ["group1"])
end

To get a list of all available options, run

fastlane action testfairy

More information about the service on TestFairy.com.

Release Notes

Automatically based on git commits

Your changelog changes, so it doesn't make a lot of sense to store a static release note in the Fastfile.

lane :beta do
  match
  gym

  changelog_from_git_commits # this will generate the changelog based on your last commits
  testflight
end

Get a list of all available options using fastlane action changelog_from_git_commits, here are some examples

changelog_from_git_commits(
  between: ['7b092b3', 'HEAD'], # Optional, lets you specify a revision/tag range between which to collect commit info
  include_merges: true # Optional, lets you filter out merge commits
)

Prompt for changelog

You can automatically be asked for the changelog in your terminal using the prompt action:

lane :beta do
  # Variant 1: Ask for a one line input
  changelog = prompt("Changelog: ")

  # Variant 2: Ask for a multi-line input
  #   The user confirms their input by typing `END` and Enter
  changelog = prompt(
    text: "Changelog: ",
    multi_line_end_keyword: "END"
  )

  match
  gym

  testflight(changelog: changelog)
end

Fetching the changelog from the file system or remote server

You can fetch values from anywhere in your Fastfile, including the file system and remote server

lane :beta do
  # Variant 1: Read from file system
  #   note the `..`, since fastlane runs in the _fastlane_ directory
  changelog = File.read("../Changelog.txt")

  # Variant 2: Fetch data from a remote web server
  changelog = download(url: "https://lookatmycms.com/changelog.txt")

  match
  gym

  testflight(changelog: changelog)
end

Best Practices

Manage devices and testers using fastlane

TestFlight

If you're using TestFlight you don't need to worry about UDIDs of your devices. Instead you just maintain a list of testers based on their Apple ID email address.

fastlane supports automatically registering devices using different approaches

boarding

boarding allows you set up a registration page for your beta testers, so they can enter their email address and start testing your application.

/img/getting-started/ios/boarding-screenshot.png

Check out the boarding GitHub repo for more information.

pilot

pilot is automatically installed with fastlane, you can use it to register individual testers to TestFlight

# Register a new external tester
fastlane pilot add [email protected]

# Register a new external tester and add them to your app
fastlane pilot add [email protected] -a com.app.name

Third party beta testing services

If you're using a third party beta testing service, you'll need to manage your registered devices and their UDIDs. fastlane already supports device registrations and updating provisioning profiles out of the box.

lane :beta do
  # Before calling match, we make sure all our devices are registered on the Apple Developer Portal
  register_devices(devices_file: "devices.txt")

  # After registering the new devices, we'll make sure to update the provisioning profile if necessary
  # Note how we make sure to pass "adhoc" to get and use a provisioning profile for Ad Hoc distribution
  match(force_for_new_devices: true, type: "adhoc")
  gym
  # ...
end

The devices.txt should look like this:

Device ID Device Name
A123456789012345678901234567890123456789  DeviceName1
B123456789012345678901234567890123456789  DeviceName2

Incrementing the build number

Depending on the beta testing service you use, you'll have to increment the build number each time you upload a new build. This is a requirement for TestFlight for example.

To do so, there are some built-in fastlane actions available, here are some examples

Commiting the build number to version control

The code sample below will increment the build number and commit the project changes to version control.

lane :beta do
  # Ensure that your git status is not dirty
  ensure_git_status_clean

  # Increment the build number (not the version number)
  # Providing the xcodeproj is optional
  increment_build_number(xcodeproj: "Example.xcodeproj")

  # Commit the version bump
  commit_version_bump(xcodeproj: "Example.xcodeproj")

  # Add a git tag for this build. This will automatically
  # use an appropriate git tag name
  add_git_tag

  # Push the new commit and tag back to your git remote
  push_to_git_remote
end

Fetching the latest build number from TestFlight

The code sample below will use the latest build number from TestFlight and temporarily set it.

lane :beta do
  increment_build_number(
    build_number: latest_testflight_build_number + 1,
    xcodeproj: "Example.xcodeproj"
  )
end

For all the steps above, there are more parameters available, run the following to get a full list:

fastlane action [action_name]