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.
14 comments:
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
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.
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.
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.
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.
Awesome! You saved me quite a bit of time in trying to figure this out by myself. Thank you.
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.
Great, let's try this
This doesn't solve the problem of having a company wide library that you would like to update on the fly.
Isn't there a way I can just add the header files to my search path and add the lib to the linker phase?
I've tried doing this but the only way to get it to work is what you have listed here ='(
Nic:
Look into Xcode / Preferences / Source Trees. You can store your private library / sources in a separate repository and separate folder, and Xcode can find them using the Source Trees settings. It can be updated independently.
You can also look into svn:externals if you are using subversion, for instance.
thank you! That looks like a great resource
Hi,
Thanks for your post, I am trying myself to have some code from my iphone app to use in other apps with similar functionality, so from what I understand, static libs are the way to go (due to frameworks restrictions for AppStore apps).
I have followed carefully the steps you describe, however I for some reason get stuck in step 6 (Build static lib for all SDK targets). When I build the static lib target (right-click target, select "Build lib") I get 99 build errors, basically of the type:
error: syntax error before 'UIButton'/'UIView'/etc
fatal error: method definition not in @implementation context
Then on the errors window, I click on the .m file line, and the errors seem to origin in some .h files in the .m file imports.
At first I thought it had to do with some missing frameworks in the lib target, so I added the same fw's I had in the app target (UIKit, Foundation, etc) but that did not work.
I assume there is some linking missing that should be included. May you have any clue on what could be missing? I also see there is a Copy Headers directory in the lib target. Should I add the headers there too?
I would appreciate any help. Please let me know in case you need further information.
Thank you advance!
Hi,
I finally got build the static lib target. A bit of background:
The static lib I am trying to build in general consists of some view controller classes (UIViewController extending classes) and delegate classes (NSObject classes) which I plan to use as base classes on other projects. I use the delegate classes to hold some functionality outside of the view controllers, and in some cases I want some UI elements to be updated from these delegates, so they hold references to UIButton, UIView, etc.
Originally the delegates contained only a (Foundation/Foundation.h) import, and that was sufficient for a successful build of the project's target. However, when I added them to the static lib target and tried to build, it sent the "error: syntax error before 'UIButton'" type of errors and the build failed, again, only on the delegates.
The solution was to add the (UIKit/UIKit.h) import to the delegates and the UI* types were recognized so the build finally completed.
I still wonder why this was not needed on the project build. (it might be something simple. I am just beginning with ObjC and XCode - Please let know in case you know the answer!)
Again, thanks for the post.
For anyone else having problems using categories from statically linked libraries, you need to add -all_load to "Other Linker Flags", in addition to -ObjC.
Post a Comment