Universal Cocoa Touch Frameworks for iOS 8

!!!!! STOP and Read This First !!!!!

We do NOT recommend using these instructions. This post continues to be extremely popular world-wide, and we cannot stress enough that, though it will result in an artifact that will compile and will work in development, the resultant artifact will not pass Apple® validation upon deployment to production. We strongly advise that you do not use these instructions and, instead, leverage the remix as that process does yield a working artifact that will pass validation. You can find the remix here:  https://kodmunki.wordpress.com/2015/03/04/cocoa-touch-frameworks-for-ios8-remix/ This post will not be removed as it is linked to in numerous places throughout the web and its removal will lead to numerous dead links. This will be the last update that we make to this post. For questions regarding the remix, please direct them to the comments section of the remix post. Best of luck! Happy Hacking! :{)}

!!!!! STOP and Read The Above First !!!!!

*** WARNING! ***

This article is no longer valid find the new article here: https://kodmunki.wordpress.com/2015/03/04/cocoa-touch-frameworks-for-ios8-remix/

There appears to be a new issue with deploying fat binaries to the App Store that renders these instructions useless. These instructions work for all development but will archive an artifact that will be rejected by Apple validation. A new process that actually passes Apple® validation can be found here: https://kodmunki.wordpress.com/2015/03/04/cocoa-touch-frameworks-for-ios8-remix/

*** END***

Recently, Apple released Xcode 6, and, with it, true iOS Cocoa Touch Frameworks! This came as welcome news, because, for me, modularity is key, and, when working with iOS, Frameworks are the only way to keep it modular! Sure, there are static libraries, but I really don’t find them palatable. For me, modularity <=> Frameworks.

Frameworks are key for many reasons. None of which I’ll cover today. This is not a Framework evangelizing post. Nor is it a post for those looking for a pro/con list of Frameworks v. whatever. No, this post is for those of you who already use Frameworks. Those of you who may have previously leveraged things like the “kstenerud/iOS-Universal-Framework” project to implement iOS Frameworks. Those of you who may have recently discovered that not only does the “kstenerud/iOS-Universal-Framework” project no longer appear to work, but, per the note on the site, as of Xcode 6, appears to no longer be supported or maintained!

Well, fear not my friends! Today, for the low, low price of free, I am going to share with you how you can continue to use your Frameworks as Cocoa Touch Frameworks and keep happily hacking :{)}

So, without further ado, here is the kodmunki™ workflow to do just that! Please, feel free to direct questions and comments to the comment section below. I will certainly respond.

To create working, portable, distributable, universal, iOS Cocoa Touch Frameworks that work on both 32 and 64 bit devices, are testable on both devices and in simulators, and can be bundled with applications or other Cocoa Touch Frameworks, you can do the following:

Creating a Framework

    1. Fire up Xcode and start a new Cocoa Touch Framework project (Fig. 1)
      CocoaTouchFrameworks_001
      (Figure 1)
    1. 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)
    2. Set “Build Active Architecture” to “NO” – Yes your build times may be a little longer, but this is what is going to allow your Frameworks to be “universal”. So, if you don’t do this, running on your sim will be a problem. Besides, if your builds are debilitatingly slow in a framework because you set “Build Active Architecture” to “NO,” you probably aren’t maximizing modularity. (Fig. 2)
    3. Set or confirm “Valid Architectures” to arm64, armv7 and armv7s. This is likely the default. (Fig. 2)
      CocoaTouchFrameworks_002
      (Figure 2)
  1. Go to the Build Phases section of your project target and append a new Run Script phase. Paste this script in in it:
set -e

DEVICE_PATH="${OBJROOT}/UninstalledProducts/${TARGET_NAME}.framework"
SIMULATOR_PATH="${SYMROOT}/../../../../Products/Debug-iphonesimulator/${TARGET_NAME}.framework"
ARCHIVE_PATH="${SRCROOT}/_Archive"
if [ "${CONFIGURATION}" = "Release" ]; then
if [ -d "${DEVICE_PATH}" ]; then
if [ -d "${SIMULATOR_PATH}" ]; then
rm -rf "${ARCHIVE_PATH}"
mkdir "${ARCHIVE_PATH}"
cp -r "${DEVICE_PATH}" "${ARCHIVE_PATH}"
lipo -create "${DEVICE_PATH}/${TARGET_NAME}" "${SIMULATOR_PATH}/${TARGET_NAME}" -output "${ARCHIVE_PATH}/${TARGET_NAME}.framework/${TARGET_NAME}"
fi
fi
fi
exit 0;

