Avatar photo

I Just Wanted to Make a Universal Binary for our iOS Library

We’re hard at work on many things here at keen. Perhaps the most important, however, is our iOS client library. We’re really interested in building a powerful and flexible client library to consume the APIs we’re exposing to customers. Obviously, decreasing battery drain and bandwidth usage is essential. And maybe I’ll even write about how we’re solving these problems later. But for now, I’d like to focus on how insanely difficult it is to distribute a client library to other iOS developers.

I mean, it’s not so hard to just point people to our GitHub repo (still private for now but will totally be open sourced soon). We can throw up some instructions and people can get started by either downloading the source, cloning the repo, or submoduling it. It sort of sucks to pollute your project with all that code, though, especially since the code I’m writing is NOT using ARC yet, since I know that a lot of developers who will be integrating with us will be on legacy code that hasn’t been ported yet, and it’s pretty crazy to have to set compiler flags for every class that isn’t ARC-ified.

So I figured it’d be awesome to distribute a compiled static library (and corresponding public headers). Simple to drag into your project, no headache, easy to use, etc. I also figured that this wouldn’t be that hard. HA HA HA HA laughs Present-Me at Past-Me.

I ran into a couple problems. First, some of the code I’m using (JSONKit is awesome) creates categories on a couple of the standard foundation objects. I found that when I used my static library, those categories weren’t available at runtime, and my app was crashing and burning with the wonderful “Invalid Selector” error we all know and love. Luckily, this problem was pretty easy to solve with some google / stack overflow-fu. All credit goes to this Stack Overflow post. Briefly, a linker flag needs to be set to tell the linker to go through all the classes in the static library to look for Objective-C classes and categories. Here’s a small screenshot.

Second, and most painful, I found out that the static library I used with my sample app worked in the simulator, but not on the device itself. It makes 100% sense in hindsight. When you compile for the simulator, you’re really compiling for an i386 architecture. And iPhones and iPads use an ARM processor, so a single universal binary is unlikely. Except that normally we developers don’t have to think about this, at all. It’s not like we’re submitting two versions of the app to the appstore, one for devices and one for simulators. It’s actually because xcode automates sending the binary off now, and the binary sent to Apple is almost certainly device-only, but still. Arg.

Okay, so I knew other people had to have solved this problem. More googling and more stack overflowing later, and I came across this excellent post. The gist is that us developers have to create two different targets, one for the simulator and one for the device. Then we create a third target that runs a custom script that invokes a command line utility called “lipo” (and wow, when you google “man lipo” looking for the manpages for lipo, you get someunexpected results). lipo builds universal binaries. Sweet.

The writeup above is great and completely solved my issue. You should read through it. The only thing I’ll say is that, of course, Apple’s changed some naming conventions since April 2011, and I had to work through that. Here’swhat the contents of my script look like.

So, great, problem solved. In the end, not a huge deal to overcome. But it’s completely non-obvious that this is a problem in the first place, and then there’s nothing in the official Apple docs (that I could find) to show how to solve the problem once you know there is one. Normally, I love Apple’s documentation and the really powerful tools they provide, but not this time. Luckily, the iOS developer community is amazing, and we can rely on their expertise when Apple fails to deliver an awesome developer experience.

Maybe the most important takeaway for me from this little episode is how passionate we all are at keen about making sure that our customers never have to deal with this shit. We’re developers ourselves. We’re picky and observant (and some would say anal). Little details are important. We’re building something we wished we had before, and we’re working hard to make sure we’re providing a development experience that doesn’t suck.

Want to know more about what we’re working on at keen? Sign up for our preview on our website and hit us up on twitter: @keen_io or @dkador.