Continous integration with Xamarin, TeamCity and FAKE – Part 2

In the previous post I talked about setting up your environment with different build configurations so you can easily switch between an alpha, beta or production iOS/Android build.

This time I’ll talk about creating a build script which you can use with your CI implementation.

Our weapon of choice? FAKE.

“FAKE – F# Make” is a build automation system with capabilities which are similar to make and rake. It is using an easy domain-specific language (DSL) so that you can start using it without learning F#. If you need more than the default functionality you can either write F# or simply reference .NET assemblies.

Little note: there’s actually a similar project in C# called CAKE but it hasn’t the complete functionality we need at the moment (HockeyApp integration is one of the missing parts).

Our build script will have several targets.

Targets are the main unit of work in a “FAKE – F# Make” script. Targets have a name and an action (given as a code block).

We’ll cover the Android setup here, but you should be able to easily set this up for iOS yourself.
The targets of the Android project are:

  • “restore-packages-project”
  • “restore-xamarin-components-android”
  • “android-build”
  • “android-package”
  • “android-hockeyapp” (will be discussed in a future post)

Each target in the list has a dependency on the target above it.
If you execute the android-build target, it will automagically run restore-xamarin-components-android and restore-packages-project.

How do we define this dependency in FAKE?

==> “restore-xamarin-components-android”
==> “android-build”
==> “android-package”

Place this at the bottom of your script.
Now let’s create each target.

Target "restore-packages-project" (fun _ ->
     String.Format("../solutions/{0}.sln", projectName)
     |> RestoreMSSolutionPackages (fun p ->
         { p with
             OutputPath = "../solutions/packages"
             Retries = 4 })

This target will restore all NuGet packages in the given solution.
As you can see the project name is defined in a variable which allows for reuse on different projects.

Target "restore-xamarin-components-android" (fun _ ->
    Shell.Exec "mono" ("tools/xamarin-component.exe restore" + android_solution)

If you don’t use Xamarin Components, you can delete this step.
If you do need this, you will first need to download the xamarin-component.exe. The link provided will download a XPKG file. Change the extension to a ZIP-file and extract the contents.

Place this file somewhere where your script can access it and provide the correct path to it in the script.

Remark: You will need to run the .exe one time manually on the build server because it will ask for your Xamarin credentials. You only need to do this once.

Target "android-build" (fun () ->
    CleanDirs [buildFolder + "/android/"]

    let buildProperties = 
            [("Configuration", buildConf); ("Platform", "Any CPU"); ("VersionCode", buildcounter); ("VersionName", releaseversion)]

    MSBuild (android_buildFolder) "Rebuild" buildProperties [android_solution] |> ignore

This target will do the actual compiling of the project.
It first cleans the directories and then starts the compiling with the correct parameters.

The projectBuildConfiguration variable will contain our alpha, beta or production build configuration from the previous post.
The buildcounter variable is the incrementing value used when new versions are released and the releaseVersion variable is the semantic version number.

That’s it. How do we trigger this FAKE script?
We’ve used a Bash script:


while getopts :t:p:r:c:b:n: FLAG; do
  case $FLAG in
      # SEMVER

nuget install FAKE -Version 4.6.2 -OutputDirectory packages -ExcludeVersion
mono packages/FAKE/tools/Fake.exe build.fsx $TARGET release=$RELEASE counter=$COUNTER buildconf=$BUILDCONF projectName=$PROJECTNAME

This Bash script will download the F# FAKE Nuget Package and call our script with the correct parameters.
You can completely test this script on your local machine before integrating it into your CI process.


As you can see in the screenshot above, there are some extra steps of compiling a common solution (which contains PCL libraries to share between Android and iOS) and some unit tests steps which were out of the scope of this blog post.

Happy integrating!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s