Series 3: Continuous Integration using Fastlane and Travis CI

What is Travis CI?
Why do you need Travis CI?

Just a summary, Travis CI is a distributed continuous integration service that can be used to build and test projects that hosted at GitHub. (If you are using other code hosting service like Gitlab, Travis CI will not work for you.)

This post mainly focus on technical process on how to integration Travis CI into iOS project, if you want to find out more what Travis CI does, you can read here.

Travis CI is very useful especially if you are working in a team. Travis CI automatically detects commit changes that had been pushed to GitHub repo, respective action will be triggered base on your travis configuration.

More importantly you can use the distributed cloud service that help you to build and deploy your In-House QA build and TestFlight build without using your local machine.

This tutorial will go through with you step by step how to integrate Travis CI easily by reuse the Fastlane integration that you learnt in the previous series.

If you have not gone through the previous tutorial series, you can checkout:

Please ensure that you have setup your Travis account with your Github account. You can find more details here.

Series 3: Continuous Integration using Fastlane and Travis CI

Step 1: Create travis.yml file in root folder.

Open Terminal (under root folder of the project):

touch .travis.yml
open .travis.yml

.travis.yml is the configuration file that Travis CI used to determine and execute the command. The .travis.yml file will contain information like which branches will trigger travis execution, what language is used, customisation of the virtual machine etc. You can find out more here.

Step 2: Define basic configurations.

In .travis.yml

language: objective-c
osx_image: xcode11.3
branches:
only:
- dev-build
before_install:
- bundle install

What it does:
1. Define the language.
2. Define the Xcode version.
3. Define the branches which the commit message will trigger the travis execution.
4. Before the actions that you would want to perform before the travis execution.
Some example of executions in before_install

  • bundle install is used by Fastlane to ensure necessary components like plugins install etc.
  • pod install is used if you used pods library in the project.

Step 3: Create a new Github SSH key in order to allow Travis access.

This step is the same as Series 1 — Section 1 — Step 1 & 2.

a: Generate new SSH key
- Open Terminal:

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"> Enter a file in which to save the key (/Users/you/.ssh/id_rsa): [Press enter]

/Users/{{you}}/Desktop/travis_ci_rsa
// Do not enter any passphrase for this

> Enter passphrase (empty for no passphrase): [Type a passphrase]
> Enter same passphrase again: [Type passphrase again]

Remember: Do not enter any passphrase for this key.

b: Add newly generated key to Github
- Copy SSH key:

pbcopy < ~/Desktop/travis_ci_rsa.pub

Go to GitHub, paste in the SSH key.

Step 4: Create the auto deployment secrets script.

This step is similar to Series 2 — Step 2.
The main different is this secret is used by Travis, (since travis is a virtual machine, you can imagine it is a new local machine that you going to setup for deployment.)

Open Terminal (under root folder of the project):

Before we create .autodeployment.sh, ensure that we add .autodeployment.sh in .gitignore file so that secret is not committed to the repo.

touch .autodeployment.sh
open .autodeployment.sh

paste in the information below

#!/bin/bash
echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
echo -e "{{travis_ci_rsa.pub file content}}" > ~/.ssh/id_rsa.pub
echo -e "{{travis_ci_rsa file content}}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa*
eval `ssh-agent -s`
ssh-add ~/.ssh/id_rsa
export FASTLANE_USER='{{apple_id}}'
export FASTLANE_PASSWORD='{{apple_id_password}}'
export MATCH_PASSWORD='{{match_repository_password}}'
export APP_CENTER_API_TOKEN='{{app_center_api_token}}'
export FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD='{{apple_application_specific_password}}'
echo "Travis Environment variables set"

What it does and what you need to do: (Important)

1. Execute pbcopy < ~/Desktop/travis_ci_rsa.pub to copy the Github ssh public key you generated in Step 3 and replace {{travis_ci_rsa.pub file content}}.

2. Execute pbcopy < ~/Desktop/travis_ci_rsa to copy the Github ssh private key.
When you copy the private key, since the private key is multi-line, remember to replace all the new line with \n so that the echo -e can recognize the string. Remember to include the -----BEGIN OPENSSH PRIVATE KEY----- and -----END OPENSSH PRIVATE KEY-----.
Hint: You can select the new line and use control + command + G to find all newline word.
Replace {{travis_ci_rsa.pub file content}} with the copied key.

3. Replace {{apple_id}}with the Apple ID that is used to connect to App Store Connect to FASTLANE_USER which is used to create the TestFlight build, incase you have multiple apple id for in-house and app store distribution.

4. Replace {{apple_id_password}} with the Apple ID’s password.

5. Replace {{match_repository_password}} with the match passphrase you used in Series 1 — Section 5 — Step 2.

6. Replace {{app_center_api_token}} with the token you generated in Series 2 — Step 3.

7. Replace {{apple_application_specific_password}} with the password you generated in Series 2 — Step 4.

Step 5: Create GitHub Access Token for 2 Factor Authentication Enabled (2FA) account.

If you have enabled 2 Factor Authentication (2FA) on Github, you will need to generate a personal access token in order to ensure that you can login to travis.

Go here and click Generate new token. Enable the scope by refer to below.

