Setting Up A Continuous Build Environment For Xamarin: Part 1 - Jenkins

Continuous integration is the core foundation of the DevOps lifecycle, as it allows tests to be run and builds to be created every time a member of the development team checks in new code. This allows the team to quickly know if the latest changes have ‘broken the build’ and depending on how the continuous integration is configured, for that check in or commit to be rejected (essentially allowing the team to pre-emptively avoid major issues from ever making it into the build).

Setting up a continuous integration environment for Xamarin is a non-trivial task because of the number of dependencies that Xamarin requires to build packages (a lot of this is thanks to Apple’s requirements that you can only build iOS apps on a Mac). So in this 2 part tutorial series, I’ll walk through configuring two different continuous integration solutions for Xamarin. Part 1 will be built using a combination of Jenkins (for Xamarin.iOS and Xamarin.Android) and a hosted TFS build controller (for Windows/Windows Phone). Part 2 will be built using the new ‘Build.vNext’ tools that are included Visual Studio Online and the newly released Team Foundation Server 2015.

Sample Solution

To give you a sample solution to work with for building these continuous integration environments, I’ve taken the TaskyPortable solution from the Xamarin Samples GitHub account, made some modifications and uploaded it to my GitHub account. So you just need to download this solution and check it in/commit it to your VSO or TFS Team Projects in order to use it.

I’ve also created a sample Java Keystore file that you can use alongside the sample solution. Java Keystore files are used for building Xamarin.Android projects. Don’t use this sample Java Keystore in production apps.

Pre-requisites & Out of Scope Topics

