Monday, November 17, 2008

Building static libraries with the iPhone SDK

I have a client that wants to use my iPhone Radio Player code for their own radio station, however they want to be able to submit the app to iTunes under their own developer account. The gotcha is they are not purchasing my source code - they want to pay a smaller fee and just have me supply them with a binary image which they can then submit to Apple.

I do not have access to my client's Apple developer account, so I needed a way to supply the client with an Xcode project that includes a skeleton of source code along with a binary library that includes all the custom radio player functionality I have developed. This will allow the client to build the iPhone app and submit it via their account without giving the client access to my source code. Normally, one would probably create a custom framework to wrap up the custom radio player code, but in the case of the iPhone, this is not an option. Apple forbids the use of external frameworks or dynamic library linking in an iPhone app. Instead, I needed to create a static library containing my radio player code.

Fortunately, creating a static library for the iPhone turned out to be a fairly simple, but not at all well documented, process. If you already have an Xcode project, you can easily turn any portion of the source code into a static library. Here's how.

1) In your Xcode project, locate the "Targets" section under the "Groups & Files" sidebar. Right click on "Targets" and choose to add a new target:



Then, in the following dialog box that appears, choose a Cocoa Touch "Static Library" target:



Name the library whatever you'd like. In this example, I named the library "TestStaticLib."

2) Now, assign source code files to your static library. You can simply drag existing files from your project list. Note: don't add the .h files.



3) Then, remove those same source code files from your app target:



4) Add the new static library to your target app via the "General" settings for the target:



5) Edit your target app's linking settings to add "-ObjC" to the "Other Linker Flags". This is only required if your static library defines Objective-C classes that your app is going to reference:



6) Build your new static library for all the SDK targets (such as simulator, iPhone Device, etc.).

7) Build your app. It should now be referencing the static library rather than compiling from the original source code.

If you need to then distribute the app to a client, you can simply remove the source code for the static library and the client will still be able to build the app without having access to the original source code.

This technique might also be useful if you have some shared code you'll use in multiple applications, but don't want to recompile the shared code each time you make a new app that references it. Simply copy the shared library binary images to a specific location in your development environment and then have all your apps link with that code.

8 Comments:

Blogger Biappi said...

Just one deployment tip

I've found that creating an Universal Binary gluing togheter the device and the simulator buids "Just Works"

It's considerably better to have only one .a than one for each architecture

November 28, 2008 2:21 AM  
Blogger d235j said...

Not really; only the developer will be testing the app in the simulator, so this will just result in extra cruft for the end user.

December 16, 2008 6:15 PM  
Blogger Phil said...

I don't think there will be extra cruft. If you make a "fat" library (with device and simulator), the linker will only link in the relevant portion of the library. This is different from dynamic linking.

January 20, 2009 4:29 PM  
Blogger costan+aw said...

If you're using static libraries to share code between iPhone projects, you can use a tool I wrote that takes the content of one project, and merges it with another project.

The tool is on GitHub, with complete instructions for using and extending it - http://github.com/costan/zerg_xcode

With my tool, you would wrap the library in an Xcode project, with all the files tucked away nicely under one folder and one group. Then the consumers would download the project somewhere, then “zerg-xcode import” from the project directory. The targets and files would be inserted in the consumer’s project, and the files would be copied on disk as well.

Most importantly, this also works for updates, even if files are added / removed.

February 28, 2009 1:42 AM  
Blogger Victor Costan said...

Thank you so much for the information!

I started with your post, and tried to automate it as much as possible. This is what I came up with: iPhone Development and Code Sharing

I would be grateful for any feedback from you and your readers.

March 2, 2009 10:03 PM  
Blogger Felix said...

Awesome! You saved me quite a bit of time in trying to figure this out by myself. Thank you.

March 18, 2009 4:32 PM  
Anonymous Clint said...

Great post. I realize that in this case the source code can't be shared, but if other folks come across this tutorial and are thinking about sharing static libraries, along with the Xcode project and source code, they might want to consider using a cross-project reference. This allows you to avoid pre-building each static library for multiple runtime environments (and is perhaps more flexible than the "fat" Universal Binary option). I actually wrote up a tutorial on this at http://www.clintharris.net/2009/iphone-app-shared-libraries in case it's helpful to anyone else.

March 30, 2009 4:31 PM  
Anonymous Phong said...

Great, let's try this

April 11, 2009 3:52 PM  

Post a Comment

Links to this post:

Create a Link

<< Home