Automatically build iOS apps on different versions of Xcode using Jenkins

  • Tutorial
If you have already been approached with the question “Where can I get a fresh assembly?”, Then you perfectly understand why automation of assembly and distribution is needed. Nobody wants to spend extra time on routine work. We used to use a utility called iOSBetaBuilder ( ). This application is designed to simplify the distribution of AdHoc builds of an iOS application: you just need to enter the name and version of the project, the address (URL) where you want to put the assembly, and you get the generated index.html and manifest.plist. This is enough for the first time.

But when the project reaches the bugfixing stage, spending the extra 5 minutes on building and republishing for QA is reluctant and once. And when there are many projects, and their assemblies become longer ... Within the company, the time spent multiplied by the number of projects becomes too significant, and the time comes for automation.

In this article, we will tell you how to configure the automatic assembly of iOS applications, sending out notifications by mail and publishing the application on an FTP server for testing and demonstration to the customer.

For those who are already in the topic, there is an interesting section at the end of the article: how to configure assemblies with different versions of Xcode on the same machine.

How to set up automatic build of iOS apps using Jenkins?

You need to install Jenkins, add and configure several plugins, add an agent to build, and configure OTA distribution. If you want to receive more notifications by mail, then you need to configure an additional plugin.


What is Jenkins? Jenkins is a continuous integration server. Jenkins is written in Java and has a large number of plugins for expanding the functionality. All the necessary information for installation can be found here
To search for plugins - , but and Google also does a good job when you know what you want to find.

The architecture of our system is as follows:

  • Jenkins is installed on a machine with Ubuntu 12.04 LTS. It is used for various projects, so Xcode is installed on a separate machine. If you need to build only projects for iOS, then you can install Jenkins on a computer with Mac OS X, and you will not need to configure an additional agent.
  • Developers upload code to the repository - in our example, this is Git.
  • Jenkins starts the agent (machine with Xcode and VCS).
  • The agent downloads the code, collects the project and, if the assembly is completed successfully, uploads it to the server via FTP for distribution.
  • Jenkins sends out notifications.

To implement this system, we need the following plugins:

Plugin settings

Consider the example of building a specific application. We have a project, the source code of which is in the Git repository: ShareKit / ShareKit.git
We want to build it and put it on our internal server for distribution via the Internet. Jenkins access to the server is via FTP, Apache is configured on the server, and everything we upload becomes automatically available to our QA department or customers on a special site.

To configure the
plugin after installing it, you need to open the Jenkins settings page:
Jenkins -> Manage Jenkins -> Configure System
In the settings, find the FTP section and enter information for accessing the server.


To configure Git, you need to add a description of Git installation on the
Jenkins -> Manage Jenkins -> Configure System
The path indicates with which command Git will be launched on the agent. You must specify the full path where git is located on the machine where Xcode is installed. You may receive an error message, but do not pay attention to it, because Jenkins checks the path to Git on the local machine, and not on the remote, where we will use it.

Xcode Agent
For any Jenkins agent to work on a remote machine, you need to add credentials to access the remote machine on the settings page

Jenkins -> Manage Jenkins -> Manage Credentials
It is also necessary to add the public key of the machine on which Jenkins stands in the authorizedKeys folder of the machine on which Xcode is installed. The username in the form must match the name of the user under whose account Xcode will be launched. The path to the file with public keys in our case will be: /Users/jenkins/.ssh/authorizedKeys
In our example, Xcode is installed on the machine with the IP address
To add the agent that will be used to build the project, on the node list page
Jenkins -> Manage Jenkins -> Manage Nodes
Click on New Node, name our node XcodeAgent, select Dumb Slave, click OK.

The number of performers can be set any, depending on the power of the machine and the load. We do not have many applications, and one thread can handle it. The directory should be accessible to the user, in our case - / Users / jenkins / jenkinsCI
Specify the IP address of the machine, and select our Credentials:
After we click Save, we can proceed to create the Job.

Build Customization - New Job

Create a new task:
Jenkins -> New Job
Enter the name of the task, select the type Build a free-style software project. Click OK. In the future, to create tasks like existing ones, the best option would be "Copy existing job".

In the Source Code section, select Git, specify the address of the repository (ShareKit is shown for the example) and the Git executable that we configured earlier:
Fill in the rest of the settings:
How often
do we want to interrogate the version control system for updates - we set it to “every minute” . As you can see, Jenkins suggests using the H parameter, which means that polling will occur 1 time per hour at a random minute to reduce the load.

Add Build Action: Xcode The
configuration in the usual case is pretty simple. We use AdHoc profiles to build applications for testing and demonstration to the customer.

Add another Build Action. This time we are interested in publishing the application on our server - via FTP:

Add mail notifications

If you have a mail server, you can configure Jenkins to send emails based on the build results.
First, on the
Jenkins -> Manage Jenkins -> Configure System
settings page,
specify the email address from which users will receive letters:
Specify the SMTP server address, port and the same email.

The plugin that we installed adds another section of settings:
We can specify the format of the subject line and the template used. All templates are in the file system. Details about the templates can be found on the plugin page

In addition, the plugin allows you to specify a list of recipients and various configurations for each build status: for example, if the application has not been collected, a notification is sent to the developers, and collected to the testers. The picture in the example is for failed build and fix statuses.

После этого добавляем в нашу сборку Post-build Action:

и конфигурируем:

Save. запускаем и радуемся!

Second xcode

Everything is fine when you just started to do a project and support only the latest versions of iOS, but time passes, the world changes, and Apple releases a new iOS and a new Xcode for it. The customer asks to support what happened and what is, and the question arises about the need to edit the bugs of the old version while a new one is being developed.
Of course, we create a new brunch, hang tags and create a new address for publishing a test version. But what about Xcode?

The plugin does not support switching between versions of Xcode, so we have two (maybe someone will come up with more - but we could not) options:
  1. configure a second machine with Xcode and add an agent to Jenkins
  2. get Jenkins to switch Xcode with shell script

We went the second way.
You can change Xcode using a fairly simple script:
sudo xcode-select -switch $ XCodePathToDeveloperFolder
- you must have root privileges to switch installed Xcode.
However, when running ssh commands, you have difficulty with the password and you can get this error:
sudo: no tty present and no askpass program specified
This is because the commands on the Jenkins agent are run through ssh, which the terminal does not provide.
To solve this problem, you need to create a file, for example, / Users / jenkins / pass, in which to put the password of our user.
Нужно добавить через конвейер в скрипт по переключению Xсode команду вывода содержимого нашего файла с паролем:

cat §Users§jenkins§pass | sudo xcode-select -switch /Applications/
We add
this command in the form of the Build step - Execute shell as the first step in the Build section of our task - before Xcode.

After starting the task, the Xcode will change, and all other tasks configured for the old version of Xcode will not assemble correctly. To avoid this, you need to return the Xcode that other projects are configured to.
It would be possible to add the same command after executing Xcode, but if the assembly fails, the execution of the Build step sequence will be interrupted.
You need to add a Post-build action - Post build task, and return everything to its place:
We assemble. Everything works great.

It is worth noting that the number of executors that we specified when setting up the agent can affect the assembly if you put more than 1. Then for all assemblies you will have to add Xcode switching to the required version.