Black Friday Sale - Save on EverythingAll videos. All books. Now 50% off.

Build your mobile development skills and save! Stay ahead of the rest with an Ultimate book & video subscription. Starting at just $149/year for Black Friday.

Home iOS & Swift Tutorials

Xcode Server for iOS: Getting Started

In this tutorial, you’ll learn how to install and configure Xcode Server so you can use it for Continuous Integration.

5/5 7 Ratings

Version

  • Swift 5, iOS 14, Xcode 12

No matter if you’re part of a large team of iOS engineers or a solo indie developer, Continuous Integration (CI) can make your development workflow rapid and consistent, allowing you to spend more time on the thing you really love — writing beautiful code. In this tutorial, you’ll learn all about how to do this with Xcode Server.

In the real world, if you need to maintain a consistent approach to building something, you almost always rely on some form of automation. If you’re producing a batch of cakes, for example, and you want to maintain the same consistent taste and texture, it’s likely there will be some kind of automation involved to make sure that the same recipe and the same cooking techniques are used every time to produce the same consistent and delicious cake.

Continuous Integration (CI for short) is the name given to this approach in software development. It’s a way to automate running builds of your iOS apps over and over as you’re developing your code. Usually you run the builds on a dedicated CI server, which might be a physical machine or could be a shared machine in the cloud. The CI server will build your app and run tests each time you commit code. That way, you will instantly know when something is broken and be able to fix it straight away.

Continuous Integration comes in many flavors (just like those delicious cakes mentioned above), and in this tutorial you’re going to explore Apple’s cloud-based Xcode Server. You will learn how to:

  • Set up Xcode Server
  • Set up your first Bot
  • Run Integrations on every commit
  • Run your tests suite in Integrations

Time to get those Bots working!

Swifty Mascot in science lab

Getting Started

For this tutorial, you’ll be working with Fruits, a very simple SwiftUI app listing fruits because the world clearly needs more fruit-listing apps :]

Note: The sample project is available for download as with any raywenderlich.com tutorial. However, when working with Xcode Server, you need to have your project stored under source control, because this is where Xcode Server will fetch your code from when building.

Therefore, feel free to download the sample project using the Download Materials button at the top or button of this tutorial to browse the code, but the first step in this tutorial is to fork an already existing repository to get your own code under source control.

This tutorial also assumes that you know how to make commits to a Git repository. If you would like to get up to speed with Git then head over to our beginner Git tutorial.

To get Xcode Server running, you need to have the project under source control so start by setting this up. In this tutorial, you’re going to use GitHub but feel free to use your preference — the logic remains the same.

Note: If you don’t already have a GitHub account, create one for free at GitHub.com. Be sure to verify your email so you can create new repositories.

Forking the Repository

In GitHub, a fork is your own copy of a repository. You can make changes to a fork without affecting the original. You are going to create a fork of Fruits so you can make a few changes.

Log in to GitHub, then visit the Fruits repository and click the Fork button at the top right.

Once you have Fruits forked, you will clone it to your local workstation. Click the green Code button, then click the clipboard icon to add the URL to your clipboard.

Next, open Terminal and type the following commands, substituting the URL for your repository:

# 1
mkdir ~/Fruits
# 2
cd ~/Fruits
# 3
git clone [The-Repository-URL-You-Just-Copied-Here] .

These commands:

  1. Create a directory in the root of your home directory to hold your code.
  2. Switch to the new directory.
  3. Clone the repository into the new directory. Watch out for the ending space and period because both are needed.

You now have a copy of the code in your local workspace.

Next, open Fruits.xcodeproj and build and run.

Fruits app running

Congratulations, you now have a local version of Fruits ready for automation!

Setting Up Xcode Server

There are two parts to getting Xcode Server completely up and running.

  1. Enabling the server.
  2. Configuring the Integration, which is done through an Xcode Bot.

This tutorial will get you set up with a local Xcode Server, but in the real world, you’ll likely want to host this somewhere other than your own personal computer. For example, you might want to have a Mac Mini that you can share across the team, or you could choose a cloud-based setup.

Don’t panic though: Once you have the local version, it’s very easy to migrate to a hosted solution.

Enabling Xcode Server

Before you begin, you must enable Xcode Server inside Xcode.

Click Xcode then Preferences.

Select preferences

Click Server & Bots.


