iOS 9 Universal Cocoa Touch Frameworks

Apple® is back at it and has released iOS 9! This is a welcome update packed with some awesome new features. But with this comes a few small changes that require an update to the Universal Cocoa Touch Framework process to keep our Cocoa Touch Frameworks modular, universal, and allow us to validate them successfully.

Here is the step by step process:

Creating a Framework

  1. Fire up Xcode and start a new Cocoa Touch Framework project (Fig. 1)


    CocoaTouchFrameworks_001 (Figure 1)

  2. Go to the Build Settings of your project target and confirm or set the “Architectures” to “Standard Architectures.” These are arm64 and armv7, and are likely the default. (Fig. 2)

  3. Set “Build Active Architecture” to “NO”. (Fig. 2)

  4. Set “Valid Architectures” to arm64, armv7 and armv7s. (Fig. 2)


    CocoaTouchFrameworks_002 (Figure 2)

  5. Set “Defines Module” to “YES”

  6. Add the script below to your project’s build Scheme as an Archive Post-action:

    1. Edit your projects build Scheme by selecting “Edit Scheme” from the Scheme drop down.


      EditScheme

    2. Add the script below as an Archive Post-action, select your project from the “Provide build settings from” drop down, and click “Close.”


      UpdateScheme

Archive Post-action script

 set -e

 BUILD_INTERMEDIATES="${OBJROOT}"
 BUILD_PRODUCTS="${SYMROOT}/../../../../Products"
 DEVICE_BIN="${BUILD_INTERMEDIATES}/UninstalledProducts/iphoneos/${TARGET_NAME}.framework"
 SIMULATOR_BIN="${BUILD_PRODUCTS}/Debug-iphonesimulator/${TARGET_NAME}.framework"

 ARCHIVE_PATH="${SRCROOT}/_Archive"
 rm -rf "${ARCHIVE_PATH}"
 mkdir "${ARCHIVE_PATH}"

 if [ "${CONFIGURATION}" = "Release" ]; then
 if [ -d "${DEVICE_BIN}" ]; then
 DEVICE_PATH="${ARCHIVE_PATH}/Release"
 mkdir "${DEVICE_PATH}"
 cp -r "${DEVICE_BIN}" "${DEVICE_PATH}"
 fi

 if [ -d "${SIMULATOR_BIN}" ]; then
 SIMULATOR_PATH="${ARCHIVE_PATH}/Debug"
 mkdir "${SIMULATOR_PATH}"
 cp -r "${SIMULATOR_BIN}" "${SIMULATOR_PATH}"
 lipo -create "${DEVICE_BIN}/${TARGET_NAME}" "${SIMULATOR_BIN}/${TARGET_NAME}" -output  "${SIMULATOR_PATH}/${TARGET_NAME}.framework/${TARGET_NAME}"
 fi
 fi

 exit 0;

Now you will simply develop.

Note that you will both have to build with your Simulator and Archive with your device to get a universal.

003a (Figure 3)

An example of a working framework template can be found on the kodmunki™ Github

Creating Dependent Frameworks

  1. Perform steps 1-6 from above to create the Framework.

  2. In the Build Settings of both the project Target and the test Target, set “Always Search User Paths” to “YES”. (Fig. 4)


    002.5 (Figure 4)

  3. Add a /lib directory to your Framework that will contain all of your project’s custom Frameworks, i.e. kernel if this is data. (Fig. 5)

  4. Put the desired Framework artifacts in this directory. When done correctly, the /lib directory will contain a /Debug and a /Release directory each containing your binary dependencies. (Fig. 5)


    dependentLib (Figure 5)

  5. Go to the Build Settings of your project target and set “Defines Module” to “YES”

  6. In the “Framework Search Paths” of both your project Target and your test Target add “$(PROJECT_DIR)/lib/$(CONFIGURATION)” (Fig. 6)


    config2 (Figure 6)

  7. In the “Runpath Search Paths” of both your project Target and your test Target add the following paths: “$(inherited), @executable_path/Frameworks, @loader_path/Frameworks, $(PROJECT_DIR)/lib/$(CONFIGURATION)” (Fig. 7)


    config (Figure 7)

All should be working successfully! Run your unit tests, build with both the simulator and device, and archive your project to verify.

An example of a working framework template can be found on the kodmunki™ Github