There you go. Now you will simply develop. Assuming that you are using your simulators and devices to test regularly during development before archiving, you will not need to take special note of this, BUT do know that to get your framework artifact you will have to Archive your project. Doing so will add an _Archive/ directory (Fig. 3) to the root of your project in Finder in which you will find your artifact. Know that you will have to build the project with a simulator and archive with a device to get a universal. If someone out there wants to contribute an xcodebuild or xctool script to build both of these on the fly, please, feel free. It would be a great contribution and a welcome addition for may, I’m sure!

CocoaTouchFrameworks_003
(Figure 3)

(An example of a working framework template can be found on here on kodmunki™ Github.)

That’s it! Now, you have a Framework. But, if you are anything like me, you have likely built a kernel or some other low level Framework and will expect other higher level Frameworks to depend on this Framework. Like, say, persistence, or data. To do this you will do the following:

Creating Dependant 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)
    1. 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)
    2. Put the desired Framework artifacts in this directory. (Fig. 5)
      CocoaTouchFrameworks_004
      (Figure 5)
    1. In the “Framework Search Paths” of both your project Target and your test Target add “$(PROJECT_DIR)/lib” (Fig. 6)
      CocoaTouchFrameworks_005
      (Figure 6)
    1. 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” (Fig. 7)
      figure7
      (Figure 7)
  1. Add the Frameworks in your /lib directory to the “Link Binaries With Libraries section” of the Build Phases in both your project Target and your test Target. (Fig. 8)
    CocoaTouchFrameworks_007
    (Figure 8)

All should be working successfully!

(An example of a working dependent framework template can be found on here on kodmunki™ Github.)

Now you want to add this awesome modularity to an application you say? Okay, here’s how:

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.
  3. In the “Framework Search Paths” of your project Target add “$(PROJECT_DIR)/lib”
  4. If you are unit testing, which you should be, navigate to the Build Settings of your test Target and in the “Runpath Search Paths” add “$(PROJECT_DIR)/lib”
  5. Navigate to the General section of your project Target and add the Frameworks to the “Embedded Binaries” section. Note, that this should automatically add them to the “Linked Frameworks and Libraries” below. After this step, you should have see your Frameworks in both sections. (Fig. 9). Point of note: ensure that they aren’t duplicated in the “Linked Frameworks and Libraries” section!
    CocoaTouchFrameworks_008
    (Figure 9)

(An example of a working application template can be found on here on kodmunki™ Github.)

Some worthwhile points of note:

  • These instructions are for those projects that support Cocoa Touch Frameworks, i.e. iOS 8+. Efforts to use these instructions for prior versions, may not be futile, but are untested and will, likely, be in vain.
  • I highly recommend against using prefix headers in your Framework projects. They may work, but they have proven finicky for me. I recommend just staying away to save yourself and your Medical Flex spending account the increased costs in Aspirin, Ibuprofen, Acetaminophen, Naproxen or whatever is your headache drug of choice. Because attempting to use prefix headers in Frameworks has, for some reason, proven migraine inducing for me! :{)}
  • If you would like to port an iOS Framework built using the “kstenerud/iOS-Universal-Framework” to a Cocoa Touch Framework, I recommend you do the following: just start a new Cocoa Touch Framework, follow the steps that I have outlined here, copy and paste the files from your old project into your new project directory tree, and add them to the project. To answer a question some of you might have, yes, you could just change the settings, phases, and scripts of your current project, but I do not condone or recommend this, as you are certain to lose hours or days of your life fiddling with settings and scouring the ends of the earth for some obscure missed step. That said; if you decide to go this route, please, do not email me with issues. I don’t recommend it, and I will not offer support for it. — Well, free support anyway … paid, hourly support, maybe :{)}
  • Xcode is horrifically finicky, skittish, and unpredictable. I have tested this method with numerous libraries and have had nothing but success. Though, I must say, I have run into compiler errors and warnings from time to time for no good reason, whatsoever. That said, please be sure to try cleaning your project, clearing your derived data, re-running your build steps, and doing any of the other “regular” Xcode cleans before assuming this doesn’t work. I absolutely hate having to make this disclaimer, but if you have any experience with Xcode you, too, know this sad but inevitable truth.