Select Server & Bots

At the top right, toggle Xcode Server to the on position


Enable Xcode Server

Xcode now presents a pop-up to choose which user will act as the Integration User.

Select user

If you are installing Xcode Server on a dedicated CI/build server, it’s recommended to use a brand new User for this. Because you are running Xcode Server on your local machine in this article, you’ll use your existing user account, so select your own user account in the drop-down menu.

Xcode now installs various tools required to run a local version of Xcode Server. This can take awhile, so this is a good time for a peak behind the curtain.

Seeing How Xcode Server Works

While you wait, it’s time to cover some theory behind Xcode Server and what’s happening under the hood.

Right now, Xcode Server is currently running on your local machine. Behind the scenes, it’s created a special set of services to run the Xcode Server. You can see these for yourself. Let’s go ahead and do that right now.

Open Terminal and run the following command:

open /Applications/Xcode.app/Contents/Developer/usr/share/xcs

This is all the components of Xcode Server running locally on your machine. This is the whole setup generated when you turned on Xcode Server from within Xcode. The best part is that this is all available to customize to your heart’s content. You can make changes as you wish, including to all the dashboards, to suit your needs.

Files installed by Xcode Server

Xcode Server is using nginx, Redis, Node.js, and CouchDB to name just a few. Who would’ve thought Xcode had Node.js bundled in?

Creating a New Server

Now that you have Xcode Server enabled, it’s time to create a new instance.

Click Xcode, then Xcode Preferences

Select preferences

Click Accounts.

Select plus at bottom

If you have linked your Apple Developer account before you should see your Apple ID; don’t worry too much if you don’t see this.

Click the + icon to create a new account.


Select Xcode server

Click Xcode Server and then Next.

You now see a list of available servers on your machine. Unless you have another machine hooked up, you should just see the one machine (your own).

Select your server machine and then click Next.

You are prompted to log in with the User you used when setting up the server (your own user account). Enter the credentials and click Add.

You have now created a local version of Xcode Server running on your machine with your own user account.

Note: As mentioned before, this might be fine if you’re an indie developer but consider moving this to a cloud-based solution or a shared Mac Mini that everyone on the team can access if required.

If you do consider using a cloud-based solution, the well-known one in the industry is MacStadium, which provides a paid solution to hosting macOS in the cloud.

Carrying on with our cake-making analogy, you now have the equipment to make your cakes a consistent taste and texture. Yet what’s really important is the detail, the recipe, and the exact cooking temperature.

You can relate to this in software development, in which you want to make sure you run the exact same scripts every time so you know that a failure is genuine and not an environmental problem. It also means the build is cut the same way every time, just like your cake :]

Adding a New Bot

Xcode Server includes a concept called the Xcode Bot. Ultimately, below the surface, it’s a separate Scheme that has some configurations that you’re going to define. The biggest difference is an Xcode Bot is for running Integrations on your Xcode Server.

Time to create your first Xcode Bot!

Select Product ► Create Bot….

Select create bot

Give your Xcode Bot a unique name (this is usually the “Product Name” + “Bot”).

Give your bot a name

Click the Server drop-down menu and select your newly created Server.

Click next

Click Next.

Repositories

At this point, Xcode asks for the source control details for your new bot. Now, the outcome here will depend on how you have used Xcode in the past. If you have previously linked your GitHub account, this will be easy. However, if you have not logged in before, click Sign In….

Select sign in

You should enter the GitHub credentials you created earlier or, if you are using SSH, navigate to the location of your SSH keys (typically stored in ~/.ssh).

This gives Xcode Bot permissions to clone the repository.

As previously mentioned, it’s down to the Bot to have full control over how and what it executes on your project. It’s what carries all the information required to cookie-cut your iOS builds.

Click Next.

Setting the Configuration

You should now see the build configuration screen. Here is what each of the options on this screen mean:

  • Scheme: The scheme inside the project that the Bot will execute. You’ll keep this as Fruits.
  • Actions: Here you can specify what actions are run on each integration.
    • Analyze: Runs the clang static analyzer on the code.
    • Test: Runs the unit tests and UI tests. You can optionally specify if code coverage is on and what language and region to run the tests in.
    • Archive: Make an archive of the app. Export defines if you would like to export the app as an IPA or not, with various options to choose from.
  • Configuration: Which configuration of your build to use. For example you might force it to be in the Debug configuration. Usually you would opt for Use Scheme Setting here.

Populate the fields to match the screenshot below:

Build configuration for bot

Note: You’re going to disable Test and the export product for now but more on this will follow shortly. :]

Click Next.

Setting the Schedule

It’s now time to set the schedule for the Integration, you can select from:

  • Periodically: Runs the integration at a set time either Hourly/Daily or Weekly.
  • On Commit: The Bot checks GitHub regularly for new commits to kick off the integration.
  • Manually: You’ll have to trigger a build by a manual process.

Select On Commit, because you’d like the Bot to run every time a developer pushes up a change to the repository.

You can allow your Xcode Bot to run your integration following an Xcode Upgrade, so keep this option ticked for now.

Finally, change the Clean option to Always. This means that a clean will be run before starting the build of the app. This is always recommended so that you have a clean slate for the build to avoid any issues that might arise (or be masked) by builds being different if there are previous build artifacts.

Options for integrations setup

Click Next.

Selecting Devices

It’s now time to decide what type of device the Bot should be configured to build for. This app only supports iOS which is why the first drop-down is set to iOS and grayed out (there’s no other option!). However, you can select whether to build for devices, simulators or both. For this tutorial, choose iOS Simulators since you only want to check for now that it builds successfully, and the simulator will do for that.

Options for Select devices

Click Next.

Signing

It’s time for the dreaded Provisioning Profile and Certificate joys! Fortunately, you don’t need to do much here so simply click Next.

Options for Signing and provisioning

Defining Environment Variables and Build Options

On this screen, you can define custom flags to pass to xcodebuild and custom environment variables to set while your Bot builds the app. In this tutorial, you won’t need to set anything here.

Options for environment variables

Skip this part by clicking Next.

Adding Triggers

The final item is custom triggers. These is essentially build phases but for your Bot. There are many possibilities here such as adding a post-hook to trigger a Slack notification when a build has completed. You won’t set up any triggers in this article so simply click Create.

Options for triggers

Congratulations, you now have an Xcode Bot running on your Xcode Server! It’s now ready to “do its thing” whenever a new commit is made to the repository. That raises a question: Just what exactly is its thing? The answer is Integrations.

Integrations

In CI terms, an Integration is a name given to a single run. In Xcode Server terms, this will be when the Xcode Bot meets the requirements that you set when creating the bot. Recall that you specified to trigger an integration when there is a commit to the GitHub repository.

So if your Xcode Bot has run 12 integrations, it means you have built the project 12 times.

Creating your First Integration

With that in mind, it’s time to continue with the tutorial and get the first integration triggered!

Open the Report navigator in Xcode.

Click Report navigator

You might already be familiar with this panel, but essentially it displays the latest reports of builds, the running of test targets, and also now your integrations from the Xcode Server.

Click your Xcode Bot.

Select your bot

This screen shows some statistics for the Xcode Bot. You can see here a history of builds and tests, along with the stats such as the total number of integrations run and the success rate. Once you start running your Xcode Bot more regularly, this screen will fill with lots of useful data which you can use to see how your builds are performing.

Expand the Fruits Bot row in the Report navigator.

Now click on the row that was revealed, i.e. Integrate (1).

Select Integration 1

This is the screen that shows you all the information for a specific integration. It will tell you if the integration is in progress or finished. It will also tell you if there were any warnings, errors, analysis failures or test failures.

If the integration is still processing then you can:

  • Cancel Integration. This stops the integration and marks it as “Canceled”.
  • View Screen. This allows you to screen share with the machine to watch the build in progress. This is super useful if the machine is shared across the team.

Due to your configuration, you also specified you wanted an archive, which is visible underneath the “Build Results” heading.

Archive shown on integration

You’re going to deep dive further into this display and what it means, but for now: Congratulations! You’ve just got your Xcode Bot running your first successful integration!

Running Unit Tests and UI Tests

A good use case for Continuous Integration is unit tests and UI tests. Every time you check in new code, the CI server will kick in and execute your test suite. If you made an error and tests are failing, you’ll know right there and then that your recent changes broke something, allowing you to fix it while you still have the scenario fresh in your memory.

Xcode Server has full support for this and can provide additional information like code coverage.

In the project Fruits, you have some basic unit and UI tests that you’re going to get your Xcode Bot to execute for you.