Remember to copy the token.

Step 6: Use Travis to encrypt the .autodeployment.sh .

This step is similar to the encryption that you use in Series 2 — Step 5. The main different is that we will not use a passphrase to encrypt the file, we will let Travis to encrypt the .autodeployment.sh for us.

Copy the Github personal access token:

Open Terminal (under root folder of the project):

travis login --pro --github-token {{github_personal_access_token}}

> Successfully logged in as 💁!

You should be able to see that you are login successfully.

Run the command below

travis encrypt-file .autodeployment.sh --add

Travis will automatically generate a random key used to encrypt and decrypt the .autodeployment.sh file and stored it as environment variable . Once the encryption is done, You will see a newly created encrypted file .autodeployment.sh.enc is created. You can commit the file to the repo.

Reminder: Every time you modify the .autodeployment.sh file, you must ensure that you encrypt the file again.

After the encryption is done, you will be prompted to allow the modification on the .travis.yml file.

You should be able to see something like below is added in the.travis.yml file.

- openssl aes-256-cbc -K $encrypted_abcdefg_key -iv $encrypted_abcdefg_iv-in .autodeployment.sh.enc -out .autodeployment.sh -d

Add two more lines to the .travis.yml file under before_install: to ensure that the deployment secrets are set as environment variables before Travis execute the script.

- chmod +x .autodeployment.sh
- . ./.autodeployment.sh

Reminder: No line break is allowed because it should be a series of steps in bash.

Commit the .travis.yml file changes to the repo.

Step 7: Create a lanes for to create In House QA build and submit to App Center using Travis.

Add a new lanes into Fastfile.

Information needed:
a. Replace {{enterprise_configuration_bundle_id}} with the bundle id.
b.Replace {{apple_id_of_the_app}} with the apple_id. You can find the apple_id by login to App Store Connect and under your App Information you should be able to find the Apple ID.

What the lane does:
1. Retrieve the version number and build number from the project.
2. Creating a new Keychain in Travis Virtual Machine.
The reason of creating a new keychain is to avoid the interactive prompt during the build phase.

3. Fetching provisioning profiles for enterprise from default keychain. (A keychain access confirmation prompt will show when we execute the lane).
4
. Archiving the iOS build with enterprise configuration and respective scheme.
5. Upload the build to App Center. (The detail on the params you can find here.)
5. Delete the keychain once submission done.

The lane is very similar to the lanes you create in Series 2 — Step 8. The main different is the access to the keychain.

Important: You should never run this lane in your local machine because it will delete your default keychain.

Step 8: Create a new lane to create TestFlight build and submit to App Store by using Travis.

Since we have different configurations for In-House and TestFlight build, we should create a new lane to deploy Testflight build to ensure that the Fastlane is able handle it properly.

Add a new lanes into Fastfile.

Information needed:
a. Replace {{app_store_configuration_bundle_id}} with the bundle id.
b.Replace {{apple_id_of_the_app}} with the apple_id. You can find the apple_id by login to App Store Connect and under your App Information you should be able to find the Apple ID.

What the lane does:
1. Retrieve the version number and build number from the project.
2. Creating a new Keychain in Travis Virtual Machine.
3. Fetching provisioning profiles for appstore from default keychain. (A keychain access confirmation prompt will show when we execute the lane).
4
. Archiving the iOS build with App Store configuration and respective scheme.
5. Upload the build to TestFlight. (The detail on the params you can find here.)
6. Delete the keychain once the build is uploaded.

The lane is very similar to the lanes you create in Series 2 — Step 9. The main different is the access to the keychain.

Important: You should never run this lane in your local machine because it will delete your default keychain.

Step 10: Add these two lanes into .travis.yml under script: .

In .travis.yml , add

- fastlane travis_inhouse
- fastlane travis_appstore

Hint: If your build normally take up more than 30 minutes, its always recommend add travis_wait to ensure that Travis will not kill your build if there is no output log during the build.

Now your .travis.yml should now look something like this:

What the .travis.yml does:
1. Define the language used for travis.
2. Define Xcode version. (Use the latest version especially if your code depends on swift version which only available in certain Xcode Version).
3. Define the branch that will trigger the execution of Travis upon commit.
4. Define the action that need to be performed before the execution of the script.
- Decrypt the .autodeployment.sh.enc to .autodeployment.sh .
- Make the script executable.
- Execute the .autodeployment.sh script to set the deployment secret as the environment variable in Travis machine.
- Install fastlane bundle (plugin etc.)
- Install specific cocoapods version.
- Execute pod install and repo update to ensure dependencies is setup.
- Execute travis_inhouse to create In-House QA build with a timeout of 90 minutes.
- Execute travis_appstore to create TestFlight build with a timeout of 90 minutes.

Step 11: Trigger Travis CI job.

Before you can trigger your job. you need to ensure that all the necessary files is committed and pushed to the Github remote repo.

Travis Job will be triggered once you push a commit to the branch that you defined in the .travis.yml (eg. dev-build) to the Github remote repo.

Awesome! Now Travis will be doing all the job for you!

jasonchan91 - iOS Engineer who passionate in UX/UI Design. http://jasonchan91.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store