Tagged with ios

Creating Static iOS Libraries

This is part 2 of a 2 part series on using and creating static iOS libraries. See part one: Using static iOS Libraries. for info on how to use static libraries in your own projects.

All of the below steps can be applied to create and package your own static libraries for distribution.

General Procedure

  • Create a new Xcode project of the iOS > “Cocoa Touch Static Library” variety.
  • Add your relevant source files to the project. (.h & .m)
  • I like to add a single .h file that includes all other public headers e.g. <staticLibName>.h
  • Select your newly created target.
  • Select “Build Phases”.
  • Delete the Auto Generated “Copy Files” Phase. (Xcode defaults to adding this, however i prefer to use an actual copy headers phase, which we will add in a second.)
    image
  • Now add a new “Copy Headers” phase.
  • Add your public headers to the public section & your private headers to the private section.
    image
  • Add any other dependant frameworks to the “Link Binary With Libraries” phase. (e.g. Addressbook.framework or CoreLocation.framework)
  • Select “Build Settings”.
  • Find Public Headers Folder Path and set it to include/$(TARGET_NAME) we also want to set Private Headers Folder Path to $(PUBLIC_HEADERS_FOLDER_PATH)/Private. This allows users of our library to find and include our headers. (We include the $(TARGET_NAME) variable so that users can include our headers using the standard framework idiom #include <folder/header.h>.)

  • Find Installation Directory and set it to /.
  • Find Skip Install and set it to Yes.
  • Make sure -all_load -ObjC is added to the Other Linker Flags section. (This makes sure everything in the static library is linked, even if not used at compile time. i.e. making it available at run time.)

Other Things To Consider

Trouble Finding Headers

Your users may have trouble finding headers in their projects even though they have added include/ to their Header Search Paths.They are likely running into an issue whereby the static library is being built with one configuration name and their project is building with another. (i.e. Debug vs DebugStaging)

Xcode will, on finding a matching configuration name in a sub-project use that configuration to build the sub-projects targets, however if it can’t find a matching configuration it uses the projects default config. This can lead to problems finding the matching headers. (i.e. Xcode is looking in Build/Products/DebugStaging-iphonesimulator and your library is being built into Build/Products/Debug-iphonesimulator)

To work around this you can set your public / private headers folder paths to be ../../Headers/$(TARGET_NAME), i.e. in the folder above the config specific folder that Xcode creates when building projects. If you choose to do this your users will instead need to add this folder to their header search paths instead of include/.

Headers being included in Xcode archives

If the path your static library is putting its headers into starts with a slash i.e. /include/$(TARGET_NAME), Xcode will include the headers in archived builds (because it’s a fully rooted path). This leads to app store validation failing when trying to upload a build. The solution to this problem is to change your public headers folder path in your library to no longer include the /.

Ideally you would set Public Headers Folder Path to include/$(TARGET_NAME) and Private Headers Folder Path to $(PUBLIC_HEADERS_FOLDER_PATH)/Private.

Specific Build Settings

Your Static Library Project

PUBLIC_HEADERS_FOLDER_PATH="include/$(TARGET_NAME)"; /*Public Headers Folder Path*/
PRIVATE_HEADERS_FOLDER_PATH="$(PUBLIC_HEADERS_FOLDER_PATH)/Private"; /*Private Headers Folder Path*/

Users Projects

HEADER_SEARCH_PATHS="include/**"; /*Header Search Paths (the ** indicates recursive)*/
Tagged , ,

Using Static iOS Libraries

This is part 1 of a 2 part series on using and creating static iOS libraries. See part two: Creating static iOS Libraries. for info on how to create your own static libraries for distribution.

All of the below steps can be applied generally to include any static library in your current iOS project.

General Procedure

  • Fork & checkout the static library into a sub folder of your project. (I like to create a “Third Party” folder & Xcode group.)
mkdir -p ~/Desktop/StaticLibraryDemo/"Third Party"
cd ~/Desktop/StaticLibraryDemo/"Third Party"
git clone git://github.com/heardrwt/RHAddressBook.git
  • Drag the static libraries Xcode project into your applications Xcode project.
    image
  • Select your applications current target.
  • Select “Build Phases”.
  • Add <StaticLibName> to your targets “Target Dependencies” section.
  • Add lib<staticLibName>.a to the “Link Binary With Libraries” section.
    image
  • Link any other dependant frameworks. (e.g. Addressbook.framework or CoreLocation.framework)
  • Select “Build Settings”.
  • Find Header Search Paths and add an entry consisting of include/. (The library may be set up to use another path. If this is the case, see the “Trouble Finding Headers” section below.) (I usually select the recursive option.)
    image
  • Make sure -all_load -ObjC is added to the Other Linker Flags section. (This makes sure everything in the static library is linked, even if not used at compile time. i.e. making it available at run time.)
    image
  • Finally include the static library headers in your source files using #import <RHAddressBook/AddressBook.h>.

Handy Tips

Trouble Finding Headers

If you are having trouble finding headers in your project even though you have added include/ to your Header Search Paths you may be running into an issue whereby the static library is being built with one configuration name and your project is building with another. (i.e. Debug vs DebugStaging)

Xcode will, on finding a matching configuration name in a sub-project use that configuration to build the sub-projects targets, however if it can’t find a matching configuration it uses the projects default config. This can lead to problems finding the matching headers.

Some static libs work around this by setting their public / private headers folder paths to be ../../Headers/$(TARGET_NAME), i.e. in the folder above the config specific folder that Xcode creates when building projects. If this is the case you will need to add this path to your header search paths instead of include/.

Another way to work around this is to use the direct path to the .h files inside your Third Party folder, i.e. set Header Search Paths to ""$(PROJECT_DIR)/Third Party" making sure to select recursive.

Finally, my preferred way depending on the project is to actually modify the static libraries project (You did fork the framework, didn’t you?), adding extra configurations that match the parent projects configuration names.

Headers being included in Xcode archives

If the path the static library is putting its headers into starts with a slash i.e. /include/$(TARGET_NAME), Xcode will include the headers in archived builds (because it’s a fully rooted path). This leads to app store validation failing when trying to upload a build. The solution to this problem is to change the public headers folder path in the static lib to no longer include the /.

Ideally you would set Public Headers Folder Path to include/$(TARGET_NAME) and Private Headers Folder Path to $(PUBLIC_HEADERS_FOLDER_PATH)/Private.

Specific Build Settings

Your Project

HEADER_SEARCH_PATHS="include/**"; /*Header Search Paths (the ** indicates recursive)*/

Static Library Project

PUBLIC_HEADERS_FOLDER_PATH="include/$(TARGET_NAME)"; /*Public Headers Folder Path*/
PRIVATE_HEADERS_FOLDER_PATH="$(PUBLIC_HEADERS_FOLDER_PATH)/Private"; /*Private Headers Folder Path*/
Tagged ,