Click Edit Bot on the Integration screen.

Click Edit bot button

Click Configuration, check the Test box and make sure Code Coverage is set to Enabled

Enable tests

Also you’re going to ensure that the tests run on both an iPhone simulator and an iPad simulator because you want to test both device classes.

Select the Devices tab and then select Specific iOS Devices and Simulators. Select an iPhone and an iPad simulator from the list.


Select specific devices

Click Done, and then click Integrate to start a new integration.

Click on integrate button

Using your new changes, the integration will build your project and run your unit and UI tests across iPhone/iPad.

Pulling Out Build Reports

Xcode Server will generate build reports and these are called Integration Reports. This means you can interrogate each integration and pull out specific build reports relating to the integration.

Select your newly minted integration which will be called Integrate (2).

Select recent run integration

If the build is still progressing then you will be able to see the progress from the integration screen. Sit and wait while it finishes — you may want to make yourself a cup of tea because it can take quite a long time to run all the tests!

When it’s finished you might notice that you have just encountered your first failing integration. Try not to panic, because this is quite normal. In fact, once you get this fully operational, this will be great for you to spot issues before your app is ready for the store. So, what went wrong?

Expand Integrate (2) in the Report navigator.

Ingegration 2 expanded

Now within the integration, you should see Tests, Coverage, Commits and Logs. You can really start digging into the details for this particular integration, and this is very useful when something goes wrong.

Inspecting Failed Tests

You should be able to see quickly that one test failed. Click Tests.

Failed tests expanded

You can see a list of all the unit tests alongside the UI tests, and you can see one of the UI tests has failed, but only on iPad. You’re probably thinking (especially because it’s failing only on the iPad): “Is it something to do with device size?”

Click the disclosure triangle next to the iPad device.

Failed tests for iPad Pro

Now, expand the Assertion Failure and hover on the Automatic Screenshot then click the “eye” icon (you might be familiar with this icon for QuickView on macOS).

Screenshot of failed tests

XCUITesting has a built-in screenshot capture and in true Apple style, it’s displayed directly here within your Xcode Bot (how cool is that!). As you can see, the list of Fruits is empty, which explains why this UI test has failed.

Fixing the Error

You are going to make a code change to Fruits to get this failing UI test succeeding again.

Open ContentView.swift and replace body with the following:

var body: some View {
  NavigationView {
    List(viewModel.fruits) { fruit in
      FruitRow(fruit: fruit)
    }
    .onAppear {
      viewModel.loadFruits()
    }
    .navigationBarTitle("Fruits")
  }.navigationViewStyle(StackNavigationViewStyle())
}

In SwiftUI, when running on iPad, the default style of NavigationView will be a SplitView. You can disable this by setting the NavigationViewStyle to a StackNavigationViewStyle as is done in the last line.

Running the Integration Again

OK, that was an easy fix. But how do you tell the Bot that things have changed?

Remember that the Xcode Server works with code in the repository you created in the beginning of this tutorial. So you need to make a commit, which Xcode Server will then pick up on and run an integration as usual.

So make a commit now with your new and improved code. You can do this via Xcode, on the command line or in whatever git GUI you normally use.

Then go back to your Report navigator and run your Bot again by clicking on Fruits Bot in the Report navigator an then Integrate.

Integration running again

All your XCUITests now pass, and the integration was successful! Congratulations — you have successfully set up an Xcode Bot and run your first few integrations on your shiny new CI system!

Where to Go From Here?

Well done! You learned how to set up and use Xcode Server to automate testing and analyzing your code.

You’ve only scratched the surface on Xcode Server, and there are many different things you can do such as:

  • Adding custom Build Scripts.
  • Adding support for hooks so you can post messages to Slack when builds complete or fail.

So go ahead and explore :]

Remember, CI is always about cookie-cutting the same builds every time. So sit back and think about all the manual tasks required to get your iOS app to the App Store and see if you can get them automated.

To learn more about Xcode Server, check this WWDC video from Apple showcasing the latest changes to Xcode Server.

For alternatives to Xcode Server, see this screencast. Or, check out our tutorial Continuous Integration With GitHub, Fastlane & Jenkins.

Thank you for reading along! If you have any questions or comments, don’t hesitate to leave them below.

Average Rating

5/5

Add a rating for this content

7 ratings

More like this

Contributors

Comments