Alrighty — There you have it. Modularity revived in Xcode 6. I hope that you enjoyed this post and find it useful! And, if you do, you share it with others.

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! :{)}

Advertisements

Software development leaders at the forefront of the latest in technology. Whether implementing updates or integrating with existing technology; developing products that push the bleeding edge of the latest in tech; or developing open-source products, paving the way of future tech, kodmunki™ inspires innovation, elevates quality, and drives value to production. kodmunki™ are experts in web, mobile, and hybrid solutions development; local and distributed team management and collaboration; and fast, quality, successful product delivery, offering R&D, training, consulting, and development services. Contact us at info@kodmunki.com. Let's discuss your vision.

Posted in Uncategorized
12 comments on “Universal Cocoa Touch Frameworks for iOS 8
  1. jerk says:

    Thanks for the article. These new cocoa touch frameworks are a PITA so far, but since the iOS universal frameworks hack is deprecated, had to update my old ones (well, I got one updated so far anyway). Apple keeps everything at such a high-level that it’s unbelievable complicated to do low level things.

    • kodmunki™ says:

      Thanks for commenting jerk! Though re-blogs, tweets, Linkedin pushes and the like are great, comments are by far the best form of feedback. Yours is appreciated! — On your comment: I agree, Apple can be ambiguous about anything remotely low level and inso doing make attempts at anything sophisticated, aka cool, real painful. — I hope that you get all your Frameworks back in working order, fully supporting each other and the apps that depend on them. If you run into any issues, don’t hesitate to comment again or drop a line to support@kodmunki.com. Always happy to help. — Happy Hacking! :{)}

  2. Valm says:

    Hi, Nice article I really enjoy. But my way is some thing differs. I did 1-4 steps. After that i Create Aggrigate –> Add newscript and paste the following code

    UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

    # make sure the output directory exists
    mkdir -p “${UNIVERSAL_OUTPUTFOLDER}”

    # Step 1. Build Device and Simulator versions
    xcodebuild -target “${PROJECT_NAME}” ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR=”${BUILD_DIR}” BUILD_ROOT=”${BUILD_ROOT}” clean build

    xcodebuild -target “${PROJECT_NAME}” -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR=”${BUILD_DIR}” BUILD_ROOT=”${BUILD_ROOT}” clean build

    # Step 2. Copy the framework structure (from iphoneos build) to the universal folder
    cp -R “${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework” “${UNIVERSAL_OUTPUTFOLDER}/”

    # Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory
    # cp -R “${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/Framework.swiftmodule/.” “${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/Framework.swiftmodule”

    # Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
    lipo -create -output “${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}” “${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}” “${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}”

    # Step 5. Convenience step to copy the framework to the project’s directory
    cp -R “${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework” “${PROJECT_DIR}”

    # Step 6. Convenience step to open the project’s directory in Finder
    open “${PROJECT_DIR}”

    Now i run the Aggrigate which produce the frameworks. I add that framework into my project. It works fine when i add that framework into Embedded Binaries.

    But the problem is when i get “Validate” the app for distribution it was not completed. I confirm that the problem was arise on behalf of add the frame work in Embedded Binaries.

    I also tried to remove the framework from Embedded Binaries and add it into “Linked Frameworks and Library”

    But the result is Crash and “dyld: Library not loaded:”.

    Hope you will understood about my problem. Please suggest your ideas.

    • kodmunki™ says:

      Hello Valm! — It is difficult to say for certain what the issue is without running your version of setup on our end. Because our posted Framework setup has been working well for numerous developers world-wide, I will first suggest that you try following the steps exactly as they are descibed in this post. If you are adamant about using the process that you describe, you may want to ensure that your Runpath search paths are complete and correct. See the “Creating Dependant Frameworks” section of this post step 6 and Figure 7. If this Build Setting is incorrect it can throw the dyld exception that you describe. Hope this helps! — Best of luck!

  3. I did step 1-5 and then I did Adding Frameworks to an App. Its not exactly clear to me in what situation the step Creating Dependent Frameworks would be helpful ?

    • kodmunki™ says:

      Hi Tabish! — Creating a dependent framework may, or may not be useful, for you. It will certainly depend upon our objectives. That said, one hypothetical situation where you might create a dependent framework could be in, say, a framework that defines some financial modeling. One concept that is certain to be in this model is the concept of money. Now, you could certainly define money in this model and, therefore, you would have a standalone independent framework for this. BUT because the concept of money is likely useful across numerous different models, e.g. a POS for a retail model, you might define your money in a lower level framework, i.e. kernel. If you did this, your financial model framework, would certainly depend on your kernel. That might be one example.

      Thank you for reading the post! I hope that the process was useful and resulted in a successful working model! Too, thanks for commenting! Happy Hacking :{)}

  4. Great article but you did lose me at a critical point I think. These statements were hard to follow:

    “do know that to get your framework artifact you will have to Archive your project. Doing so will add an _Archive/ directory (Fig. 3) to the root of your project in Finder in which you will find your artifact. Know that you will have to build the project with a simulator and archive with a device to get a universal”

    Can you clarify exactly what needs to be build or archived to generate the universal framework?

    I’ve followed the steps exactly but the generated framework will only work in my app when running on the device, the simulator build fails with “‘MyFramework’ is unavailable: cannot find Swift declaration for this class”.

    Thanks

    • kodmunki™ says:

      Hi Michael —

      I’m sorry to hear the process wasn’t seamless for you. To try and clarify, the excerpt that you quoted is attempting to let the developer know that this process does not build for both sims and devices on one build. It builds for sims when you as the developer explicitly builds for a sim. That is, when you choose any of your sims as your build target. It builds for the device when you choose the device as the target. Behind the scenes Xcode archives these two builds as separate artifacts on your machine. These are used independently for whichever target you are currently building.

      What the run script that this post tells you to add to your framework does is takes both of these independent builds and lipo them together to form a universal. If it did not do this, the configurations that you as the developer would need to do between building for various targets would be debilitatingly painful, and might make the whole process of architecting with modularity in mind seem, frankly, not worth it. In short, you will need to build at least once with the sim and once with the device. This will ensure that the right components are in place behind the scenes to lipo the universal. It is assumed that both of these necessary builds will just happen organically in development, as a sim build will occur on the first run of a unit test, and the device build will occur with the first archive. Leaving the developer with the desired results by virtue of just doing what he/she would just “normally” do!

      As for your exception message, without further info I really cannot say for sure why this is happening for you. What I did do, though, in effort to help, is update the post to include links to example projects for each of the steps. I went back through the blog and created each of these projects using the step by step instructions and everything worked as I would expect. These links are now available in the post at the conclusion of each section. I am also adding them here for you so they are easy to find. I would recommend going back through the post step-by-step and seeing if it doesn’t work. If it does not, I would need a little more info to better understand the issue. I hope that this works as well for you, as it has been for so many others. Best of luck! Happy Hacking! :{)}

      Example Framework: https://github.com/kodmunki/ku4objc_temp
      Example Dependent Framework: https://github.com/kodmunki/ku4objc_tempDependent
      Example App: https://github.com/kodmunki/ku4objc_tempApp

  5. Pitteri says:

    Hello, I downloaded the example framework project and tried to add the framework to my project. Everything went fine till I had to archive my project and validate with app store. The message I got is: Your executable contains unsupported architectures.

    Do you have the same issues?

    thanks in advance

Enjoy the read? -- Let us know.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

kodmunki™ Tweets

Enter your email address and receive notifications of new kodmunki™ posts by email.

%d bloggers like this: