How to setup FastLane, an easy continuous integration tool for iOS

Fastlane is a collection of tools to automate building and releasing your iOS and Android apps. If you have before tried to deliver apps to TestFlight or the Apple Store, you know how long the process is: archiving the app, export it to the AppleStore, adding the new build (after an infinite processing time), adding screenshots for each device, jumping through a few more hoops and finallyyy, making it available to your tester or to the world

Fastlane puts a lot of great tools together to automate this tedious process and create a chain of commands for testing, building, archiving and publishing your apps. It also allows you to call each one of this tool independently through command line, so you have a lot of freedom in the process. The whole thing looks complicated at first but once you have done it one or 2 times it becomes very simple, and saves a lot of time.

So here is a little tutorial to get you started with Fastlane in iOS.

 

1. Installing Fastlane on Mac

First of all we are going to install and setup fastlane. Assuming you are on a mac, open the terminal and run each of the following commands:

sudo gem install fastlane --verbose
xcode-select --install //this will pop up some actions from xCode
gem cleanup

Once you have Fastlane installed, you can add different tools, depending on your needs. Here is the list of fastlane commands from github:

  • deliver: Upload screenshots, metadata, and your app to the App Store
  • supply: Upload your Android app and its metadata to Google Play
  • snapshot: Automate taking localized screenshots of your iOS app on every device
  • screengrab: Automate taking localized screenshots of your Android app on every device
  • frameit: Quickly put your screenshots into the right device frames
  • pem: Automatically generate and renew your push notification profiles
  • sigh: Because you would rather spend your time building stuff than fighting provisioning
  • produce: Create new iOS apps on iTunes Connect and Dev Portal using the command line
  • cert: Automatically create and maintain iOS code signing certificates
  • spaceship: Ruby library to access the Apple Dev Center and iTunes Connect
  • pilot: The best way to manage your TestFlight testers and builds from your terminal
  • boarding: The easiest way to invite your TestFlight beta testers
  • gym: Building your iOS apps has never been easier
  • match: Easily sync your certificates and profiles across your team using Git
  • scan: The easiest way to run tests for your iOS and Mac apps

Each of the product can be installed separately, so just have a look and install the ones you need.

In this example, we are going to install gym (which produce ipa file (build and archive))

sudo gem install gym

By the way, you can also write any custom ruby script you want and launch them in the same way through fastlane.

2. Setting up the Fastlane in your iOS project

Once you have your created your xcode project, go to its folder and run fastlane init . The script will prompt you for your apple ID/password, the app identifier, the scheme, create the app on iTunes Connect and the Apple Developer Port if necessary, and store all this information in fastlane/Appfile and fastlane/Deliverfile.

Once everything is correctly set up, you should see something like that:

fastlane_ios

Fastlane will then create a folder called `fastlane` with inside a `Fastfile`, which is the ruby configuration script. Here is an example file:

# Customise this file, documentation can be found here:
# https://github.com/fastlane/fastlane/tree/master/fastlane/docs
# All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md
# can also be listed using the `fastlane actions` command

# Change the syntax highlighting to Ruby
# All lines starting with a # are ignored when running `fastlane`

# If you want to automatically update fastlane if a new version is available:
# update_fastlane

# This is the minimum version number required.
# Update this, if you use features of a newer version
fastlane_version "1.89.0"

default_platform :ios

platform :ios do
    before_all do
        #test # to setup the proper urls, scroll down to part 3
        ENV["SLACK_URL"] ||= "https://hooks.slack.com/services/xxxxxxx"

        # URL for Project #ios channel
        #ENV["SLACK_URL"] ||= "https://hooks.slack.com/services/xxxx"
        slack(message:"New version recieved, processing started")
    end

    after_all do |lane|
        # This block is called, only if the executed lane was successful

        # slack(
        #   message: "New App Update successfully deployed."
        # )
    end

    error do |lane, exception|
        slack(
            message: exception.message,
            success: false
        )
    end

    #lane to run unit tests
    desc "[TEST] Runs all the tests"
    lane :unittest do
        scan
    end

    #lane to send app to testflight
    desc "[TESTFLIGHT] publish production"
        lane :tf_production do
        apple_testflight(scheme: "YOUR_SCHEME_NAME")
    end

    desc "[STORE] Deploy a new version"
    lane :app_store do
        # match(type: "appstore")
        # snapshot
        build(scheme:"YOUR_SCHEME_NAME")
        deliver(force: true)
        # frameit
    end

    desc "[PRIVATE] Deploy a new version to the Testflight"
    private_lane :apple_testflight do |options|

        scheme = options[:scheme]
        slack(message: "Starting processing "+scheme+" for Testflight")
        cert
        sigh
        #TODO: fix "increment_build_number" to bump ONLY the build number or the selected scheme 
        # increment_build_number
        build(scheme: scheme)
        resign(signing_identity:'#Name of the certificate as shown in the Keychain, for ex: iPhone Distribution: My COMPANY (XXXXXXXX)')
        pilot(
#            distribute_external: false,
#            testers_file_path:"./external_testers.csv"
        )
        slack(message: "Processing finished")
    end

    desc "[PRIVATE] Build usign schema"
    private_lane :build do |options|
        scheme = options[:scheme]
        cocoapods
        gym(
            scheme: scheme,
            codesigning_identity: '#Name of the certificate as shown in the Keychain, for ex: iPhone Distribution: My COMPANY (XXXXXXXX)'
        )
    end

