iOS Continuous Deployment Using Travis CI and Fastlane
In the last post, we covered how to set up a CI system to perform code validation and run tests on pull requests. This time, we'll go through step-by-step how you set up a CD system for your iOS apps. You're not required to read the first post, but do so if you want to assemble the complete CI/CD setup!
Whenever you're ready, let's launch your iOS apps to the App Store - automated using Travis CI and Fastlane!
1. Initial Travis CI setup 🔧
1.1. Activate repo in Travis CI
So I'm just going to quote the initial setup from the Travis CI docs here:
- Go to Travis-ci.com and Sign up with GitHub.
- Accept the Authorization of Travis CI. You’ll be redirected to GitHub.
- Click the green Activate button, and select the repositories you want to use with Travis CI.
1.2. GitHub access token for Travis CI
We need to provide Travis CI access to our GitHub repositories. Go to GitHub's Personal Access Token in Settings and generate a new access token. You can name it "travis" if you like. Then you need to go to the environment variables section of your repo in Travis CI. It should be under Settings. You then need to create an environment variable called
GITHUB_API_TOKEN and copy/paste the access token into it.
2. Initial Fastlane setup 🔨
2.1. Install RubyGems
If you don't have Bundler installed already on your Mac, do it by running
gem install bundler. If you don't have permissions, you need to have rbenv installed or
sudo it if you're brave.
Navigate to the directory of your project and run
bundle init. That will create a Gemfile for you. Here are the dependencies we need to install, so copy/paste this code into your newly created Gemfile:
source "https://rubygems.org" gem "fastlane" gem "xcode-install"
Now that we've specified the dependencies we need, install them by running
2.2. Create an Apple ID without 2-Factor Authentication (2FA)
To deploy your apps using Fastlane, make sure you have an Apple ID without 2FA enabled. If not, you can create a new Apple ID here. This way, Travis CI won't be required to enter a 2FA code during deployment! Fastlane does provide an alternative where 2FA is supported, but it comes with some limitations. If you're interested, you can learn about it here.
Whenever you've created the Apple ID, add it as a user in your App Store Connect, and you should be ready to continue!
2.3. Fastlane init
To get started with Fastlane, navigate to your project using the terminal and run
fastlane init and select "Manual setup" when prompted. That will create a fastlane folder as well as a Fastfile and an Appfile. Now, just open the Appfile and provide the parameters
app_identifier "com.appid.example" apple_id "email@example.com"
You should use your newly created Apple ID without 2FA as
3. Configure Fastlane match 🔏
Here's what will allow us to perform code signing from Travis CI easily! Fastlane match is a tool for generating all necessary certificates and provisioning profiles and storing them in a git repository. This way, anyone with access to the repo, such as Travis CI, will be able to fetch these credentials from the repo and perform code signing of our apps, so they can go on the App Store!
3.1. Create empty GitHub repository
This is required by Fastlane match. You can create a new GitHub repository here. Name it "ios-certificates" and make it private. That's it. Now you just let Fastlane match do the changes to it.
3.2. Fastlane match init
Open your terminal, navigate to your project and run
fastlane match init. Follow the guide by providing the URL to your empty git repo. Afterward, open the newly created Matchfile in the fastlane folder. Provide the URL to the git repo you created:
This will let Fastlane match know where to fetch the certificates and profiles from next time.
3.3. Generate profiles and certificates
You can now run the following to generate new certificates and provisioning profiles:
- First, run
fastlane match development. That should generate the certificate and profile used by our debug builds.
- Afterward, run
fastlane match appstoreto create the certificate and profile used by our release builds.
3.4. Select provisioning profiles in Xcode
The newly created certificates and profiles should now be possible to select inside our project. Open up Xcode and go to Signing & Capabilities. Here, select the appropriate provisioning profiles like this:
3.5. Fastlane environment variables
You need to create these two additional environment variables in Travis CI:
FASTLANE_PASSWORDis the password to your newly created Apple ID without 2FA.
MATCH_PASSWORDis the passphrase you created for your certificates/profiles during the Fastlane match setup.
4. Prepare pipeline ⏭
4.1. Travis CI configuration
Create a file in the root of your project and name it ".travis.yml". This is where we will define all the jobs that we want to run. Copy/paste the following code into the .travis.yml file:
# environment setup language: swift osx_image: xcode11.1 # caching of dependencies cache: bundler: true directories: - Carthage # branch safelist branches: only: - master - /^release\/.*$/ # prepare dependency managers before_install: - brew update - brew outdated carthage || brew upgrade carthage - gem install bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)" # install dependencies install: - travis_wait carthage bootstrap --platform iOS --cache-builds - bundle install # jobs and stages to run jobs: include: - stage: Deploy name: Deploy to App Store script: - echo "machine github.com login $GITHUB_API_TOKEN" >> ~/.netrc - bundle exec fastlane deploy_to_app_store if: branch =~ /^release\/.*$/
The deployment stage is what's important here. Here are the key takeaways from it:
- The deployment stage is only triggered on commits to branches that are prefixed with "release/". This means that we perform a deployment to the App Store by creating a remote branch called "release/x.x.x".
- The deployment stage contains a script that will run two commands:
- The command
echo "machine github.com login $GITHUB_API_TOKEN" >> ~/.netrcgives Travis CI access to the private GitHub repo containing the necessary certificates and profiles.
- The command
bundle exec fastlane deploy_to_app_storetriggers the lane in our Fastfile that is responsible for deploying the app to the App Store.
- The command
4.2. Branch protection
We also want our release branches to be protected so future commits into it must be submitted as pull requests. To do this, go to your project settings in GitHub and select "Branches". Here, you create a branch protection rule with the following settings:
5. Prepare deployment 🚀
5.1. Fastfile lanes
In your Fastfile, you'll need a lane for performing the deployment and one for installing certificates. You can copy/paste the following code into your Fastfile, and you should be good:
default_platform(:ios) before_all do xcversion(version: "11.1") end setup_travis def version_number if ENV["TRAVIS_BRANCH"].match?(/^release\/.*$/) return ENV["TRAVIS_BRANCH"].split("/").last else return get_version_number end end platform :ios do desc "Installs the certificates locally" private_lane :install_certificates do tmp_keychain = "temporary_keychain" create_keychain( name: tmp_keychain, password: tmp_keychain, default_keychain: true, timeout: 3600, unlock: true, ) match( type: "appstore", keychain_name: tmp_keychain, keychain_password: tmp_keychain, readonly: true ) end desc 'Deploys QCards to App Store' lane :deploy_to_app_store do install_certificates increment_version_number(version_number: version_number) increment_build_number(build_number: latest_testflight_build_number + 1) gym( scheme: "QCards", clean: true ) deliver( submit_for_review: true, reject_if_possible: true, skip_screenshots: true, skip_metadata: true, force: true ) end end
deploy_to_app_store is called from our deployment stage in travis.yml. This lane will, in turn, call the
install_certificates lane which will fetch the code signing credentials using Fastlane match and store them in a temporary keychain. Afterward, we're ready to perform the code signing, whenever we build the app as an .ipa file using
deliver will send the .ipa file to App Store Connect and submit it for review.
You need to manually prepare the app version with screenshots, release notes etc. in App Store Connect before you deploy your app with Fastlane - otherwise, Fastlane will report back that the app version wasn't found and the job will fail.
5.2. Enable Apple Generic versioning system
Since Fastlane will increment the build numbers for us, it's required that we change the versioning system to "Apple Generic". Look for versioning in the build settings and change it like this:
Now you should be all set with the setup. If you've come this far, you should be able to create a remote branch prefixed with "release/" and see the pipeline go to work. If everything is successful, you should see a screen similar to this in Travis CI.
There we go! This setup will save you a lot of time in the future. You can find the source code for the complete setup on GitHub.
Thanks for following along!