Due to the complexity of this topic, there are some pre-requisites that I’m going to assume you already have knowledge about and already have installed and configured properly on your machine.

  • You have the latest version of Xamarin already installed and configured on your Windows and Mac machines. This includes all of the Xamarin pre-requisites that are included in the Xamarin installer (Java, MDK Framework, GTK# and Android SDK).
  • On your Mac, you have the latest version of Xcode installed.
  • You have Visual Studio 2013 or 2015 installed on your Windows machine. The awesome thing about Visual Studio 2015 is that it can install Xamarin and all of it’s pre-requisites as part of the installation if you choose to do so (highly recommended). If you’re setting up a new Xamarin development environment, it makes sense to use Visual Studio 2015.
  • You have the latest Android SDK components installed. If you installed Xamarin, you can open the Android SDK Manager by either opening Visual Studio and choosing Tools -> Android -> Android SDK Manager or by opening Xamarin Studio and choosing Tools -> Android SDK Manager. The SDK Manager will tell you if there are updates available to the components you have installed.
  • You have a Xamarin solution that currently builds into a deployable app on the machine you want to turn into your build server. This means you’ve got your Provisioning Profiles and Development Certificates correctly configured for your Xamarin.iOS apps and your Java Keystore file created for your Xamarin.Android apps (or you’re using the sample solution, the sample Java Keystore file). For iOS apps, this means you’ll need to be a part of the Apple Developer Program.
  • You already have either a Visual Studio Online (VSO) account or a server running Team Foundation Server (TFS) 2015. You also have Administrator access to that account/server to make the configuration changes required.
  • For Part 1, you need a Team Project with the Team Foundation Version Control (TFVC) source control option chosen. For Part 2, you need a Team Project with the Git source control option chosen (hopefully in the future, Part 2 will also work with TFVC Team Projects too).
  • If you’re going to use Visual Studio Online, the Jenkins server you’re creating needs to be accessible from the internet. If you’re using your own internal Team Foundation Server, the Jenkins server just needs to be accessible from that TFS server.
  • This tutorial isn’t a tutorial on how to use Visual Studio Online or Team Foundation server as a source code repository. I assume you already know how to check in code and connect Visual Studio to VSO/TFS.
  • Although testing is a critical part of continuous integration, this tutorial series doesn’t cover this particular topic. I do plan to write a follow up tutorial at some point that will add testing to the continuous integration environment that you’ll be creating in this tutorial series.

Before you start, I’d just like to recommend this article from Xamarin’s developer website. Some of the content included in this tutorial is based on this particular page.

Finally, this tutorial series has been written as an accompaniment to a talk I did at the Queensland C# Mobile Developers user group in Brisbane, Queensland, Australia in July 2015. You can watch the video from that talk here (apologies for the lack of screen capture, that didn’t save correctly this time).

Jenkins & XAML Build Definitions

The first method for creating a continuous build environment for Xamarin.iOS and Xamarin.Android projects involves using a server called Jenkins. This will run on your Mac OS X machine and will download the source code for your solution and then run the appropriate commands to build the app packages for each platform. For Windows/Windows Phone projects, you’ll use a Team Foundation Build server on a Windows machine to run the commands needed to build the app package.

The setup of the Jenkins server breaks into 3 different parts. Firstly, you configure install and configure Jenkins (which also involves a small configuration change to VSO/TFS to allow Jenkins to connect). Secondly, you create jobs within Jenkins that retrieve source code and then build Xamarin.iOS and Xamarin.Android projects from that source code. Finally, you then configure VSO/TFS Service Hooks Subscriptions to allow VSO/TFS to alert Jenkins that new code has been checked in and to start a build.

Installing & Configuring Jenkins

Before you install Jenkins, you need to download and configure a few pre-requisites. The first is called Team Explorer Everywhere, it’s a command line utility that is used to interact with a VSO/TFS server on a non-Windows machine (on Windows you tend to interact with a VSO/TFS server using the Visual Studio GUI). Team Explorer Everywhere also includes an Eclipse plugin too that gives you a very similar GUI to Team Explorer in Visual Studio.

1.       Download Team Explorer Everywhere 2015 from here: http://www.microsoft.com/en-us/download/details.aspx?id=47727

There are 3 zip files that you can download from that page. The zip file you’re looking for is the one with CLC in the filename, this is the Team Explorer Everywhere Command-Line Client (CLC). I recommend creating a folder called TEE inside of the Developer folder on your Macintosh HD partition and extracting the contents of the zip into that folder.

2.       Open an OS X Terminal and type cd /Developer/TEE (or wherever you decided to extract Team Explorer Everywhere to) and press enter to switch to the TEE folder.

3.       Now type tf eula and press enter. Follow the instructions on screen to accept the Team Explorer Everywhere End User Licence Agreement.

You’ll also need to place your Java Keystore file into a folder where it can be easily accessed by Jenkins. Remember you can download the sample Java Keystore file for this tutorial if you don’t have one, but you’ll need to create your own for a production environment.

4.       Take the Java Keystore file you use for signing your Android packages and place it into a folder called BuildAssets that you’ll create inside the Developer folder on your Macintosh HD partition.

Jenkins is a Java web application that comes in a .war file that you can run from the command line or from within other products like Apache Tomcat. However, it’s easier to download an app called Jenkins.app which you copy into your Applications folder, like most other applications on your Mac. You can then just put it on the Dock and launch it.

5.       Download Jenkins.app from here: https://github.com/stisti/jenkins-app

6.       Drag Jenkins.app into your Applications folder (just like you normally would with most Mac OS X applications) and then launch it. You can keep it pinned to your Dock for easy access if you want.

7.       When Jenkins.app launches, for the first time, it will let you know it’s about to download Jenkins.war. Click OK and then wait until this download has completed. There will be no visual on-screen indication while this is happening.

8.       Each time you start Jenkins.app you’ll get asked if you want to customise Jenkins startup. Just click on ‘Use Defaults’ as you don’t need to add any startup parameters to Jenkins for this tutorial.

Now that Jenkins is installed, it’s time to configure it so that you can start to create jobs for your Xamarin.iOS and Xamarin.Android projects. This will broadly consist of installing some plugins into Jenkins, setting some Jenkins system settings and enabling the Jenkins Security system.

9.       Launch your browser and navigate to http://localhost:8080/. By default, Jenkins runs on port 8080. Navigating to this URL will bring up the Jenkins home page.

10.   Click on ‘Manage Jenkins’ that is located to the left of the home page. Then click on ‘Manage Plugins’.

11.   In the Plugin Manager click on the Available tab and then tick the boxes for the following plugins and then click ‘Install without Restart’:

a.       Environmental Injector Plugin – This plugin lets you set environment variables within Jenkins. These allow you to set key-pair values that you can define once and then use throughout every job you create. They’re very useful for defining paths to shared tools.

b.       MSBuild Plugin – This plugin lets Jenkins build .sln and .csproj files using Mono’s implementation of MSBuild (which is called XBuild)

c.       Team Foundation Server Plugin – This lets Jenkins communicate with TFVC Team Projects that are on VSO/TFS . Out of the box Jenkins supports CVS and Subversion, but plugins such as this one allow it to support many source control systems (there’s also plugins for Git and GitHub etc.)

12.   Next, return to the ‘Manage Jenkins’ page and click on ‘Configure System’.

13.   On the ‘Configure System’ you’re going to configure a number of items including the Team Foundation Server plugin, the MSBuild plugin and set some environment variables. Click Save once everything has been configured correctly.

a.       Under Global Properties, tick the Environment Variables option and then add the following key-value pairs that will be used in your Xamarin.Android job (Note: these are the values you’ll need if you’re build the sample solution supplied. In a production environment these values would be changed to match the solution being built, the tools installed and the Keystore being used):

i.      KEYSTORE_FILE: /Developer/BuildAssets/SampleKeystore.jks

ii.      KEYSTORE_ALIAS: Demo

iii.      INPUT_APK: $WORKSPACE/TaskyAndroid/bin/Release/com.andrewtechhelp.samples.taskyportableci.apk

iv.      SIGNED_APK: $WORKSPACE/TaskyAndroid/bin/Release/ com.andrewtechhelp.samples.taskyportableci-Signed.apk

v.      FINAL_APK: $WORKSPACE/TaskyAndroid/bin/Release/com.andrewtechhelp.samples.taskyportableci-Final.apk

vi.      ANDROID_SDK: /Users/yourusername/Library/Developer/Xamarin/android-sdk-macosx

vii.      ANDROID_BUILD_TOOLS_VERSION: 22.0.1

b.       Under MSBuild, add an MSBuild installation:

i.      Name the installation: Xamarin MSBuild

 ii.      Set the Path to MSBuild to: /usr/bin/xbuild

(Jenkins may complain about this path because it is actually an alias to the real location of XBuild, but this location works and is what Xamarin recommends to use)

c.       Under Team Foundation Server, set the TF command line executable to: /Developer/TEE/tf

14.   Return to the ‘Manage Jenkins’ page and this time click ‘Configure Global Security’.

15.   Tick the ‘Enable Security’ option to display the rest of the page. Under Security Realm choose the “Jenkins’ own user database” option. Under Authorization, choose the ‘Matrix-based security’ option and click Save. Now close the browser so that you can trigger the login page to appear next time you visit.

16.   Open the browser back up and navigate back to http://localhost:8080 and then click on the ‘Create an account’ link. Create an account called “admin”.

17.   Now return to the ‘Configure Global Security’ page. Untick the option to ‘Allow users to sign up’.

18.   In the table beneath the ‘Matrix-based security’ option you selected earlier, add the ‘admin’ user if it isn’t already there (type “admin” into the ‘User/group to add’ textbox and click Add) and tick every single box for that user. Then click Save.

19.   On the ‘Manage Jenkins’ page, choose ‘Manage Users’ and then click ‘Create User’ on the left hand panel. Create a user with the username “remotebuild”. You can set the other details to whatever you want, although the password should be a fairly secure one.

20.   Return to the Configure Global Security screen and add the new ‘remotebuild’ user to the matrix. For this user tick the following options:

a.       Under Overall tick Read

b.       Under Job tick Build and Read

21.   Finally Click Save. Jenkins is now configured correctly. You can now create jobs to build Xamarin.iOS and Xamarin.Android projects.

Configuring Visual Studio Online Authentication

This small section only applies if you’re using Visual Studio Online. For the Team Foundation Server plugin in Jenkins to be able to connect to Visual Studio Online, you’ll need to enable Alternative Credentials because this plugin doesn’t support the OAuth protocol that allows you to log onto Visual Studio Online using your Microsoft Account. An on-premises Team Foundation Server uses IIS’ authentication instead.

1.       Log into Visual Studio Online and then click your name in the top right hand corner and choose My Profile

2.       Next, choose the Security tab and then the ‘Alternative authentication credentials’ item from the left panel.

3.       Tick the ‘Enable alternative authentication credentials’ option and then enter a secondary username and password into the appropriate fields. Then click Save.

Creating A Xamarin.iOS Job Using Jenkins

Now that you’ve successfully configured Jenkins (and Visual Studio Online if applicable), you can now add jobs to Jenkins, so that it will actually build your projects. First up you’ll build a Xamarin.iOS project.

Successfully building a Xamarin.iOS project using Jenkins involves getting the latest code from VSO/TFS via the Team Foundation Server plugin and then executing the shell command ‘mdtool’ to build the project and generate the .ipa file.

1.       In Jenkins, click on the ‘New Item’ on the left. Select ‘Freestyle Project’ and give your job a name. Then Click OK.

2.       In the ‘Source Code Management’ section, select ‘Team Foundation Server’ and enter in the following details

a.       Server URL: This is the URL of your Team Foundation Server. If you’re using Visual Studio Online, this URL is in the following format: https://myvsoaccountname.visualstudio.com/DefaultCollection (where myvsoaccountname is the name of your account)

b.       Project Path: This goes in the format of $/nameofyourteamproject/folderofyoursolutionfile. So if your Team Project was called XamarinCITalk and your solution file was in a folder called TaskyPortable, your path would be $/XamarinCITalk/TaskyPortable.

c.       Login Name: This is the email address of the Microsoft Account you use to log into your Visual Studio Online account (not the username you set in alternative credentials). If you’re using an on-premises TFS server, this is the domain and username you use to log into that server (in the format domain\username)

d.       Password: This is the password you assigned earlier as alternative credentials (or your regular password for an on-premises TFS server).

3.       Under ‘Build Triggers;, tick the ‘Trigger Builds Remotely’ option and then set the authentication token to whatever value you want (the more secure the better). This will be used later on as one of the forms of authentication required to set up your automated build using Service Hooks.

4. In the Build Section, add an ‘Execute Shell’ build step. Type the following command into the command box:

/Applications/Xamarin\ Studio.app/Contents/MacOS/mdtool -v build "--configuration:Release|iPhone" ./TaskyPortable.sln

If you’re using the sample solution, replace Release with Release_iOS.

5.       Now click Save to save your Xamarin.iOS job. Next you’ll add a job for a Xamarin.Android project.

Creating A Xamarin.Android Job using Jenkins

Creating a job for a Xamarin.Android project is very similar to the job you just created for the Xamarin.iOS project.

Successfully building a Xamarin.Android project using Jenkins involves getting the latest code from VSO/TFS via the Team Foundation Server plugin, running MSBuild to build the Android project into an .apk package, then signing that .apk package with your Java Keystore and finally running the zipalign command over the signed .apk package so that it will run properly on Android devices.

1.       In Jenkins, click on the ‘New Item’ on the left. Select ‘Freestyle Project; and give your job a name. Then Click OK.

2.       In the ‘Source Code Management’ section, select ‘Team Foundation Server’ and enter in the following details

a.       Server URL: This is the URL of your Team Foundation Server. If you’re using Visual Studio Online, this URL is in the following format: https://myvsoaccountname.visualstudio.com/DefaultCollection (where myvsoaccountname is the name of your account)

b.       Project Path: This goes in the format of $/nameofyourteamproject/folderofyoursolutionfile. So if your Team Project was called XamarinCITalk and your solution file was in a folder called TaskyPortable, your path would be $/XamarinCITalk/TaskyPortable.

c.       Login Name: This is the email address of the Microsoft Account you use to log into your Visual Studio Online account (not the username you set in alternative credentials). If you’re using an on-premises TFS server, this is the domain and username you use to log into that server (in the format domain\username)

d.       Password: This is the password you assigned earlier as alternative credentials (or your regular password for an on-premises TFS server).

3.       Under ‘Build Triggers’, tick the ‘Trigger Builds Remotely’ option and then set the authentication token to whatever value you want (the more secure the better). This will be used later on as one of the forms of authentication required to set up your automated build using Service Hooks.

4.       In the ‘Build Environment’ section, tick the ‘Inject passwords to the build as environment variables’ option. Click the Add button beside ‘Job Passwords’ and add the following two values:

a.       Name: STORE_PASS. Password: enter the password for your Keystore file.
If you’re using the Sample Keystore, the password is: Demo123

b.       Name: ALIAS_PASS. Password: enter the password for your the Alias you’re using in that Keystore.
If you’re using the Sample Keystore, the password is also: Demo123

Finally tick the ‘Mask Password Parameters’ option.

5.       In the Build section, add a ‘Build a Visual Studio Project or Solution Using MSBuild’ build step.

6.       For the MSBuild Version, select ‘Xamarin MSBuild’ from the drop down.

7.       For the ‘MSBuild Build File’ input field, type the path to the project file for your Xamarin.Android project. As this is normally in a subfolder relative to your solution file, the path will probably look something like this: ./TaskyAndroid/TaskyAndroid.csproj (that path is the one to use for the sample solution)

8.       For the ‘Command Line Arguments’ enter: /p:Configuration=Release /t:PackageForAndroid

If you’re using the sample solution, replace Release with Release_Android.

9.       Add another build step, this time the ‘Execute Shell’ build step.

10.   For the command to execute enter the following two lines (each bullet point is a new line):

  • jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore $KEYSTORE_FILE -storepass $STORE_PASS -keypass $ALIAS_PASS -signedjar "$SIGNED_APK" "$INPUT_APK" $KEYSTORE_ALIAS
  • $ANDROID_SDK/build-tools/$ANDROID_BUILD_TOOLS_VERSION/zipalign -f -v 4 "$SIGNED_APK" "$FINAL_APK"

11.   Now click Save.

Configure Jenkins To Continuously Build With VSO/TFS Using Service Hooks

Jenkins lacks the ability to know every time you check in to VSO/TFS. It can poll for changes every x number of minutes and build if it detects changes, but it lacks the ability to know to build immediately after each check in. Thankfully Visual Studio Online & Team Foundation Server 2015 have a feature called Service Hooks that allows you to integrate VSO/TFS with dozens of 3rd party products, one of them being Jenkins.

Essentially, every time you check in a change, VSO/TFS will log in using an account supplied (which is why you have setup an account called ‘remotebuild’ with extremely limited access rights) and send a build trigger for an appropriate job.

1.       Log into your Jenkins server and go to the ‘Manage Jenkins’ page. Then click on ‘Manage User’, followed by the ‘remotebuild’ account and then finally Configure on the left panel. On this page, click on the ‘Show API Token...’ button and copy the API Token that is displayed. It will be required in a few steps.

2.       Next, log into VSO/TFS and click on the Team Project you want to build. Then click on the Settings icon in the top right hand corner and go to the Service Hooks tab.

3.       Click on the green plus button to create a new Service Hooks Subscription.

4.       On the Service page of the ‘New Service Hooks Subscription’ wizard, click Jenkins and then click Next.

5.    On the Trigger page, in the ‘Trigger on this type of event’ dropdown, choose ‘Code checked in’ and then in the ‘Under path’ text box, type the path of where to watch where code is checked in. Unless you use branches, you can probably leave this as the default. Then click Next.

6.    On the Action page enter the following settings:

a.       Jenkins base URL: This is the IP address of your Jenkins server

b.       Build token: Enter in the build token that you’ve set for the job you selected.

c.       Build: If everything has been configured correctly, this dropdown should contain all of the jobs you’ve created on your Jenkins server. Select job you want to build.

d.       User API token (or password):  Paste in the API token that you collected back in step 1.

e.       User name: remotebuild

7.    Then click Finish and your Service Hooks Subscription will be created. Whenever you check new code in now, the Jenkins server is notified and a new build will be started. You’ll need to create another Service Hooks Subscription for the other jobs you also want building continuously.

You can test that this all works correctly by checking in a small change to your Xamarin solution and seeing if your Xamarin.iOS and Xamarin.Android projects build successfully. If they fail, log into Jenkins, click on the job, pick the latest build from the left panel and click on ‘Console Output’. This will allow you to diagnose what went wrong. You can retrieve the app packages by clicking on a job in Jenkins, clicking Workspace on the left panel and then navigating down into the project folder and then the ‘bin’ folder to find the appropriate .ipa or .apk file.

Creating a Windows/Windows Phone Build Definition

For time and cost purposes, I didn’t want to set up a local Team Foundation Build server for this tutorial series, so I used the hosted build controller built into Visual Studio Online for my Windows/Windows Phone project because it has everything installed on it to build Windows/Windows Phone projects. However, the build definition created here can be used for Windows/Windows Phone projects that are being built using an on-premises Team Foundation Build server as long as that server has the appropriate Windows/Windows Phone SDK installed on it.

This is using the older XAML build definition system, part two of this tutorial series will describe the new ‘Build.vNext’ system built into Visual Studio Online and Team Foundation Server 2015, that does away with these older XAML build definitions and can be configured completely online.

1.       To create a XAML build definition, you need to do this in Visual Studio. So open Visual Studio and in the Team Explorer panel, go to the Builds page. Then under the ‘Build Definitions’ section (‘XAML Build Definitions’ in Visual Studio 2015), click on ‘New Build Definition’.

2.       On the General page, give your build definition a name by entering it into the ‘Build definition name’ input field. You can also give your build definition a description if you want. Finally, just make sure that ‘Queue processing’ is set to Enabled, so that this build will be triggered.

3.       Now switch to the Trigger page (the pages are listed on the left). Select the ‘Continuous Integration – Build each check-in’ option. This will mean your Windows Phone project will be built automatically each time new code is checked in to VSO/TFS.

4.       Next, on the ‘Source Settings’ page, remove all of the items from the ‘Working folders’ list (you can right click them and delete them).

5.       Now add a new item to the list with the following details:

a.       Status: Active

b.       Source Control Folder: Set this to the folder where your solution file is located. Click the ellipsis (...) that appears in the ‘Source Control Folder’ column to browse to the correct path rather than having to type it in.

c.       Build Agent Folder: $(SourceDir)

6.       On the ‘Build Defaults’ page, select ‘Hosted Build Controller’ as the Build Controller. If you have an appropriately configured on-premises Team Foundation Build server listed in this dropdown, you can select that instead.

7.       Under ‘Staging Location’, select the ‘Copy build output to the server’ option. This will copy all of the items that get placed in the ‘bin’ folder back up to VSO/TFS as build artefacts (which is great because you don’t need to sift through the build server to find your app package).

8.       On the Process page, set the following values:

a.       In the Required section expand the ‘Items to Build’ row.

i.      For ‘Projects to Build’, set this to the path to your Solution file. You can use the ellipsis (...) to browse to this path instead of typing it.

ii.      For ‘Configurations to Build’, use the ellipsis(...) to bring up the Configurations dialog. Set the Configuration to Release and the Platform to ARM and click OK.

If you’re using the sample solution, replace Release with Release_WinPhone.

b.       In the Basic section, set the ‘Clean Workspace’ option to Outputs. This just cleans out the ‘bin’ folder each time a build occurs so that there’s nothing left in there from previous builds.

c.       In the Advanced section, set the ‘MSBuild Platform’ to X86. This is important because otherwise your Windows/Windows Phone project will fail to build.

9.       Finally, click Save to save this build definition. From now on, whenever new code is checked in, your Windows/Windows Phone project will be built and the .xap or .appx package will be uploaded to VSO/TFS for retrieval.

You can test that this all works correctly by checking in a small change to your Xamarin solution and seeing if your Windows/Windows Phone project builds successfully. If it fails, you can click on the build definition that is listed in the Team Explorer panel in Visual Studio (or the Build tab of VSO/TFS) and see the log there to diagnose what went wrong.

Summary

This brings Part 1 of this tutorial series to a close. Hopefully you’ve been able to follow along and now have a Jenkins server that can automatically build you Xamarin.iOS and Xamarin.Android packages and a TFS Build server that can build you Windows/Windows Phone packages.

Part 2 will cover the new ‘Build.vNext’ tools that are included in Visual Studio Online and Team Foundation Server 2015. There are a number of benefits that these newer tools bring over using the Jenkins server (these benefits will be discussed in Part 2).

If you have any questions or feedback about this topic, leave your comments below. :)