The other day I wanted to create a DevOps CI / CD pipeline for a simple Xamarin.Forms app that I’d created. The Visual Studio solution contains project files for the PCL, Android, iOS, and UWP projects. The CI / CD pipeline would include VSTS for source control, build, and release, my Mac for the actual compile and packaging of the iOS app, and HockeyApp for beta version management and beta user management. It’s not that difficult to set up, but there are a few places where it would be easy to get hung up.
For my Xamarin.Forms project I created three VSTS build definitions, one for each platform. This allowed me manage the pipeline for each platform separately. Two separate build agents are required to build the solution. The Hosted Pool and Agents can build for UWP, Android, and a number of other platforms, but they can’t build for iOS. A different Pool and Agent has to be set up for iOS, pointing to a Mac environment such as MacInCloud, or to your local Mac.
The solution in Visual Studio needed three Build Configurations: one for Android (without UWP or iOS), one for UWP (without Android or iOS), and one for iOS (without Android and UWP).
VSTS Agents and Build Definitions
So with that, let’s take a look, first with the VSTS Build setup. . . (FYI, I’m currently not using Release Management to publish the app to HockeyApp. I’m going to add that process later.)
I downloaded an Agent to my Mac and configured it to run using a pool other than the Hosted pool. I chose to use default pool. In the following image you can see that I have a number of Agents defined in the “default” pool. “MIC_VSTS_snow…” is set up to use MacInCloud. The other three point to different Agent configurations on my local Macs. (I’m going to write a future post about how I configured the Agent on my Mac.)
I defined a User Capabilities variable for each Agent so my build definitions could demand which particular Agent to use from the default pool. For instance, I created a User Capability called MacinCloud for the agent associated with MacInCloud. I created a Capability called NewMac for one of the agents that lives on my MacBook Pro.
In the VSTS build definition I added a Demand for “NewMac” “exists” so it will run a particular agent on my MacBook Pro. (You can have multiple agents running on your Mac if you want to, and point to them this way.)
In my build definition I also created a variable called BuildConfiguration so I can identify which which Build Configuration in the VS solution I want the VSTS build to use. (I’ll show those settings in VS in just a bit.)
I pointed the build to my Xamarin project repo and set it to have a continuous integration trigger. In the Build Task I used the $(BuildConfiguration) variable for the Configuration.
I set up the Android and UWP VSTS build definitions similar to the iOS definition. Biggest difference was that I was able to use the Hosted agent.
Visual Studio Build Configuration
Let’s take a look at the Build Configuration in Visual Studio next.
As I mentioned I created three VS build configurations to be used by the three VSTS builds, “iOS Release”, “Android Release”, and “UWP Release”. In the VSTS build definition for iOS above, I used the “iOS Release” configuration. Here’s the definition in Visual Studio. The “XamarinFormsIosAndroid” project is the PCL project, and the “XamarinFormsIosAndroid.iOS” project is, yep, the iOS project. Notice that the Droid and UWP projects are not set to build (checkboxes are unchecked) in this configuration.
For the Android and UWP build configurations I took the same approach: build the PCL project and the .Droid or UWP project as appropriate. Here’s the screenshot for the Android build. Notice that I left the “Deploy” checkkbox unchecked for the .Droid project. There’s no need to deploy it during the Build task in VSTS.
And that’s pretty much it…. at least as far as setting up the build goes. : )
I haven’t shown it here, but you can add a step for Xamarin Test Cloud (automated testing) and a step for deployment to HockeyApp (for beta distribution and user management). Or even better, create a Release Management definition to handle the deployment to HockeyApp. More about those topics in a future blog posts.
Here are some references you’ll probably find useful when setting up your VSTS builds for Xamarin.Forms.