I've been banging my head into my desk quite a bit with this one, and finally found the answer (and of course, it was after all of this that I found Xamarin's page on Configuring TFS!). I set up a TFS build server to test continuous integration features of Visual Studio and Team Foundation Server (TFS) with Xamarin projects. On the server I installed TFS 2013 Express along with Visual Studio Ultimate 2013 Update 4 and the Xamarin tools. I confirmed that I was able to build the Xamarin project on that machine directly. So far so good.
I then connected to the team project from another machine and set up a build definition to the server. I had a couple of issues there that took some wrangling that I'll come back to shortly. The biggest headache was that I got this error from the builds:
C:Program Files (x86)MSBuildXamarinAndroidXamarin.Android.Common.targets (379): The Android SDK Directory could not be found. Please set via /p:AndroidSdkDirectory.
This turns out to the be the right option if you're just building locally, but there's a little more to it. First, if you're building locally and get this error, make sure that you have the appropriate API level of the Android SDK installed, because it could be that MSBuild is finding the SDK folder but not the right version.
Second, you add this switch in the build definition under Process > Build > Advanced > MSBuild arguments. The text for that field appears like the following:
Third, with TFS there's another catch: the directory must be accessible by the build agent account and not just your user account. This bit me because I'd installed Xamarin under my user account, which ended up putting the Android SDK and NDKs underneath my c:users<username>AppData and Documents folders, respectively, which were not accessible by the build agent. In other words, the TFS build failed because of an account issue, not because the SDK wasn't there.
The solution, then, was to move the SDK and NDK into folders off the c: root. In doing so, be sure to patch up the ADT_HOME, ANDROID_NDK_PATH, and PATH environment variables to point to those new locations. I verified that a local build worked on the server after this, and then was able to successfully run the TFS build and set up continuous integration (build on check-in).
It's also possible from the Team Foundation Server Administration Console > Build Configuration section to change the account for the service. This page will identify the account under which the service will run (NT AUTHORITYNETWORK SERVICE by default). I could have set this to my own account, but that wouldn't be a workable solution in a real team environment unless you created a specific build account for this purpose.
Side Note: if you're wondering whether you can do Xamarin builds with Visual Studio Online's hosted build controller, the answer is presently no. According to the Hosted Build Controller page (visualstudio.com) and the more detailed hosted build server software list, Xamarin is not included (nor is Cordova for that matter). I imagine this will change at some point, so check those pages again to be sure. For the time being, you'll need an on-premise build server like the one I'm working with. Apparently you can also connect the on-premise server to VSO, but I haven't worked that out yet.
Back to the build definition. When I first set this up, I had a couple of issues:
- The default settings for the build definition gives a warning in the Source Settings section that reads: "The build definition workspace mapping contains potential problems. This build wastes time and computer resources because your working folders include the team projects, which include a Drops folder. You chould cloak the Drops folders." After several hours of "WTF?" reactions, and having no clue about a Drops folder and cloaking which answers on StackOverflow assumed, I figured it out. In Source Settings, just add another working folder with Source Control Folder set to $/<project>/Drops, and in the leftmost Status column, select Cloaked (this was not at all discoverable!).
- Under Build Defaults, there are options for where to place the build drops. I suggest when you're first working with TFS builds to use the "Copy build output to the server" option for simplicity. In this case, builds will go into the folder you have set up in the TFS Admin Console > Build Configuration > <server> – Agent > Properties. By default this is set to $(SystemDrive)Builds$(BuildAgentId)$(BuildDefinitionPath).
- If you want to place the builds on a different server/share (e.g. for distribution to testers who side-load the app), then make sure the build machine has full access/control for that share, otherwise you'll see "Access to the path is denied" errors. On the other server, right-click the shared folder, select Properties > Sharing > Advanced Sharing > Permissions. In that dialog, click Add…, and in that dialog click Object Types then check Computers. This way you can enter your <domain><build machine name>, and have it recognized. You have to do it by machine name because the NETWORK SERVICE applies only locally. (See this question on ServerFault.)
There you have it–my learnings from the past few days. I hope this helps some of you avoid similar headaches!