ICYSTT: In Case You See This Too

Humor me. I'm trying this acronym as a way of signaling the content of posts where I struggle through a problem and come out the other side with some findings.

Thanks to my teammate Ryan O. for piling onto this problem to help.

The Problem

Recently, some of the command-line build scripts for an iOS project starting failing. Specifically, the build steps around archiving the project. Of course, the problem only showed up after updating some of the tools on the machine.

Here's what was updated:

  • OS X -> 10.11 (El Capitan)
  • Xcode -> 7.3.1
  • Xamarin Release Cycle 7
    • Xamarin Studio 6, etc.

In this particular build pipeline, FAKE is the build system of choice. The bundled XamarinHelper adds an easy iOSArchive task that generates a command something like this:

mdtool -v archive "-c:Release|iPhone" -p:YourApp.iOS your_solution.sln

Ordinarily, this command builds the project, then generates an .xcarchive.

Enter problem #1:

mdtool archive doesn't work

Oh no! Is mdtool deprecated?

Well, not really as Xamarin's Mikayla points out. However, more and more we're being pointed toward xbuild or msbuild since mdtool is just an interface into those other systems.

So, while mdtool may not be officially deprecated, the archive command broke as of Xamarin Studio 6 as commented on here and hinted at over here. Previously, the archive command would first build the iOS project, then archive. No longer the case as of this write-up. Maybe Xamarin will patch things up in a future release?

Squirrel Alert!

Before I get to the fix, I want to warn you about a squirrel we chased. Once realizing that the mdtool archive command had changed -- and therefore the FAKE iOSArchive task -- we tried running the FAKE iOSBuild task immediately before the iOSArchive task to make sure a build happens.

The build happened and an archive was created, but the build still failed. There are additional steps in my build pipeline that export the archive as an .ipa. This one-two punch of iOSBuild and iOSArchive ultimately generated a bad archive. Turns out, if your achive is bad, you won't be able to export and may see errors such as:

xcodebuild: WARNING: -exportArchive without -exportOptionsPlist is deprecated

We chased that squirrel before realizing that the generated archive was simply bad. Although, duly noted, the export step needs to change.

You can anecdotally recognize a bad archive by viewing the Xcode Archive Organizer, selecting an archive from the list, and verifying that the Export, Validate, and Submit buttons are grayed out.

The fix for problem #1:

This post was the most helpful.

Down the page a bit, a Xamarin employee suggests using an xbuild command explicitly:

xbuild /p:Configuration=Release /p:Platform=iPhone /p:ArchiveOnBuild=true /t:"Build" MyProject.csproj

He goes on to explain how the ArchiveOnBuild property works. Not entirely familiar with xbuild, I whittled the suggestion down to a simpler:

xbuild /p:Configuration=Release /p:ArchiveOnBuild=true /t:"Build" MyProject.csproj

The Platform property wasn't described, so because I didn't want to include something I wasn't sure of, I removed that bit.

Enter problem #2:

The project builds, but no archive is generated

Well, running that command certainly built the app, but no .xcarchive was generated, and my app didn't show up in the Xcode Archive Organizer.

The fix for problem #2:

You guessed it -- Platform was necessary. Putting that property back fixed the script:

xbuild /p:Configuration=Release /p:Platform=iPhone /p:ArchiveOnBuild=true /t:"Build" MyProject.csproj

The Platform property is the platform target (e.g.- iPhone, iPhoneSimulator, x86, etc.)

Executing this command built the project, and generated an archive, but the archive wasn't listed under my iOS Apps in Xcode Archive Organizer.

Enter problem #3:

Archive shows up in Xcode Archive Organizer under Other Items instead of under iOS Apps.

If you read the entire post from the problem #1 fix, you already know what's going on. If you jump down to this comment you'll see that the CFBundleVersion must be present and populated in the archive's Info.plist.

The fix for problem #3:

This isn't necessarily a big problem if your application's Info.plist is correct. Your app will still export correctly and be able to be submitted to the App Store. However, this comment provides a suggestion that works perfectly.

/usr/libexec/PlistBuddy -c "Add :ApplicationProperties:CFBundleVersion string "your build number here"" path/to/archive.xcarchive/Info.plist

Adding that command to your build pipeline will ensure that the archive files correctly under the iOS Apps section of the Xcode Archive Organizer.

That's it! Build scripts work again. The community did a great job helping with the various fixes, but I wanted to compile everything into a single how-to. Maybe it will save someone else some time.

I'd love your feedback. Let me know if this helped you or if you ran into different kinds of problems.