Deploy iOS applications
On This Page
- Introduction
- Best practices
- Use Git branches
- Set the build number
- CircleCI configuration for Fastlane integration
- Set up with App Store Connect
- 1. Deploy to the App Store
- 2. Deploy to TestFlight
- Deploy to Firebase
- 1. Fastlane Plugin Setup
- 2. Generate a CLI Token
- 3. Fastlane configuration
- Deploy to Visual Studio App Center
- 1. Fastlane Plugin Setup
- 2. App Center setup
- 3. Fastlane configuration
- Upload to TestFairy
- Fastlane configuration
In this how-to guide, you will learn how to to configure Fastlane to automatically deploy iOS apps from CircleCI to a distribution service.
Introduction
Using Fastlane, CircleCI can automatically deploy iOS apps to various services. This helps remove the manual steps required to ship a beta or release version of an iOS app to its intended audience.
Deployment lanes can be combined with testing lanes so that the app is automatically deployed upon a successful build and test.
Best practices
Use Git branches
It is advisable to only run your release lane on a specific branch of your git repository, for example, a dedicated release/beta branch. This will allow releases on only successful merges into the specified branch, and prevent a release every time a push is committed during your development phase. In turn this will also reduce job completion time, as uploading to an external service may take some time depending on the size of the iOS app binary. For information on how to set up a workflow to achieve this, refer to the Branch-Level Job Execution page.
Set the build number
When uploading to a deployment service, it is important to consider the build number of the iOS app binary. Commonly this is set in the .xcproject
and has to be updated manually to ensure it is unique. If the build number is not updated before each run of the deployment lane, you may find that the receiving service rejects the binary due to a build number conflict.
Fastlane provides an increment_build_number
action which allows the build number to be modified during the lane execution. As an example, if you want to tie the build number to a particular CircleCI job, consider using the $CIRCLE_BUILD_NUM
environment variable:
increment_build_number(
build_number: "$CIRCLE_BUILD_NUM"
)
CircleCI configuration for Fastlane integration
All the examples on this page use Fastlane to configure deployment. For each example the following example .circleci/config.yml
configuration can be used to integrate your Fastlane setup with CircleCI. This is an example config which should be edited to fit the needs of your project:
FL_OUTPUT_DIR
is the artifact directory where FastLane logs, and a signed .ipa
file should be stored. Use this to set the path in the store_artifacts
step to automatically save logs and build artifacts from Fastlane.# .circleci/config.yml
version: 2.1
jobs:
build-and-test:
macos:
xcode: 14.2.0
environment:
FL_OUTPUT_DIR: output
FASTLANE_LANE: test
steps:
- checkout
- run: bundle install
- run:
name: Fastlane
command: bundle exec fastlane $FASTLANE_LANE
- store_artifacts:
path: output
- store_test_results:
path: output/scan
adhoc:
macos:
xcode: 14.2.0
environment:
FL_OUTPUT_DIR: output
FASTLANE_LANE: adhoc
steps:
- checkout
- run: bundle install
- run:
name: Fastlane
command: bundle exec fastlane $FASTLANE_LANE
- store_artifacts:
path: output
workflows:
build-test-adhoc:
jobs:
- build-and-test
- adhoc:
filters:
branches:
only: development
requires:
- build-and-test
In this example, upon pushing to a development branch, the adhoc
job enables producing a development build, or upload to Testflight.
Set up with App Store Connect
To set up Fastlane to automatically upload iOS binaries to App Store Connect and/or TestFlight, a few steps need to be followed to allow Fastlane access to your App Store Connect account.
The recommended way to set this up is to generate and use an App Store Connect API key. This prevents issues occurring with 2FA, which is now mandatory for Apple IDs, and is the most reliable way of interacting with the service.
To create an API Key, follow the steps outlined in the Apple Developer Documentation. Once you have the resulting .p8
file, make a note of the Issuer ID and Key ID which can be found on the App Store Connect API Keys page.
.p8
file and store it somewhere safe. The file cannot be downloaded again once you navigate away from the App Store Connect portal.Next, a few environment variables need to be set. In your CircleCI project, navigate to Build Settings -> Environment Variables and set the following:
APP_STORE_CONNECT_API_KEY_ISSUER_ID
to the Issuer ID- Example:
6053b7fe-68a8-4acb-89be-165aa6465141
- Example:
APP_STORE_CONNECT_API_KEY_KEY_ID
to your Key ID- Example:
D383SF739
- Example:
APP_STORE_CONNECT_API_KEY_KEY
to the contents of your.p8
file- Example:
-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHknlhdlYdLu\n-----END PRIVATE KEY-----
- Example:
.p8
file, open it in a text editor. You will need to replace each new line with \n
so that it forms one long string.Finally, Fastlane requires some information from us in order to know which Apple ID to use and which application we are targeting. The Apple ID and application bundle identifier can be set in the fastlane/Appfile
as follows:
# fastlane/Appfile
apple_id "ci@yourcompany.com"
app_identifier "com.example.HelloWorld"
If you need to use different credentials for App Store Connect and the Apple Developer Portal, check the Fastlane Appfile documentation for more details.
Once this is configured, you just need to call app_store_connect_api_key
in your lane before calling any actions that interact with App Store Connect (such as pilot
and deliver
).
1. Deploy to the App Store
The example below shows a basic lane to build, sign and upload a binary to App Store Connect. The deliver
action provided by Fastlane is a powerful tool that automates the App Store submission process.
Deliver also allows various options such as automatic uploading of metadata and screenshots (which can be generated with the snapshot
and frameit actions). For further configuration, refer to the Fastlane documentation for deliver
.
# fastlane/Fastfile
default_platform :ios
platform :ios do
before_all do
setup_circle_ci
end
desc "Upload Release to App Store"
lane :upload_release do
# Get the version number from the project and check against
# the latest build already available on App Store Connect, then
# increase the build number by 1. If no build is available
# for that version, then start at 1
increment_build_number(
build_number: app_store_build_number(
initial_build_number: 1,
version: get_version_number(xcodeproj: "HelloCircle.xcodeproj"),
live: false
) + 1,
)
# Set up Distribution code signing and build the app
match(type: "appstore")
gym(scheme: "HelloCircle")
# Upload the binary to App Store Connect
app_store_connect_api_key
deliver(
submit_for_review: false,
force: true
)
end
end
2. Deploy to TestFlight
TestFlight is Apple’s beta distribution service which is tied into App Store Connect. Fastlane provides the pilot
action to make managing TestFlight distribution simple.
The example below shows how Fastlane can be configured to automatically build, sign and upload an iOS binary. Pilot has lots of customization options to help deliver apps to TestFlight, so it is highly recommended to check out the pilot
documentation for further information.
# fastlane/Fastfile
default_platform :ios
platform :ios do
before_all do
setup_circle_ci
end
desc "Upload to Testflight"
lane :upload_testflight do
# Get the version number from the project and check against
# the latest build already available on TestFlight, then
# increase the build number by 1. If no build is available
# for that version, then start at 1
increment_build_number(
build_number: latest_testflight_build_number(
initial_build_number: 1,
version: get_version_number(xcodeproj: "HelloWorld.xcodeproj")
) + 1,
)
# Set up Distribution code signing and build the app
match(type: "appstore")
gym(scheme: "HelloWorld")
# Upload the binary to TestFlight and automatically publish
# to the configured beta testing group
app_store_connect_api_key
pilot(
distribute_external: true,
notify_external_testers: true,
groups: ["HelloWorld Beta Testers"],
changelog: "This is another new build from CircleCI!"
)
end
end
Deploy to Firebase
Firebase is a distribution service from Google. Deploying to Firebase is simplified by installing the Firebase app distribution plugin.
1. Fastlane Plugin Setup
To set up the plugin for your project, on your local machine, open your project directory in Terminal and run the following command:
fastlane add_plugin firebase_app_distribution
This will install the plugin and add the required information to fastlane/Pluginfile
and your Gemfile
.
bundle install
step.2. Generate a CLI Token
Firebase requires a token to used during authentication. To generate the token, we need to use the Firebase CLI and a browser - as CircleCI is a headless environment, we will need to generate this token locally, rather than at runtime, then add it to CircleCI as an environment variable.
- Download and install the Firebase CLI locally with the command
curl -sL https://firebase.tools | bash
. - Trigger a login by using the command
firebase login:ci
. - Complete the sign in via the browser window, then copy the token provided in the Terminal output.
- Go to your project settings in CircleCI and create a new environment variable named
FIREBASE_TOKEN
with the value of the token.
3. Fastlane configuration
The Firebase plugin requires minimal configuration to upload an iOS binary to Firebase. The main parameter is app
which will require the App ID set by Firebase. To find this, go to your project in the Firebase Console, then go to Project Settings -> General. Under Your apps, you will see the list of apps that are part of the project and their information, including the App ID (generally in the format of 1:123456789012:ios:abcd1234abcd1234567890
).
For more configuration options, see the Firebase Fastlane plugin documentation.
# Fastlane/fastfile
default_platform :ios
platform :ios do
before_all do
setup_circle_ci
end
desc "Upload to Firebase"
lane :upload_firebase do
increment_build_number(
build_number: "$CIRCLE_BUILD_NUM"
)
match(type: "adhoc")
gym(scheme: "HelloWorld")
firebase_app_distribution(
app: "1:123456789012:ios:abcd1234abcd1234567890",
release_notes: "This is a test release!"
)
end
end
To use the Firebase Fastlane plugin, the Firebase CLI must be installed as part of the job via the curl -sL https://firebase.tools | bash
command:
version: 2.1
jobs:
adhoc:
macos:
xcode: "12.5.1"
environment:
FL_OUTPUT_DIR: output
steps:
- checkout
- run: echo 'chruby ruby-2.6' >> ~/.bash_profile
- run: bundle install
- run: curl -sL https://firebase.tools | bash
- run: bundle exec fastlane upload_firebase
workflows:
adhoc-build:
jobs:
- adhoc
Note: The Firebase plugin may cause errors when run with the macOS system Ruby. It is therefore advisable to switch to a different Ruby version.
Deploy to Visual Studio App Center
Visual Studio App Center (formally HockeyApp), is a distribution service from Microsoft. App Center integration with Fastlane is enabled by installing the App Center plugin.
1. Fastlane Plugin Setup
To set up the plugin for your project, on your local machine open your project directory in Terminal and run the following command:
fastlane add_plugin appcenter
This will install the plugin and add the required information to fastlane/Pluginfile
and your Gemfile
.
Note: It is important that both of these files are checked into your git repo so that this plugin can be installed by CircleCI during the job execution via a bundle install
step.
2. App Center setup
First, the app needs to be created in VS App Center.
- Log in, or sign up, to Visual Studio App Center.
- At the top-right of the page, click on “Add New”, then select “Add New App”.
- Fill out the required information in the form as required.
Once this is complete you will need to generate an API token to allow Fastlane to upload to App Center.
- Go to the API Tokens section in Settings.
- Click on “New API Token”.
- Enter a description for the token, then set the access to “Full Access”.
- When the token is generated, make sure to copy it somewhere safe.
- Go to your project settings in CircleCI and create a new environment variable named
VS_API_TOKEN
with the value of the API Key.
3. Fastlane configuration
Below is an example of a lane that distributes beta app builds to Visual Studio App Center. Both the username of your App Center account and an API Token with “Full Access” is required to upload the binary to App Center.
# Fastlane/fastfile
default_platform :ios
platform :ios do
before_all do
setup_circle_ci
end
desc "Upload to VS App Center"
lane :upload_appcenter do
# Here we are using the CircleCI job number
# for the build number
increment_build_number(
build_number: "$CIRCLE_BUILD_NUM"
)
# Set up Adhoc code signing and build the app
match(type: "adhoc")
gym(scheme: "HelloWorld")
# Set up the required information to upload the
# app binary to VS App Center
appcenter_upload(
api_token: ENV[VS_API_TOKEN],
owner_name: "YOUR_VS_APPCENTER_USERNAME",
owner_type: "user",
app_name: "HelloWorld"
)
end
end
Upload to TestFairy
TestFairy is another popular Enterprise App distribution and testing service. Fastlane has built-in support for TestFairy, making it quick and easy to upload new builds to the service.
- On the TestFairy dashboard, navigate to the Preferences page.
- On the Preferences page, go to the API Key section and copy your API Key.
- Go to your project settings in CircleCI and create a new environment variable named
TESTFAIRY_API_KEY
with the value of the API Key
Fastlane configuration
To configure uploading to TestFairy within Fastlane, see the following example:
# Fastlane/fastfile
default_platform :ios
platform :ios do
before_all do
setup_circle_ci
end
desc "Upload to TestFairy"
lane :upload_testfairy do
# Here we are using the CircleCI job number
# for the build number
increment_build_number(
build_number: "$CIRCLE_BUILD_NUM"
)
# Set up Adhoc code signing and build the app
match(type: "adhoc")
gym(scheme: "HelloWorld")
# Set up the required information to upload the
# app binary to VS App Center
testfairy(
api_key: ENV[TESTFAIRY_API_KEY],
ipa: 'path/to/ipafile.ipa',
comment: ENV[CIRCLE_BUILD_URL]
)
end
end