Adding Frameworks to an App

  1. Create a /lib directory at the project root that will contain the custom Frameworks that you want to add.

  2. Put the desired Framework artifacts in this directory. (Be sure to add both the Debug and Release bins at the directory level. This is just like in step #4 of the previous section

  3. In the“Runpath Search Paths” and “Framework Search Paths” of your project target and test target add “$(PROJECT_DIR)/lib/$(CONFIGURATION)”

  4. Navigate to the General section of your project Target and add the desired Frameworks to the “Embedded Binaries” section. Add the binaries that are found in Release! The ones in Debug will not pass validation with Apple®! This should automatically add the Frameworks to the “Linked Frameworks and Libraries” below. After this step, you should have see your Frameworks in both sections. (Fig. 9).


    CocoaTouchFrameworks_008 (Figure 9)

Point of note: ensure that they aren’t duplicated in the “Linked Frameworks and Libraries” section!

An example of a working framework template can be found on the kodmunki™ Github

I hope that this post is as helpful as it’s predecessors

Please, comment on and share this post with others if you enjoy it; follow @kodmunki on Twitter for regular updates on new developments, deployments, articles, and tools; and check out kodmunki™ on github for cool, managed, and tested kodmunki™ projects.

Happy hacking! :{)}

44 thoughts on “iOS 9 Universal Cocoa Touch Frameworks

    1. Good day jedi —

      Apple changed the location of a project’s compiled artifacts requiring us to make updates to the artifact collection steps in our process. The changes are small, but evident.

      Because, internally, we treat our development instructions as atomic, independent units of information, these changes by Apple required a new post.

      You can investigate these changes further by reviewing the Post Action script included in the process and through examining the DerivedData of your framework project.

      Hope this helps! Happy Hacking! :{)}

      1. Right, the addition of the platform in the path (in this case, iphoneos) in this case. Sorry, I must have glossed over that when reading as I had already addressed that since I was working on a framework target for tvOS. Thanks for pointing it out, since it was driving me a bit nuts.

  1. This blog is life savior. I followed the steps and it worked like a charm. Really helpful bro.

    I have one question though. If I have to distribute my framework same like Crashlytics or any other third party frameworks does, Should I use this Debug version (Universal) of the framework. As they provide only one framework file to integrate inside project. And it works on simulator and devices both.

    Please do guide me. This will be helpful.

    1. This is great news Shardul! This process worked very nicely for us as well. In answer to your question: we are not distributing our frameworks so I cannot say with any authority how you might distribute your frameworks. In the past I would have told you that you should push your Universal as this will certainly run on all platforms. The problem though is that distributing that artifact may lead to your users not being able to validate their dependent applications and therefore making it impossible for them to distribute their apps to the app store. I highly suggest that you create a dependent project yourself and attempt to push it to the app store bundled with the Universal. This should give you an answer. Hope that helps! Good luck! :{)}

  2. The first example for “Creating a Framework” does not match the description from the explanation. There is no Kernel target in the example in the post action script. In the example project, the post action script is not there. Does that mean the template doesn’t really need the post action script?

    1. Good day Mike —

      I am unclear as to what you are saying here. A few of us have looked at this question and we are not able to determine what does not “match.” If you could offer some more information we would are happy to try and offer a helpful answer to your question. But, in short, I can say that the instructions posted here are the very instructions that we go to and follow every time we create a new framework. We look forward to your offering a little more clarity on this one! :{)}

  3. I’ve followed the steps here on how to create a framework and it worked fine, but I’m having a problem when I try to make my framework use another framework (in this case, cryptoswift).

    I followed creating dependent frameworks guide but it has one problem.
    When I run my project (that uses my framework, that uses cryptoswift) on a simulator it works fine, but if I run it on a device it crashes on launch with the error
    “dyld: Library not loaded: @rpath/CryptoSwift.framework/CryptoSwift
    Referenced from: /private/var/mobile/Containers/Bundle/Application/5E2B0A0B-F519-497F-8E00-CC9354E49CB7/MyApp.app/Frameworks/MyFramework.framework/MyFramework
    Reason: image not found”

    Could you by any chance help me solve this issue? Thanks!

    1. Good day Ricardo —

      It sounds like you are missing dependencies. Have you tried linking (embedding) all of your dependencies into your app? That is, have you bundled CryptoSwift along with your custom framework into your application?

      1. I wanted to avoid precisely that.

        I thought that MyFramework dependencies would just be confined to the framework itself and I wouldn’t need to add those dependencies to the app. This way, if I want to ship MyFramework, the user also has to download all the frameworks I used inside mine. Isn’t there any way around it?

      2. Good Day Ricardo —

        Directly to your question: There may, in fact, be a “way around it,” but we don’ t have any resources that will be investigating this anytime soon. And, quite frankly, will likely never have resources investigate this.

        What you are describing does not adhere to our dependency management model and would not be a welcome change as the model you describe does not maximize a loosely coupled architecture. The process that we outline in this post describes a process that works quite well for independent framework development with well defined context segregation whereby team artifact ownership is easily distinguishable and sharable across a pull dependency paradigm via explicit and versioned contractual APIs. Our drive to adhere to this and efforts to exploit the gains that we see from it will continue.

        I hope that this helps clear up our thoughts on your question, and helps highlight that our non-action in investigating it further is not out of apathy or malice but because of an apparent disparity in our respective development goals.

        All of our best to you in finding a satisfactory answer to your question. Thank you for checking in. Happy Hacking! :{)}

  4. Thank you for putting together this tutorial. Having the 3 different sections really covers most (possibly even all) of the questions I was having.

    I am having problems synchronising the instructions in the first section (Creating a Framework) with the example framework sample code (ku4objc_temp). The two problems are, 1. (minor) the tutorial shows the project name as ‘ku4objc_kernel’, but the actual project name is ku4objc_temp; and, 2. (more problematic) the ku4objc_temp Xcode project lacks the archive post actions script.

    1. Good day David —

      Some answers to your questions:

      1) It is likely that the developer who composed this article was using our internal ku4objc_kernel project for the walkthrough. This is not public code, but the ku4objc_temp (template), the template for our frameworks, is. That is likely the reason for the naming disparity.

      2) We have looked into the temp project “[lacking] the archive post actions script,” and we are not seeing this issue. All attempts to pull it from Github are including it on our end. I am sorry to hear that this is not the case for you. It is not our intention to cut corners nor to push sub-standard code or tutorials. I hope that in the event that this continues to not work as intended, you can grab the necessary script from the blog post and successfully install it into your project.

      It is great to hear that your questions were answered, and we greatly appreciate your giving us the heads up on the Post Action Script. If we can replicate the issue on our end we will fix it immediately. Thanks for checking in!

      Best of luck to you on your current project! :{)}

  5. Do you follow the same steps 1-6 if you are creating a watch framework? I want my framework to run on the watch also, Does this mean that I need to add a new target and follow steps 1-6(i did this and when I try archive there is no artifact produced)?

    Any help would be appreciated

    1. Good day Brett!

      Watch apps, huh? Pretty cool! — We have been very busy on this end working on a huge product that we are very excited about and have not had any time to take a stab at a watch app.

      So, with that said, what I am about to suggest is highly experimental, but very likely a solid hypothesis. If you do try it, we would greatly appreciate your taking the time to respond to us and let us know if it worked. A little quid pro quo as it were :{)}

      Okay, so, here it is: you are likely not getting your watch archive because this script assumes iphone. If Xcode follows the same convention for their varied devices, i.e. watch and tv (which they very likely do), you should be able to get this to work for watch by modifying the Post Archive script.

      Step 6 of this process requests that you add a bash script to your Archive Post-action. Please, focus your attention on line 3 and 4. There, we are defining paths to the device and device simulator. The very first thing I would try in my experiment with this is to try changing the DEVICE_PATH from …/iphoneos/… to …/watchos/… and the SIMULATOR_PATH from …/iphonesimulator/… to …/watchsimulator/… (assuming there is such a thing)

      As I said, if Xcode is following convention not only should this work for watch, but substituting tvos instead of watchos should yield a tvos framework.

      Some further work could likely be done on the script to condense setup for multiple devices, but this should get you started.

      Furthermore, if this proved to not work, the next thing I would try is navigate to the “UninstalledProducts” directory mentioned in the script and see what Xcode is naming the watchos directory, and then substituting that in the script.

      There you have it. The first things that kodmunki would do in effort to solve this problem. We will be very interested in what you find, and would much appreciate your letting us know.

      Best of luck to you! :{)}

  6. Holy moly this process should be a lot simpler! Thanks for the tutorial. Strange one, though it seems to be working, I’m still getting a warning: “directory not found for option ‘-F/(etc)/projectName/lib/Debug’

      1. Weird, I’ve retested a few times today and new projects/frameworks seem to be working ok. So something must have gone wrong in the process yesterday. Thanks, and good work!

  7. I have created my custom Framework using swift. I was able to use it separately for the iOS simulator and device by building(Command+B) separately for both of them. Now I want to distribute my custom SDK as like crashlytics.

    How should I generate the production framework(release framework) from my Custom cocoa Touch Framework Project? Anything which you may suggest or advise would really be helpful.

    Thanks in advance.

    1. Good day Saravana —

      You issue in regard to distribution is becoming a more common request for us. I am sorry to report that, at this time, we do not distribute any of our frameworks outside of our internal develop network, and, because of this, we have not invested any efforts on implementing a solution. Our sincerest best wishes to you in finding your solution and to a successful distribution. :{)}

  8. I have developed a custom framework in Swift. And it worked perfectly in the iOS Simulator and device, which was build(command+B) on both simulator and device. I wasn’t able to distribute it as like crashlytics or other frameworks.

    How should I generate the production framework (releasable version) from my custom cocoa touch framework project? Anything which you find as suggestive or advisable would be really helpful.

    Thanks in advance.

  9. Hi kodmunki. I have one problem, when I try to run my app in my device IOS shows a message than it can’t find the my framework library (Reason:image not found). Do you think your procedure would fix it? Thanks in advance.

      1. This response isn’t really helpful. I get it, you can’t be the helpdesk for the internet, but at the same time iOS development is often dealing with many moving targets.

      2. Good day scottyelich —

        Thanks for checking in! Sorry to hear that you didn’t find this response satisfactory. We do hope that you will find some others to your liking!

        Happy Hacking! :{)}

  10. Hi Kodmunki, Thanks for reply individually,
    I am hoping for answer:
    Issue: I already have 1 ready framework(and their .a files) say “A”, i am trying to create my own custom framework “B” in which i want to make Framework “A” as sub-framework (Wrapper). i just want to hide framework “A” from developer (just provide public API through B). how to do that?

    Getting error:
    1)http://stackoverflow.com/questions/36934763/cannot-import-framework-file-in-custom-framework-in-ios
    2)http://stackoverflow.com/questions/36879769/how-to-build-framework-from-static-library-in-ios

    Any help will much appreciated. thanks

    1. Good day Avijit —

      A static library may be a better fit for your objective as “wrapping” or “hiding” “sub-frameworks” is not something that we understand as possible with a framework.

      Thanks for checking in, and best of luck to you in accomplishing your objective! :{)}

  11. I have followed first 6 steps and wondering how can the created project be connected into the other project in order to use it? Thank you.

    1. Thanks for checking in Ruslan —

      You will want to continue reading the post to the end. As the first six steps do describe how to create a framework, a later subsection describes how to wire it into an app.

      Happy hacking! :{)}

  12. Hello and thank you for posting this article. While I am a developer, iOS Swift development is not my day job, so please pardon my ignorance. (I find XCode generally mysterious 🙂

    I am confused by the following:

    1. It seems that, when any change is made to the framework, it would be necessary to build the framework project against a simulator target and then archive it. Is that correct?

    2. Regarding the process of copying the artifacts to the /lib directory. Am I correct that each time the framework changes the debug and release framework folders must be recopied to the consuming app’s source /lib directory? Could links to the framework _archive directory be used when adding the reference instead?

    3. I’m confused about the difference in the consuming app’s General/Embedded Binaries and General/Linked Frameworks and Libraries. Could you explain why the Release version of the framework is put in ‘Embedded Binaries’ and the Debug version is put in the ‘Linked…’ section?

    I would greatly appreciate if you have time to answer these questions. I am building a “companion” application to my “primary” application and I would like to share Swift code and other artifacts between them. I didn’t realize that would be quite this complicated.

    Thank you.

    Peter…

    1. Good day Peter –

      Thanks for checking in! There are quite a few points to cover in your post. We’ll do our best here.

      1) Our internal systems development strongly encourages development of completely uncoupled, independent modules. These modules are developed with zero external dependencies and interact with disparate modules and dependent applications via internally defined contracts that these external components are obliged to conform to in order to leverage the features that a given module defines. For us, builds against the various targets are not necessarily required, but are inevitable during our development process. With that said, it may not be necessary for you to proceed with the steps that you define, but it is difficult to say for sure without more insight into your project.

      2) For us, we semantically version our Frameworks and deploy these artifacts to be pulled by dependent applications at a time of their choosing. These artifacts are placed in the /lib directory. You may be able to link these to ease parallel development, but that would have to be tested. If you do link, you may want to expect errors in archiving as the link may cause your Frameworks to not be deployed to the target device leading to runtime sig terms and/or sig aborts due to undefined components. It would certainly be interesting to know what you find.

      3) It is our understanding that Linked Frameworks are merely linked to the app at linking time. That is these dependencies are assumed to exist on the running device. Whereas Embedded Binaries are assumed to not exist on the device and should be bundled with your application. The reason for the Debug in Linked and Release in Embedded are as follows. Debug binaries are lipo’d into Fat Binaries in the compilation script that you can find in this same post. This allows the binaries to be run on the Simulator and has proven to ease our development cycle. Since Apple stopped accepting fat binaries in the validation step of deployment, Release binaries are Embeded in the target Archive, one so that they are available for linking, but two, the Release is used because they do not include the simulator architecture in the archived artifact and can therefore pass Apple validation at time of deployment.

      Hope this helps. Happy Hacking! :{)}

      1. “How to add a /lib Directory to my framework” help me out I am stopped there

      2. Assuming you are running a mac, system defaults, and El Capitan OS:

        1. Open a terminal window. You can do this by pressing cmd+spacebar and typing in the word “Terminal” and then pressing enter.

        2. Run `mkdir /PATH/TO/YOUR/PROJECT/ROOT/lib`, where /PATH/TO/YOUR/PROJECT/ROOT is the path to the root of your project. *Note that this is just one of a veritable plethora of ways to create a new directory on a Mac.

        Best of luck! :{)}

  13. The script below takes the “Frameworks” directory into account (when using swift, is some circumstances all swift dependencies are poured there)

    set -e

    DEVICE_BIN=”${OBJROOT}/UninstalledProducts/iphoneos/${TARGET_NAME}.framework”
    SIMULATOR_BIN=”${SYMROOT}/../../../../Products/Debug-iphonesimulator/${TARGET_NAME}.framework”

    ARCHIVE_PATH=”${SRCROOT}/_Archive”
    rm -rf “${ARCHIVE_PATH}”
    mkdir “${ARCHIVE_PATH}”

    if [ “${CONFIGURATION}” = “Release” ]; then

    if [ -d “${DEVICE_BIN}” ]; then
    DEVICE_PATH=”${ARCHIVE_PATH}/Release”
    mkdir “${DEVICE_PATH}”
    cp -r “${DEVICE_BIN}” “${DEVICE_PATH}”
    fi
    if [ -d “${SIMULATOR_BIN}” ]; then
    SIMULATOR_PATH=”${ARCHIVE_PATH}/Debug”
    mkdir “${SIMULATOR_PATH}”
    cp -r “${SIMULATOR_BIN}” “${SIMULATOR_PATH}”
    lipo -create “${DEVICE_BIN}/${TARGET_NAME}” “${SIMULATOR_BIN}/${TARGET_NAME}” -output “${SIMULATOR_PATH}/${TARGET_NAME}.framework/${TARGET_NAME}”
    for SWIFT in ${DEVICE_BIN}/Frameworks/*
    do
    BNN=”${SWIFT##*/}”
    lipo -create “${DEVICE_BIN}/Frameworks/${BNN}” “${SIMULATOR_BIN}/Frameworks/${BNN}” -output “${SIMULATOR_PATH}/${TARGET_NAME}.framework/Frameworks/${BNN}”

    done
    fi
    fi
    exit 0;

  14. For people who are getting the error “Apple Mach-O Linker error – Linker command failed” when you add your framework to another project. Try to set “Match-O Type” to “Static Library” instead of “Dynamic Library” in your framework. I’ve lost some hours with this issue…

Leave a reply to Universal Cocoa Touch Frameworks for iOS8 – (Remix) | kodmunki™ Cancel reply