ICYSTT: Command Line Tool Trouble after Xamarin Cycle 7 Upgrade
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
...
** EXPORT FAILED **
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.