end


# More information about multiple platforms in fastlane: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
# All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md

# fastlane reports which actions are used
# No personal data is recorded. Learn more at https://github.com/fastlane/enhancer

Inside this `Fastfile` you have different tools which you can configure. The `Before` and `after` methods are always called, while the `Error` (do) will throw exceptions in case of error.

And are going to start by defining lanes with `desc`.

Here we use Private lanes to abstract the build internally: choose scheme, send slack messages, call cocoapods to install and compile the pods, run gym to build and produce an ipa file, sign download provisionning profile with resign, etc.

As the process go through each command it populate some environment variables which are then used by the next commands. Of course it’s possible to not use private lanes and specify your build scheme manually.

You can find the name of the scheme to specify in your Fastfile in xcode `Manage schemes` at the top, the icon before the one to choose between simulator or device. In 99% of the case targets and schemes are the same, but not always (for instance having the same target with 2 schemes: release and debug), so pick them there.

The exact certificate name shouldn’t be needed if you have only one scheme (FastLane will retrieve it automatically with the commands `cert and `sigh`). In case you need to specify it, you can find the exact certificate name by opening your keychain, selecting the corresponding certificate, right clicking on it, selecting `get info` , and then copying the text in `common name`.

In the metadata folder you can update the information you want to display on the apple store. This is automatically popluated the first time from the info downloaded from the apple store. You can also produce localized screenshots automatically if you have UI testing setup, and the command `frameit` will resizes all of them for each device.

If you haven’t set up the app in itunes connect yet, run produce  to create the app in itunes connect and its provisionning profiles.

You also have to add some code in your plist file in xcode (reference here):

<key>ITSAppUsesNonExemptEncryption</key>
<false/>

Once everything is setup properly, go to your project directory via the terminal, and then run the command `fastlane`. Without anything it will asks which lane you want to run. If you already know it, just type fastlane + platform + scheme name , which would look like this:

fastlane ios tf_production

You will see the all process being displayed (connection to itunes, upload, processing). fastlane –v verbose

Remember to change the build number before running fastlane (there is a beta script doing it but you cannot specify which scheme to use, so it’s a bit useless).

A few more tips:

fastlane –help -> gives you a list of actions in fastlane

fastlane –actions -> description of each action, especially useful to understand how to properly fill the Fastfile.

fastlane –action slack -> see all the parameters for this specific action

3. How to connect Fastlane to Slack

slackYou can connect Slack and Fastlane in order to be notified through messages in a channel once the app is processing, or has been publishing, or when unit test are failing etc.

To set up the environnment variable SLACK_URL (https://hooks.slack.services) , you will need to create web hooks in slack.

Go to the slack dashboard : https://api.slack.com/incoming-webhooks, and click on `incoming webhook integration`. If you are logged in in Slack, it will bring you directly to your slack app configuration. Another way to get there is to go to `https://yourchannel.slack.com/apps/manage`, and then -> custom integration -> incoming webhooks

slack_manage

Once you are there you can create a new hooks by clicking on `add configuration` -> `select channel` (or direct message people) _> `Add incoming web hook`, which return a webhook url that you can then paste in your configuration file!

 

4. Integrating Fastlane with Bamboo

Bamboo is a continuous integration server from Atlassian, the makers of Bitbucket, JIRA, Confluence and Crowd. Bamboo, Bitbucket, and JIRA Software are fully integrated and can give you full traceability from the time a feature request is made all the way to deployment.

To integrate Fastlane with Bamboo you will need to create a build plan (a job). There, you can add a task, and choose the command line tools. There, just setup the path of your local Fastlane installation (binary file), link the task to the repo you want, add a description, and you should be good to go! Feel free to drop me a line if you need more detailed descriptions, I’ll try to make a more in depth post about Bamboo sometimes soon.