docs Documentation

Official MDX developer resources and documentation for buger/docs with 37k stars. Verified technical context for AI.

36,534 stars MDX 1 file ยท ~243,732 tokens
RAW Doc

1. Project Overview & Quickstart (buger/docs)

File: README.md

fastlane docs

This repo contains all documentation for fastlane. You can find the .md files inside the docs folder.

To preview the updated documentation locally, just clone the repo, modify the file, and run

text
mkdocs serve

The live version is available on docs.fastlane.tools.

Why new docs?

You can find more information here

Deploy changes

Once a PR is merged into master, the latest version will automatically be deployed to docs.fastlane.tools by one of the hard working fastlane bots. No need to do anything manually. The resulting HTML files are stored in the gh-pages branch.

Installation of [mkdocs](http://www.mkdocs.org/)

sh
brew install python # if you don't have pip already
[sudo] pip install -r requirements.txt

Adding a Python dependency

Likely, to add a Markdown extension.

  1. Install with pip install <some extension>
  2. Add to requirements-to-freeze.txt.
  3. Run pip freeze > requirements.txt to update the exact requirements.

Why requirements-to-freeze.txt?

Based on A Better Pip Workflow,
requirements-to-freeze.txt and requirements.txt provide a similar experience
to Gemfile and Gemfile.lock, respectively.

requirements-to-freeze.txt lets you pick out the top level packages the
project depends on, while requirements.txt exactly specifies all of the
dependencies and subdependencies for repeatable builds.


File: docs/best-practices/continuous-integration.md

Continuous Integration

Best Practices

Two-step or Two-factor auth

If you want to upload builds to TestFlight/iTunes Connect from your CI machine, you need to generate an application specific password:

  1. Visit appleid.apple.com/account/manage
  2. Generate a new application specific password
  3. Provide the application specific password using the environment variable FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD

Because your CI machine will not be able to prompt you for your two-step or two-factor auth information, you also need to generate a login session for your CI machine in advance. You can get this by running:

text
fastlane spaceauth -u [email protected]

This will generate a token you can set using the FASTLANE_SESSION environment variable on your CI system.

Deploy Strategy

You should not deploy a new App Store update after every commit, since you still have to wait 1-2 days for the review. Instead it is recommended that you use Git Tags, or custom triggers to deploy a new update.

You can set up your own Release job, which is only triggered manually.

Jenkins Integration

Deploying from your own computer isn't cool. You know what's cool? Letting a remote server publish app updates for you.

fastlane automatically generates a JUnit report for you. This allows Continuous Integration systems, like Jenkins, access the results of your deployment.

Installation

The recommended way to install Jenkins is through homebrew:

no-highlight
brew update && brew install jenkins

From now on start Jenkins by running:

no-highlight
jenkins

To store the password in the Keychain of your remote machine, it is recommended that you run match or deliver using ssh or remote desktop at least once.

Plugins

You'll find the following Jenkins plugins to be useful:

Build Step

Use the following as your build step:

no-highlight
fastlane appstore

Replace appstore with the lane you want to use.

setup_jenkins

You can use setup_jenkins action which integrates well with the Keychains and Provisioning Profiles Plugin. Selected keychain will automatically unlocked and the selected code signing identity will be used. Also all build results, like IPA files, archives, dSYMs and result bundles will be stored in the ./output folder in the job workspace. In additions setup_jenkins will create separate derived data folder for each job (in the ./derivedData).

Under the hood setup_jenkins configures other actions like: gym, scan, xcodebuild, backup_xcarchive and clear_derived_data.

commit_version_bump || git_commit

You can use commit_version_bump or git_commit action to commit changes to your repository in your fastlane setup. When you are using webhooks to trigger your build on a push this will cause an infinite loop of triggering builds.

Gitlab

When you are using Gitlab you will need the GitLab Plugin. Inside the job you want to configure you go to Build Triggers > Build when a change is pushed to GitLab > Enable [ci-skip].
When you include [ci-skip] in your build this commit won't trigger the build in jenkins at all.

Example

ruby
build_number = increment_build_number
commit_version_bump(message:"[ci-skip] Version Bump to #{build_number}")
git_commit(path:"./CHANGELOG.md", message:"[ci-skip] Updated CHANGELOG for Build #{build_number}")
push_to_git_remote

Test Results and Screenshots

To show the deployment result right in Jenkins

  • Add post-build action
  • Publish JUnit test result report
  • Test report XMLs: fastlane/report.xml

To show the generated screenshots right in Jenkins

  • Add post-build action
  • Publish HTML reports
  • HTML directory to archive: fastlane/screenshots
  • Index page: screenshots.html

Save and run. The result should look like this:

Circle Integration

To run fastlane on Circle as your CI, first create a Gemfile in the root of your project with the following content

ruby
source "https://rubygems.org"

gem "fastlane"

and run

no-highlight
gem install bundler && bundle update

This will create a Gemfile.lock, that defines all Ruby dependencies. Make sure to commit both files to version control.

Next, use the following circle.yml file

yml
machine:
  xcode:
    version: "7.3"
dependencies:
  override:
    - bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3 --without development
  cache_directories:
    - vendor/bundle
test:
  override:
    - bundle exec fastlane test

This will automatically cache the installed gems on Circle, making your CI builds much faster!

Bamboo Integration

Repository setup

In bamboo under Linked Repositories (where you configure your git repo) under Advanced Settings is an option called Exclude changesets

This dialog will allow you to enter a regular expression that if a commit matches, a build will not be triggered.

For example, if your Fastfile is configured to make a commit message in the style of

no-highlight
Build Version bump by fastlane to Version [0.3] Build [8]

Then you could use the following regex to ignore these commits

no-highlight
^.*Build Version bump by fastlane.*$

Setting repository remote

By default bamboo will do an anonymous shallow clone of the repo. This will not preserve the git remote information nor the list of tags. If you are using bamboo to create commits you may want to use a code block similar to the following:

ruby
# In prep for eventually committing a version/build bump - set the git params
sh('git config user.name "<COMMITTER USERNAME>"')
sh('git config user.email <COMITTER EMAIL>')

# Bamboo does an anonymous checkout so in order to update the build versions must set the git repo URL
git_remote_cmd = 'git remote set-url origin ' + ENV['bamboo_repository_git_repositoryUrl']
sh(git_remote_cmd)

Speeding up build times with carthage

Carthage is a wonderful dependency manager but once you are start using a large number of frameworks, things can start to slow down, especially if your CI server has to run carthage EVERY time you check in a small line of code.

One way to make build times faster is to break your work up into two separate build plans (this can get even more funky if you start having multiple branches)

The general idea is to make a build plan: Project - Artifacts that builds the Carthage directory and stores it as a shared artifact. Then you create a second build plan Project - Fastlane that pulls down the Carthage directory and runs fastlane.

Artifact Plan

Use a simple setup to create this build plan. First off you want to make sure this plan is manually triggered only - because you only need to run it whenever the Cartfile changes as opposed to after ever single commit. It could also be on a nightly build perhaps if you desire.

Stages / Jobs / Tasks

This plan consists of 1 Job, 1 Stage and 2 Tasks

  • Task 1: Source Code Checkout
  • Task 2: Script (carthage update)

Artifact definitions

Create a shared artifact with the following info:

  • Name: CarthageFolder
  • Location: (leave blank)
  • Copy Pattern: Carthage/Build/**

Optional: You may want to automatically make the fastlane plan trigger whenever this plan is built

_fastlane_ plan

When configuring fastlane to run in this setup you need to make sure that you are not calling either:

ruby
reset_git_repo(force: true)

or

ruby
ensure_git_status_clean

as these calls will either fail the build or delete the Carthage directory. Additionally you want to remove any carthage tasks from inside your Fastfile as carthage is now happening externally to the build.

Build plan setup

What this build plan does is it checks out the source code, then it downloads the entire Carthage/Build/ directory into your local project - which is exactly what would be created from carthage bootstrap and then it runs fastlane

  • Task 1: Source Code Checkout
  • Task 2: Artifact Download
  • Task 3: fastlane

GitLab CI Integration

Use GitLab CI Runner running on a macOS machine
to build using fastlane.

Repository setup

First create a Gemfile in the root of your project with the following content:

ruby
source "https://rubygems.org"

gem "fastlane"

Add a .gitlab-ci.yml file to trigger fastlane.

yml
stages:
  - unit_tests
  - test_flight

variables:
  LC_ALL: "en_US.UTF-8"
  LANG: "en_US.UTF-8"

before_script:
  - gem install bundler
  - bundle install

unit_tests:
  dependencies: []
  stage: unit_tests
  artifacts:
    paths:
      - fastlane/screenshots
      - fastlane/logs
  script:
    - fastlane tests
  tags:
    - ios

test_flight_build:
  dependencies: []
  stage: test_flight
  artifacts:
    paths:
      - fastlane/screenshots
      - fastlane/logs
  script:
    - fastlane beta
  tags:
    - ios
  only:
     - /^release-.*$/
     - master

See the ``.gitlab-ci.yml` documentation
for more information on how this file works.

Setting up the lanes

You should have a lane - in this example called beta - which should do the usual, match, gym, pilot, to distribute an updated Test Flight version, and one lane tests which calls scan to run UI Tests.

Auto-incremented build number.

To get an auto-incremented build number you can use something like the following lane:

ruby
lane :increment_build_number do
  increment_build_number(build_number: ENV['CI_BUILD_ID'])
end

Then the GitLab CI build ID (which iterates on each build) will be used.


File: docs/best-practices/keys.md

fastlane keys

This guide will show you the best ways to store and use your keys for services like Crashlytics, Slack, etc.

In your `Fastfile`

ruby
lane :beta do
  crashlytics(api_token: "123abc", build_secret: "secret_key")
end

or if you want to only define the keys once and use it multiple times

ruby
ENV["CRASHLYTICS_API_TOKEN"] = "123abc"
ENV["CRASHLYTICS_BUILD_SECRET"] = "secret_key"

lane :beta do
  crashlytics
end

This is the most straight forward and easiest solution, but might cause a few issues:

  • If you ever decide to open source your application you'll have to make sure to remove the keys from your git history
  • If your keys got invalidated for whatever reason and you decide to rollback your code base to an earlier stage the keys will also be rolled back

To get the name of the available environment variables, run fastlane action [action_name].

Bash Profile

To not store your keys in git, you can pass all parameters of all actions using environment variables.

You can edit your ~/.bash_profile to include something like

sh
export SLACK_URL="https://hooks.slack.com/services/T03NA19Q5/..."
export CRASHLYTICS_API_TOKEN="123abc"

If you use a different shell (e.g. zshell) you'll need to edit ~/.zshrc instead.

After editing the .bash_profile you need to either re-open your terminal session or run source ~/.bash_profile.

Disadvantages

  • Every terminal tool you run gets access to your environment variables.
  • You have to edit your bash profile on every computer you want to run fastlane from
  • The bash profile isn't automatically loaded by some CI-systems like Jenkins

To get the name of the available environment variables, run fastlane action [action_name].

[dotenv](https://github.com/bkeepers/dotenv)

dotenv is a system to store your environment in a file that is project specific. Basically you have a hidden file in your project containing all the environment variables for your project.

You can store a default configuration in .env.default which will be loaded by fastlane automatically.

sh
SLACK_URL="https://hooks.slack.com/services/T03NA19Q5/..."
CRASHLYTICS_API_TOKEN="123abc"

You might want different configurations depending on your environment.

no-highlight
fastlane beta --env development

and store the configuration in .env.development with all keys for the development environment.

Install [sudo] gem install dotenv or add dotenv to your Gemfile. More information about the recommend way to install gems.

To get the name of the available environment variables, run fastlane action [action_name].


File: docs/best-practices/source-control.md

Source Control

It is recommended that you keep fastlane configuration files in the repository. You may want to add the following lines to the repository's .gitignore (Git) or .hgignore (Mercurial) file to exclude generated and temporary files:

no-highlight
# fastlane specific
fastlane/report.xml

# deliver temporary files
fastlane/Preview.html

# snapshot generated screenshots
fastlane/screenshots

# scan temporary files
fastlane/test_output

It is also recommended that you avoid storing screenshots or other delivery artifacts in the repository. Instead, use fastlane to re-generate whenever needed.


File: docs/codesigning/common-issues.md

Common code signing issues

Xcode errors

Code Sign error: No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) matching the bundle identifier "X" were found.

The provisioning profile for the given app identifier "X" is not available on the local machine. Make sure you have a valid provisioning profile for the correct distribution type (App Store, Development or Ad Hoc) on the Apple Developer Portal, download and install it, and select the profile in the Xcode settings (See Setting up your Xcode Project).

You might have the provisioning profile installed locally, but miss the private key or certificate for it.

No matching codesigning identity found: No codesigning identities (i.e. certificate and private key pairs) matching "iPhone Distribution: X" were found

The code signing identity you specified in the Xcode project can't be found in your local keychain. Make sure to transfer the certificate and private key from another Mac (or wherever you store the private key), or to update the project file to use the correct code signing identity.

Error Domain=IDEDistributionErrorDomain Code=1 "The operation couldnโ€™t be completed. (IDEDistributionErrorDomain error 1.)"

This error can have a lot of reasons, some things you should try:

  • Verify your Keychain is valid and you don't have an expired WWDR certificate using this guide
  • Verify both your certificate and provisioning profile are valid in both your Keychain and on the Apple Developer Portal (Check out Debugging codesigning issues for more information)
  • If you're using gym, try using the use_legacy_build_api flag to fallback to the Xcode 6 build API
  • Follow the other steps of Debugging codesigning issues

Provisioning profile does not match bundle identifier: The provisioning profile specified in your build settings ("X") has an AppID of "Y" which does not match your bundle identifier "Z"

Your project defines a provisioning profile that doesn't match the bundle identifier of your app. There is mismatch between the bundle identifiers, this might happen if you specify the wrong provisioning profile in your target.

Your build settings specify a provisioning profile with the UUID "X", however, no such provisioning profile was found.

Your project defines a provisioning profile which doesn't exist on your local machine. Check out Setting up your Xcode Project for more information how to properly specify a provisioning profile to avoid hard coded UUIDs in your project.

CodeSign Error: code signing is required for product type 'Application'...

Make sure to have a valid code signing identity defined in your project targets. This might happen when you select Don't Code Sign as Code Signing Identity.

fastlane errors

Could not find a matching code signing identity for type 'X'

There are no certificates available on the Apple Developer Portal. This could either mean someone revoked a certificate, or you don't have access to it.


File: docs/codesigning/getting-started.md

Codesigning concepts

If you are just starting a new project, it's important to think about how you want to handle code signing. This guide will help you choose the best approach for you.

For existing projects it might make sense to switch from a manual process to the match approach to make it easier for new team-members to onboard.

If you are new to code signing, check out the WWDC session that describes the fundamentals of code signing in Xcode.

Using [match](https://fastlane.tools/match)

The concept of match is described in the codesigning guide.

With match you store your private keys and certificates in a git repo to sync them across machines. This makes it easy to onboard new team-members and set up new Mac machines. This approach is secure and uses technology you already use.

Getting started with match requires you to revoke your existing certificates.

Make sure to follow Setting up your Xcode Project to set up your project properly.

Using [cert](https://fastlane.tools/cert) and [sigh](https://fastlane.tools/sigh)

If you don't want to revoke your existing certificates, but still want an automated setup, cert and sigh are for you.

  • cert will make sure you have a valid certificate and its private key installed on the local machine
  • sigh will make sure you have a valid provisioning profile installed locally, that matches the installed certificate

Add the following lines to your Fastfile

ruby
lane :beta do
  cert
  sigh
  gym
end

Make sure to follow Setting up your Xcode Project to set up your project properly.

Using Xcode's code signing feature

Occasionally the Automatic setting as the provisioning profile doesn't work reliably as it will just select the most recently updated provisioning profile, no matter if the certificate is installed.

That's why it is recommended to specify a specific provisioning profile somehow:

Xcode 7 and lower

You should avoid clicking the Fix Issue button (There is an Xcode plugin that disables the button), as it sometimes revokes existing certificates, and with it the provisioning profiles.

Unfortunately you can't specify the name of the provisioning profile in Xcode 7. Instead you can specify the UUID of the profile, which changes every time the profile gets re-generated (e.g. when you add a new device).

To work around this issue, check out Setting up your Xcode Project on how to pass a provisioning profile to Xcode when building your app.

Xcode 8 and up

Apple improved code signing a lot with the release of Xcode 8, the following has changed:

  • No more Fix Issue button, instead all code signing processes run in the background and show the log right in Xcode
  • You can now specify the provisioning profile by name, instead of the UUID (Check out Setting up your Xcode Project for more information)
  • Improved error messages when something goes wrong. If you run into code signing errors you should always try building and signing with Xcode to get more detailed error information. (Check out Debugging codesigning issues for more information)
  • Improved Automatic Provisioning that can create per-machine development private keys, certificates, and provisioning profiles. (Check out Setting up your Xcode Project for more information)

Manually

You can always manually create and manage your certificates and provisioning profiles using the Apple Developer Portal. Make sure to store the private key (.p12) of your certificates in a safe place, as they can't be restored if you lose them.

You can always download the certificate (.cer) and provisioning profile (.mobileprovision) from the Apple Developer Portal.

Where to go from here


File: docs/codesigning/troubleshooting.md

Debugging codesigning issues

This guide will help you resolve the most common code signing errors.

Error message

Make sure to find the exact error message in your build output. Many times the error message actually tells you how to resolve the issue.

To get even more details, try archiving using Xcode 8.

Different machine

Does code signing work on a different Mac, but not on yours? If so, chances are high you don't have the latest private key, the certificate or the provisioning profile. Also follow the Keychain part of this document to make sure you don't have any expired certificates installed.

Xcode project

Make sure to follow Setting up your Xcode Project to properly set up your project.

A check list on what you should verify on your Xcode project

  1. Make sure to have consistent code signing settings across your targets
  2. Don't set any code signing settings on your project level, just on the target level
  3. Make sure the bundle identifier matches the one of your provisioning profile
  4. Make sure the code signing identity is set to iOS Distribution for Release builds
  5. Make sure to set a provisioning profile for all your targets, e.g. Watch, Today widget, ...
  6. Check your working copy in git - did you make any changes by mistake?

Developer Portal

If a certificate gets revoked, all connected provisioning profiles get invalidated. This however might not immediately show up in your local keychain.

  1. Open the Developer Portal
  • Verify your certificates are valid, and didn't expire or get revoked
  • Switch to the Provisioning Profiles and make sure the profiles you want to use are all still valid
    1. If your profile is invalid or expired, you can easily fix it:
    2. If you're using match, run match with force enabled
    • If you're using sigh, run sigh with force enabled
    • If you're doing manual code signing, edit the provisioning profile, and click on Generate on the bottom of the screen. Make sure to select the correct certificate, then download and open the new provisioning profile
    • If your profile is valid, but you still have issues make sure
      1. that the certificate matches the certificate you have installed locally. You can view the used certificate by editing the profile (Don't click Generate, unless you want to re-generate the provisioning profile)
      • that all devices you need are included (Development and Ad-Hoc only)
      • that you are actually looking at the correct provisioning profile, that matches the bundle identifier of your app. You might have multiple provisioning profiles for the same app / certificate combination. By default Xcode will use the last modified one.

Keychain

  1. Run security find-identity -v -p codesigning to get a list of locally installed code signing identities. Does yours show up?

  2. Open the Keychain Access app, switch to Certificates and find your iOS Developer or iOS Distribution entry and unfold the entry to verify the private key is locally installed:

  3. Make sure to have deleted all expired WWDR certificates, more information here. There might be 2 expired WWDR certificates, one in the login, and one in the system keychain

Have you tried turning it off and on again?

As funny as it sounds, sometimes restarting your Mac helps.

fastlane

Run fastlane in verbose mode to get even more debug information:

no-highlight
fastlane [lane] --verbose

Common Issues

Check out Common code signing issues for the most common code signing issues and how you can solve them.


File: docs/codesigning/xcode-project.md

Setting up your Xcode Project

Xcode 8 and up

With Xcode 8 you can set a provisioning profile name for each of your targets instead of a provisioning profile UUID. By doing so, Xcode automatically selects the latest provisioning profile matching its name. This way you don't have to update your Xcode project, every time you re-generate your provisioning profile (e.g. when adding a new device)

You can now specify which provisioning profile to use in the General tab after disabling Automatically manage signing.

Alternatively you can also specify the provisioning profile in the Build Settings tab.

If your provisioning profile is not listed in the drop down, there might be a few reasons:

  • It doesn't match the bundle identifier of the target
  • The associated certificate or its private key is not installed on the local machine
  • The provisioning profile is not installed on the local machine

Check out Debugging codesigning issues for more information on how to debug signing issues.

Build settings

Previously you could specify the UUID of the provisioning profile using the PROVISIONING_PROFILE Xcode settings property, with Xcode 8 you specify it using the PROVISIONING_PROFILE_SPECIFIER instead:

no-highlight
DEVELOPMENT_TEAM = N8XAAASEU2;
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.themoji.app.release";

It is recommended to select the provisioning profile in the General tab in your Xcode project, so Xcode will automatically set the values mentioned above for you.

Set using environment variable

You could pass the profile specifier via environment variables too (See Xcode 7 approach below), however in most cases it's enough to define it statically in your project, per target, since usually neither your Team ID, nor the provisioning profile change.

If you're using match the following environment variables are being set for you:

text
+---------------------+------------------------------------------------+--------------------------------------+
|                                       Installed Provisioning Profile                                        |
+---------------------+------------------------------------------------+--------------------------------------+
| Parameter           | Environment Variable                           | Value                                |
+---------------------+------------------------------------------------+--------------------------------------+
| App Identifier      |                                                | me.themoji.release                   |
| Type                |                                                | appstore                             |
| Profile UUID        | sigh_me.themoji.beta_appstore                  | 22a19b3a-7cf6-4997-95f2-9cbb4d33fe7e |
| Profile Name        | sigh_me.themoji.beta_appstore_profile-name     | match AppStore me.themoji.release    |
| Development Team ID | sigh_me.themoji.beta_appstore_team-id          | N8XAAASEU2                           |
+---------------------+------------------------------------------------+--------------------------------------+

Check out the Xcode 7 section on how to update build settings using environment variables.

Using `match development` or Xcode Automatic Provisioning

Apple's Automatic Provisioning in Xcode 8 will automatically generate a private key, development certificate, and managed development provisioning profile for each computer used to build a project. Since Xcode can auto-generate these for you, there is no need to share them between teammates' computers. As such, when using Xcode Automatic Provisioning, there is no need to use match development to keep development keys, certificates, and provisioning profiles in sync.

If you are already using match to manage development code signing, Automatic Provisioning will use the match-generated key and certificate. However, Xcode will create and manage its own provisioning profile and will not use the match-generated profile.

`match appstore` and Xcode Automatic Provisioning

Xcode Automatic Provisioning doesn't sync your private keys across machines (if you have multiple computers or share them between teammates). To securely store your private key and have access to it from all your devices, use match appstore or match adhoc. This will sync your keys, certificates and provisioning profiles via git, encrypted using OpenSSL.

Xcode 7 and lower

Note: This approach is deprecated with Xcode 8

If you use Automatic value for your provisioning profile, Xcode sometimes selects the wrong profile, resulting in code signing errors at a later point.

Instead it is recommended to specify a specific provisioning profile, which can only be done using the UUID (in Xcode 7).

Since it is not recommended to update the project file, every time you update your provisioning profile, you can pass the UUID via environment variables.

To do so, open your target settings, open the dropdown for Provisioning Profile and select Other:

Using the $(...) notation, Xcode will use the provisioning profile matching the UUID, and fallback to Automatic if it's not provided.

If you use fastlane you don't have to do any extra work, since the environment variable for the latest profile are automatically set by match

ruby
lane :beta do
  match(type: "adhoc")
  gym
end

You can also manually set the environment variable using

ruby
lane :beta do
  ENV["PROVISIONING_PROFILE_TARGET1"] = "b01c39c9-1b4a-412e-9ae2-3087ee9ea9d3"
  gym
end

File: docs/getting-started/ios/appstore-deployment.md

iOS App Store 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:

text
lane :appstore do
  gym(scheme: "MyApp")
end

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

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

Try running the lane using

no-highlight
fastlane appstore

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.

Submitting your app

Generating screenshots

To find out more about how to automatically generate screenshots for the App Store, check out fastlane screenshots for iOS and tvOS.

Upload the binary and app metadata

After building your app, it's ready to be uploaded to the App Store. If you've already followed iOS Beta deployment using fastlane, the following code might look similar already.

ruby
lane :appstore do
  snapshot                      # generate new screenshots for the App Store
  match(type: "appstore")       # see code signing guide for more information
  gym(scheme: "MyApp")          # build your app
  appstore                      # upload your app to iTunes Connect
  slack(message: "Successfully uploaded a new App Store build")
end

fastlane automatically passes on information about the generated screenshots and the binary to the appstore action of your Fastfile.

For a list of all options for each of the steps run fastlane action [action_name].

Best Practices

Push Notifications

To make sure your latest push notification certificate is still valid during your submission process, add the following at the beginning of your lane:

ruby
lane :appstore do
  pem
  # ...
end

pem will ensure your certificate is valid for at least another 2 weeks, and create a new one if it isn't.

If you don't have any push certificates already, pem will create one for you and store locally in your project's directory. To get more information about the available options run fastlane action pem.


File: docs/getting-started/ios/beta-deployment.md

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:

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

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

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

Try running the lane using

no-highlight
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:

ruby
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

no-highlight
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

ruby
lane :beta do
  # ...
  gym
  testflight
end

Some example use cases

ruby
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

no-highlight
fastlane action testflight

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


Crashlytics

ruby
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

no-highlight
fastlane action crashlytics

TODO: Also mention the other onboarding method


HockeyApp

ruby
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

no-highlight
fastlane action hockey

TestFairy

ruby
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

no-highlight
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.

ruby
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

ruby
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:

ruby
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

ruby
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](https://github.com/fastlane/boarding#readme)

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

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

no-highlight
# 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.

ruby
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:

no-highlight
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.

ruby
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.

ruby
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:

no-highlight
fastlane action [action_name]

2. Official Technical Reference & Guides (buger/docs)

File: README.md

fastlane docs

This repo contains all documentation for fastlane. You can find the .md files inside the docs folder.

To preview the updated documentation locally, just clone the repo, modify the file, and run

text
mkdocs serve

The live version is available on docs.fastlane.tools.

Why new docs?

You can find more information here

Deploy changes

Once a PR is merged into master, the latest version will automatically be deployed to docs.fastlane.tools by one of the hard working fastlane bots. No need to do anything manually. The resulting HTML files are stored in the gh-pages branch.

Installation of [mkdocs](http://www.mkdocs.org/)

sh
brew install python # if you don't have pip already
[sudo] pip install -r requirements.txt

Adding a Python dependency

Likely, to add a Markdown extension.

  1. Install with pip install <some extension>
  2. Add to requirements-to-freeze.txt.
  3. Run pip freeze > requirements.txt to update the exact requirements.

Why requirements-to-freeze.txt?

Based on A Better Pip Workflow,
requirements-to-freeze.txt and requirements.txt provide a similar experience
to Gemfile and Gemfile.lock, respectively.

requirements-to-freeze.txt lets you pick out the top level packages the
project depends on, while requirements.txt exactly specifies all of the
dependencies and subdependencies for repeatable builds.


File: docs/best-practices/continuous-integration.md

Continuous Integration

Best Practices

Two-step or Two-factor auth

If you want to upload builds to TestFlight/iTunes Connect from your CI machine, you need to generate an application specific password:

  1. Visit appleid.apple.com/account/manage
  2. Generate a new application specific password
  3. Provide the application specific password using the environment variable FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD

Because your CI machine will not be able to prompt you for your two-step or two-factor auth information, you also need to generate a login session for your CI machine in advance. You can get this by running:

text
fastlane spaceauth -u [email protected]

This will generate a token you can set using the FASTLANE_SESSION environment variable on your CI system.

Deploy Strategy

You should not deploy a new App Store update after every commit, since you still have to wait 1-2 days for the review. Instead it is recommended that you use Git Tags, or custom triggers to deploy a new update.

You can set up your own Release job, which is only triggered manually.

Jenkins Integration

Deploying from your own computer isn't cool. You know what's cool? Letting a remote server publish app updates for you.

fastlane automatically generates a JUnit report for you. This allows Continuous Integration systems, like Jenkins, access the results of your deployment.

Installation

The recommended way to install Jenkins is through homebrew:

no-highlight
brew update && brew install jenkins

From now on start Jenkins by running:

no-highlight
jenkins

To store the password in the Keychain of your remote machine, it is recommended that you run match or deliver using ssh or remote desktop at least once.

Plugins

You'll find the following Jenkins plugins to be useful:

Build Step

Use the following as your build step:

no-highlight
fastlane appstore

Replace appstore with the lane you want to use.

setup_jenkins

You can use setup_jenkins action which integrates well with the Keychains and Provisioning Profiles Plugin. Selected keychain will automatically unlocked and the selected code signing identity will be used. Also all build results, like IPA files, archives, dSYMs and result bundles will be stored in the ./output folder in the job workspace. In additions setup_jenkins will create separate derived data folder for each job (in the ./derivedData).

Under the hood setup_jenkins configures other actions like: gym, scan, xcodebuild, backup_xcarchive and clear_derived_data.

commit_version_bump || git_commit

You can use commit_version_bump or git_commit action to commit changes to your repository in your fastlane setup. When you are using webhooks to trigger your build on a push this will cause an infinite loop of triggering builds.

Gitlab

When you are using Gitlab you will need the GitLab Plugin. Inside the job you want to configure you go to Build Triggers > Build when a change is pushed to GitLab > Enable [ci-skip].
When you include [ci-skip] in your build this commit won't trigger the build in jenkins at all.

Example

ruby
build_number = increment_build_number
commit_version_bump(message:"[ci-skip] Version Bump to #{build_number}")
git_commit(path:"./CHANGELOG.md", message:"[ci-skip] Updated CHANGELOG for Build #{build_number}")
push_to_git_remote

Test Results and Screenshots

To show the deployment result right in Jenkins

  • Add post-build action
  • Publish JUnit test result report
  • Test report XMLs: fastlane/report.xml

To show the generated screenshots right in Jenkins

  • Add post-build action
  • Publish HTML reports
  • HTML directory to archive: fastlane/screenshots
  • Index page: screenshots.html

Save and run. The result should look like this:

Circle Integration

To run fastlane on Circle as your CI, first create a Gemfile in the root of your project with the following content

ruby
source "https://rubygems.org"

gem "fastlane"

and run

no-highlight
gem install bundler && bundle update

This will create a Gemfile.lock, that defines all Ruby dependencies. Make sure to commit both files to version control.

Next, use the following circle.yml file

yml
machine:
  xcode:
    version: "7.3"
dependencies:
  override:
    - bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3 --without development
  cache_directories:
    - vendor/bundle
test:
  override:
    - bundle exec fastlane test

This will automatically cache the installed gems on Circle, making your CI builds much faster!

Bamboo Integration

Repository setup

In bamboo under Linked Repositories (where you configure your git repo) under Advanced Settings is an option called Exclude changesets

This dialog will allow you to enter a regular expression that if a commit matches, a build will not be triggered.

For example, if your Fastfile is configured to make a commit message in the style of

no-highlight
Build Version bump by fastlane to Version [0.3] Build [8]

Then you could use the following regex to ignore these commits

no-highlight
^.*Build Version bump by fastlane.*$

Setting repository remote

By default bamboo will do an anonymous shallow clone of the repo. This will not preserve the git remote information nor the list of tags. If you are using bamboo to create commits you may want to use a code block similar to the following:

ruby
# In prep for eventually committing a version/build bump - set the git params
sh('git config user.name "<COMMITTER USERNAME>"')
sh('git config user.email <COMITTER EMAIL>')

# Bamboo does an anonymous checkout so in order to update the build versions must set the git repo URL
git_remote_cmd = 'git remote set-url origin ' + ENV['bamboo_repository_git_repositoryUrl']
sh(git_remote_cmd)

Speeding up build times with carthage

Carthage is a wonderful dependency manager but once you are start using a large number of frameworks, things can start to slow down, especially if your CI server has to run carthage EVERY time you check in a small line of code.

One way to make build times faster is to break your work up into two separate build plans (this can get even more funky if you start having multiple branches)

The general idea is to make a build plan: Project - Artifacts that builds the Carthage directory and stores it as a shared artifact. Then you create a second build plan Project - Fastlane that pulls down the Carthage directory and runs fastlane.

Artifact Plan

Use a simple setup to create this build plan. First off you want to make sure this plan is manually triggered only - because you only need to run it whenever the Cartfile changes as opposed to after ever single commit. It could also be on a nightly build perhaps if you desire.

Stages / Jobs / Tasks

This plan consists of 1 Job, 1 Stage and 2 Tasks

  • Task 1: Source Code Checkout
  • Task 2: Script (carthage update)

Artifact definitions

Create a shared artifact with the following info:

  • Name: CarthageFolder
  • Location: (leave blank)
  • Copy Pattern: Carthage/Build/**

Optional: You may want to automatically make the fastlane plan trigger whenever this plan is built

_fastlane_ plan

When configuring fastlane to run in this setup you need to make sure that you are not calling either:

ruby
reset_git_repo(force: true)

or

ruby
ensure_git_status_clean

as these calls will either fail the build or delete the Carthage directory. Additionally you want to remove any carthage tasks from inside your Fastfile as carthage is now happening externally to the build.

Build plan setup

What this build plan does is it checks out the source code, then it downloads the entire Carthage/Build/ directory into your local project - which is exactly what would be created from carthage bootstrap and then it runs fastlane

  • Task 1: Source Code Checkout
  • Task 2: Artifact Download
  • Task 3: fastlane

GitLab CI Integration

Use GitLab CI Runner running on a macOS machine
to build using fastlane.

Repository setup

First create a Gemfile in the root of your project with the following content:

ruby
source "https://rubygems.org"

gem "fastlane"

Add a .gitlab-ci.yml file to trigger fastlane.

yml
stages:
  - unit_tests
  - test_flight

variables:
  LC_ALL: "en_US.UTF-8"
  LANG: "en_US.UTF-8"

before_script:
  - gem install bundler
  - bundle install

unit_tests:
  dependencies: []
  stage: unit_tests
  artifacts:
    paths:
      - fastlane/screenshots
      - fastlane/logs
  script:
    - fastlane tests
  tags:
    - ios

test_flight_build:
  dependencies: []
  stage: test_flight
  artifacts:
    paths:
      - fastlane/screenshots
      - fastlane/logs
  script:
    - fastlane beta
  tags:
    - ios
  only:
     - /^release-.*$/
     - master

See the ``.gitlab-ci.yml` documentation
for more information on how this file works.

Setting up the lanes

You should have a lane - in this example called beta - which should do the usual, match, gym, pilot, to distribute an updated Test Flight version, and one lane tests which calls scan to run UI Tests.

Auto-incremented build number.

To get an auto-incremented build number you can use something like the following lane:

ruby
lane :increment_build_number do
  increment_build_number(build_number: ENV['CI_BUILD_ID'])
end

Then the GitLab CI build ID (which iterates on each build) will be used.


File: docs/best-practices/keys.md

fastlane keys

This guide will show you the best ways to store and use your keys for services like Crashlytics, Slack, etc.

In your `Fastfile`

ruby
lane :beta do
  crashlytics(api_token: "123abc", build_secret: "secret_key")
end

or if you want to only define the keys once and use it multiple times

ruby
ENV["CRASHLYTICS_API_TOKEN"] = "123abc"
ENV["CRASHLYTICS_BUILD_SECRET"] = "secret_key"

lane :beta do
  crashlytics
end

This is the most straight forward and easiest solution, but might cause a few issues:

  • If you ever decide to open source your application you'll have to make sure to remove the keys from your git history
  • If your keys got invalidated for whatever reason and you decide to rollback your code base to an earlier stage the keys will also be rolled back

To get the name of the available environment variables, run fastlane action [action_name].

Bash Profile

To not store your keys in git, you can pass all parameters of all actions using environment variables.

You can edit your ~/.bash_profile to include something like

sh
export SLACK_URL="https://hooks.slack.com/services/T03NA19Q5/..."
export CRASHLYTICS_API_TOKEN="123abc"

If you use a different shell (e.g. zshell) you'll need to edit ~/.zshrc instead.

After editing the .bash_profile you need to either re-open your terminal session or run source ~/.bash_profile.

Disadvantages

  • Every terminal tool you run gets access to your environment variables.
  • You have to edit your bash profile on every computer you want to run fastlane from
  • The bash profile isn't automatically loaded by some CI-systems like Jenkins

To get the name of the available environment variables, run fastlane action [action_name].

[dotenv](https://github.com/bkeepers/dotenv)

dotenv is a system to store your environment in a file that is project specific. Basically you have a hidden file in your project containing all the environment variables for your project.

You can store a default configuration in .env.default which will be loaded by fastlane automatically.

sh
SLACK_URL="https://hooks.slack.com/services/T03NA19Q5/..."
CRASHLYTICS_API_TOKEN="123abc"

You might want different configurations depending on your environment.

no-highlight
fastlane beta --env development

and store the configuration in .env.development with all keys for the development environment.

Install [sudo] gem install dotenv or add dotenv to your Gemfile. More information about the recommend way to install gems.

To get the name of the available environment variables, run fastlane action [action_name].


File: docs/best-practices/source-control.md

Source Control

It is recommended that you keep fastlane configuration files in the repository. You may want to add the following lines to the repository's .gitignore (Git) or .hgignore (Mercurial) file to exclude generated and temporary files:

no-highlight
# fastlane specific
fastlane/report.xml

# deliver temporary files
fastlane/Preview.html

# snapshot generated screenshots
fastlane/screenshots

# scan temporary files
fastlane/test_output

It is also recommended that you avoid storing screenshots or other delivery artifacts in the repository. Instead, use fastlane to re-generate whenever needed.


File: docs/codesigning/common-issues.md

Common code signing issues

Xcode errors

Code Sign error: No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) matching the bundle identifier "X" were found.

The provisioning profile for the given app identifier "X" is not available on the local machine. Make sure you have a valid provisioning profile for the correct distribution type (App Store, Development or Ad Hoc) on the Apple Developer Portal, download and install it, and select the profile in the Xcode settings (See Setting up your Xcode Project).

You might have the provisioning profile installed locally, but miss the private key or certificate for it.

No matching codesigning identity found: No codesigning identities (i.e. certificate and private key pairs) matching "iPhone Distribution: X" were found

The code signing identity you specified in the Xcode project can't be found in your local keychain. Make sure to transfer the certificate and private key from another Mac (or wherever you store the private key), or to update the project file to use the correct code signing identity.

Error Domain=IDEDistributionErrorDomain Code=1 "The operation couldnโ€™t be completed. (IDEDistributionErrorDomain error 1.)"

This error can have a lot of reasons, some things you should try:

  • Verify your Keychain is valid and you don't have an expired WWDR certificate using this guide
  • Verify both your certificate and provisioning profile are valid in both your Keychain and on the Apple Developer Portal (Check out Debugging codesigning issues for more information)
  • If you're using gym, try using the use_legacy_build_api flag to fallback to the Xcode 6 build API
  • Follow the other steps of Debugging codesigning issues

Provisioning profile does not match bundle identifier: The provisioning profile specified in your build settings ("X") has an AppID of "Y" which does not match your bundle identifier "Z"

Your project defines a provisioning profile that doesn't match the bundle identifier of your app. There is mismatch between the bundle identifiers, this might happen if you specify the wrong provisioning profile in your target.

Your build settings specify a provisioning profile with the UUID "X", however, no such provisioning profile was found.

Your project defines a provisioning profile which doesn't exist on your local machine. Check out Setting up your Xcode Project for more information how to properly specify a provisioning profile to avoid hard coded UUIDs in your project.

CodeSign Error: code signing is required for product type 'Application'...

Make sure to have a valid code signing identity defined in your project targets. This might happen when you select Don't Code Sign as Code Signing Identity.

fastlane errors

Could not find a matching code signing identity for type 'X'

There are no certificates available on the Apple Developer Portal. This could either mean someone revoked a certificate, or you don't have access to it.


File: docs/codesigning/getting-started.md

Codesigning concepts

If you are just starting a new project, it's important to think about how you want to handle code signing. This guide will help you choose the best approach for you.

For existing projects it might make sense to switch from a manual process to the match approach to make it easier for new team-members to onboard.

If you are new to code signing, check out the WWDC session that describes the fundamentals of code signing in Xcode.

Using [match](https://fastlane.tools/match)

The concept of match is described in the codesigning guide.

With match you store your private keys and certificates in a git repo to sync them across machines. This makes it easy to onboard new team-members and set up new Mac machines. This approach is secure and uses technology you already use.

Getting started with match requires you to revoke your existing certificates.

Make sure to follow Setting up your Xcode Project to set up your project properly.

Using [cert](https://fastlane.tools/cert) and [sigh](https://fastlane.tools/sigh)

If you don't want to revoke your existing certificates, but still want an automated setup, cert and sigh are for you.

  • cert will make sure you have a valid certificate and its private key installed on the local machine
  • sigh will make sure you have a valid provisioning profile installed locally, that matches the installed certificate

Add the following lines to your Fastfile

ruby
lane :beta do
  cert
  sigh
  gym
end

Make sure to follow Setting up your Xcode Project to set up your project properly.

Using Xcode's code signing feature

Occasionally the Automatic setting as the provisioning profile doesn't work reliably as it will just select the most recently updated provisioning profile, no matter if the certificate is installed.

That's why it is recommended to specify a specific provisioning profile somehow:

Xcode 7 and lower

You should avoid clicking the Fix Issue button (There is an Xcode plugin that disables the button), as it sometimes revokes existing certificates, and with it the provisioning profiles.

Unfortunately you can't specify the name of the provisioning profile in Xcode 7. Instead you can specify the UUID of the profile, which changes every time the profile gets re-generated (e.g. when you add a new device).

To work around this issue, check out Setting up your Xcode Project on how to pass a provisioning profile to Xcode when building your app.

Xcode 8 and up

Apple improved code signing a lot with the release of Xcode 8, the following has changed:

  • No more Fix Issue button, instead all code signing processes run in the background and show the log right in Xcode
  • You can now specify the provisioning profile by name, instead of the UUID (Check out Setting up your Xcode Project for more information)
  • Improved error messages when something goes wrong. If you run into code signing errors you should always try building and signing with Xcode to get more detailed error information. (Check out Debugging codesigning issues for more information)
  • Improved Automatic Provisioning that can create per-machine development private keys, certificates, and provisioning profiles. (Check out Setting up your Xcode Project for more information)

Manually

You can always manually create and manage your certificates and provisioning profiles using the Apple Developer Portal. Make sure to store the private key (.p12) of your certificates in a safe place, as they can't be restored if you lose them.

You can always download the certificate (.cer) and provisioning profile (.mobileprovision) from the Apple Developer Portal.

Where to go from here


File: docs/codesigning/troubleshooting.md

Debugging codesigning issues

This guide will help you resolve the most common code signing errors.

Error message

Make sure to find the exact error message in your build output. Many times the error message actually tells you how to resolve the issue.

To get even more details, try archiving using Xcode 8.

Different machine

Does code signing work on a different Mac, but not on yours? If so, chances are high you don't have the latest private key, the certificate or the provisioning profile. Also follow the Keychain part of this document to make sure you don't have any expired certificates installed.

Xcode project

Make sure to follow Setting up your Xcode Project to properly set up your project.

A check list on what you should verify on your Xcode project

  1. Make sure to have consistent code signing settings across your targets
  2. Don't set any code signing settings on your project level, just on the target level
  3. Make sure the bundle identifier matches the one of your provisioning profile
  4. Make sure the code signing identity is set to iOS Distribution for Release builds
  5. Make sure to set a provisioning profile for all your targets, e.g. Watch, Today widget, ...
  6. Check your working copy in git - did you make any changes by mistake?

Developer Portal

If a certificate gets revoked, all connected provisioning profiles get invalidated. This however might not immediately show up in your local keychain.

  1. Open the Developer Portal
  • Verify your certificates are valid, and didn't expire or get revoked
  • Switch to the Provisioning Profiles and make sure the profiles you want to use are all still valid
    1. If your profile is invalid or expired, you can easily fix it:
    2. If you're using match, run match with force enabled
    • If you're using sigh, run sigh with force enabled
    • If you're doing manual code signing, edit the provisioning profile, and click on Generate on the bottom of the screen. Make sure to select the correct certificate, then download and open the new provisioning profile
    • If your profile is valid, but you still have issues make sure
      1. that the certificate matches the certificate you have installed locally. You can view the used certificate by editing the profile (Don't click Generate, unless you want to re-generate the provisioning profile)
      • that all devices you need are included (Development and Ad-Hoc only)
      • that you are actually looking at the correct provisioning profile, that matches the bundle identifier of your app. You might have multiple provisioning profiles for the same app / certificate combination. By default Xcode will use the last modified one.

Keychain

  1. Run security find-identity -v -p codesigning to get a list of locally installed code signing identities. Does yours show up?

  2. Open the Keychain Access app, switch to Certificates and find your iOS Developer or iOS Distribution entry and unfold the entry to verify the private key is locally installed:

  3. Make sure to have deleted all expired WWDR certificates, more information here. There might be 2 expired WWDR certificates, one in the login, and one in the system keychain

Have you tried turning it off and on again?

As funny as it sounds, sometimes restarting your Mac helps.

fastlane

Run fastlane in verbose mode to get even more debug information:

no-highlight
fastlane [lane] --verbose

Common Issues

Check out Common code signing issues for the most common code signing issues and how you can solve them.


File: docs/codesigning/xcode-project.md

Setting up your Xcode Project

Xcode 8 and up

With Xcode 8 you can set a provisioning profile name for each of your targets instead of a provisioning profile UUID. By doing so, Xcode automatically selects the latest provisioning profile matching its name. This way you don't have to update your Xcode project, every time you re-generate your provisioning profile (e.g. when adding a new device)

You can now specify which provisioning profile to use in the General tab after disabling Automatically manage signing.

Alternatively you can also specify the provisioning profile in the Build Settings tab.

If your provisioning profile is not listed in the drop down, there might be a few reasons:

  • It doesn't match the bundle identifier of the target
  • The associated certificate or its private key is not installed on the local machine
  • The provisioning profile is not installed on the local machine

Check out Debugging codesigning issues for more information on how to debug signing issues.

Build settings

Previously you could specify the UUID of the provisioning profile using the PROVISIONING_PROFILE Xcode settings property, with Xcode 8 you specify it using the PROVISIONING_PROFILE_SPECIFIER instead:

no-highlight
DEVELOPMENT_TEAM = N8XAAASEU2;
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.themoji.app.release";

It is recommended to select the provisioning profile in the General tab in your Xcode project, so Xcode will automatically set the values mentioned above for you.

Set using environment variable

You could pass the profile specifier via environment variables too (See Xcode 7 approach below), however in most cases it's enough to define it statically in your project, per target, since usually neither your Team ID, nor the provisioning profile change.

If you're using match the following environment variables are being set for you:

text
+---------------------+------------------------------------------------+--------------------------------------+
|                                       Installed Provisioning Profile                                        |
+---------------------+------------------------------------------------+--------------------------------------+
| Parameter           | Environment Variable                           | Value                                |
+---------------------+------------------------------------------------+--------------------------------------+
| App Identifier      |                                                | me.themoji.release                   |
| Type                |                                                | appstore                             |
| Profile UUID        | sigh_me.themoji.beta_appstore                  | 22a19b3a-7cf6-4997-95f2-9cbb4d33fe7e |
| Profile Name        | sigh_me.themoji.beta_appstore_profile-name     | match AppStore me.themoji.release    |
| Development Team ID | sigh_me.themoji.beta_appstore_team-id          | N8XAAASEU2                           |
+---------------------+------------------------------------------------+--------------------------------------+

Check out the Xcode 7 section on how to update build settings using environment variables.

Using `match development` or Xcode Automatic Provisioning

Apple's Automatic Provisioning in Xcode 8 will automatically generate a private key, development certificate, and managed development provisioning profile for each computer used to build a project. Since Xcode can auto-generate these for you, there is no need to share them between teammates' computers. As such, when using Xcode Automatic Provisioning, there is no need to use match development to keep development keys, certificates, and provisioning profiles in sync.

If you are already using match to manage development code signing, Automatic Provisioning will use the match-generated key and certificate. However, Xcode will create and manage its own provisioning profile and will not use the match-generated profile.

`match appstore` and Xcode Automatic Provisioning

Xcode Automatic Provisioning doesn't sync your private keys across machines (if you have multiple computers or share them between teammates). To securely store your private key and have access to it from all your devices, use match appstore or match adhoc. This will sync your keys, certificates and provisioning profiles via git, encrypted using OpenSSL.

Xcode 7 and lower

Note: This approach is deprecated with Xcode 8

If you use Automatic value for your provisioning profile, Xcode sometimes selects the wrong profile, resulting in code signing errors at a later point.

Instead it is recommended to specify a specific provisioning profile, which can only be done using the UUID (in Xcode 7).

Since it is not recommended to update the project file, every time you update your provisioning profile, you can pass the UUID via environment variables.

To do so, open your target settings, open the dropdown for Provisioning Profile and select Other:

Using the $(...) notation, Xcode will use the provisioning profile matching the UUID, and fallback to Automatic if it's not provided.

If you use fastlane you don't have to do any extra work, since the environment variable for the latest profile are automatically set by match

ruby
lane :beta do
  match(type: "adhoc")
  gym
end

You can also manually set the environment variable using

ruby
lane :beta do
  ENV["PROVISIONING_PROFILE_TARGET1"] = "b01c39c9-1b4a-412e-9ae2-3087ee9ea9d3"
  gym
end

File: docs/getting-started/ios/appstore-deployment.md

iOS App Store 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:

text
lane :appstore do
  gym(scheme: "MyApp")
end

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

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

Try running the lane using

no-highlight
fastlane appstore

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.

Submitting your app

Generating screenshots

To find out more about how to automatically generate screenshots for the App Store, check out fastlane screenshots for iOS and tvOS.

Upload the binary and app metadata

After building your app, it's ready to be uploaded to the App Store. If you've already followed iOS Beta deployment using fastlane, the following code might look similar already.

ruby
lane :appstore do
  snapshot                      # generate new screenshots for the App Store
  match(type: "appstore")       # see code signing guide for more information
  gym(scheme: "MyApp")          # build your app
  appstore                      # upload your app to iTunes Connect
  slack(message: "Successfully uploaded a new App Store build")
end

fastlane automatically passes on information about the generated screenshots and the binary to the appstore action of your Fastfile.

For a list of all options for each of the steps run fastlane action [action_name].

Best Practices

Push Notifications

To make sure your latest push notification certificate is still valid during your submission process, add the following at the beginning of your lane:

ruby
lane :appstore do
  pem
  # ...
end

pem will ensure your certificate is valid for at least another 2 weeks, and create a new one if it isn't.

If you don't have any push certificates already, pem will create one for you and store locally in your project's directory. To get more information about the available options run fastlane action pem.


File: docs/getting-started/ios/beta-deployment.md

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:

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

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

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

Try running the lane using

no-highlight
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:

ruby
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

no-highlight
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

ruby
lane :beta do
  # ...
  gym
  testflight
end

Some example use cases

ruby
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

no-highlight
fastlane action testflight

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


Crashlytics

ruby
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

no-highlight
fastlane action crashlytics

TODO: Also mention the other onboarding method


HockeyApp

ruby
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

no-highlight
fastlane action hockey

TestFairy

ruby
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

no-highlight
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.

ruby
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

ruby
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:

ruby
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

ruby
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](https://github.com/fastlane/boarding#readme)

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

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

no-highlight
# 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.

ruby
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:

no-highlight
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.

ruby
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.

ruby
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:

no-highlight
fastlane action [action_name]