Xcode 6 iOS Creating a Cocoa Touch Framework - Architectures issues

I'm trying to make a dynamic framework for an iOS app. Thanks to the new version of Xcode (6) we can select a Cocoa Touch Framework when we create a new project and there is no more need to add an aggregate target, run script and so to make one. I have no issue when i build the framework. But when I'm trying to use it inside an iOS app I get some architectures issues.

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (arm64): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
      objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture armv7:
  "_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
      objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Well I have tried to change the settings of the framework project and target (Architectures & Build valid architecture only & Valid architectures). I've done the same thing for the iOS app project but nothing works. I think there is something I didn't understand.

For example when I build a framework for only i386 (iOS Simulator) check with the command line "xcrun lipo -info MyFramework", I have an issue that

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (i386)...

If someone can help me to get a framework that works for all iOS architectures including simulators.


Based on all the responses, the post on raywenderlich.com and the gist created by Chris Conway I came up with this.

Executing the following steps I was able to build a Cocoa Touch framework (including Swift and Objective-C files) that contains all architectures for both simulator and device:

  1. Create a new (Aggregate) target in your framework's project
  2. Under "Build Phases" select "Add Run Script" and copy the contents of this file
  3. Select the Aggregate target in the Scheme Selection drop down
  4. Build the target for the aggregate scheme

Hope it helps :)

UPDATE: Fixed an error in the gist where the paths in step #3 were incorrect. Thanks to Tokuriku!!

UPDATE In Xcode 7 and 8, click File>New>Target... and there select "Other" group to select Aggregate target


Try the following steps to create a workspace that contains a framework project and an app project.

Workspace:

  • Create a Workspace.

Framework project:

  • Create an iOS Cocoa touch Framework project inside Workspace.
  • Add a simple Objective C class MyClass (header .h and implementation file .m), and create a method - (void)greetings.
  • Go project Build Phases > Headers > Move MyClass.h from Project to Public.
  • Change scheme to framework project and choose iOS simulator, then build. (Choose iOS Device if the app that integrates this framework runs on device. I will continue to use simulator in this example)
  • You should have no issue building, the framework build is found in your Derived Data directory which you can find in Organizer.

App project:

  • Create a Swift Single View application inside Workspace.
  • Drag above iOS simulator framework build (Found in Debug-iphonesimulator or Release-iphonesimulator) to your project.
  • Create a bridging header to expose Objective C class methods to Swift.
  • Import MyClass.h in bridging header file.
  • Note that if MyClass definition is not found, then add framework Headers path of to Build Settings Header Search Paths.
  • Create instance of MyClass in viewDidLoad of ViewController.swift, then call greetings.
  • Add framework to Target > Embedded Binaries
  • Change scheme to app project and choose iOS simulator, then build.
  • You should be able to see greeting messages.

Note that above example demonstrates how to build an app that runs in simulator. If you need to create universal static library that runs on both simulator and devices, then general steps are:

  • Build library for simulator
  • Build library for device
  • Combine them using lipo

There are good references on the web about it, here for example.

Create universal binary for framework: navigate to framework Derived Data directory then /Build/Products, following command should help you create a universal binary in Products directory:

lipo -create -output "framework-test-01-universal" "Debug-iphonesimulator/framework-test-01.framework/framework-test-01" "Debug-iphoneos/framework-test-01.framework/framework-test-01" 

Note that framework-test-01 is my framework project name.


The way I did it is similar to vladof, but hopefully a little simpler. I made the framework a subproject of the app project.

Framework project

  • Create a new iOS Cocoa Touch Framework. Call it MyLib. This will create a single MyLib.h
  • Add a simple Cocoa Touch Obj-C class, MyClass (.h & .m) and in the implementation of the .m, create a method that returns a string, - (NSString *)greetings;
  • In MyLib.h, add this near the bottom, #import "MyClass.h"
  • In the target's Build Phases/Headers section, Move MyClass.h from the Project section to the Public section.
  • Do a Build (cmd-B)
  • Close the the project

App project

  • Create a new Single View application project, either Swift or Obj-C. Call it MyApp.
  • From the Finder, drag your MyLib project file to the left hand organizer section of you MyApp window and make sure the insertion line is just below MyApp. This makes MyLib a subproject of MyApp. (It can still be used the same way in other projects)
  • Click on MyApp in the organizer and then select the MyApp target and select Build Phases.
  • In Target Dependancies, click the + sign and add MyLib.
  • In Link with Libraries, click the + sign and add MyLib.framework.

For an Obj-C app

  • In ViewController.m, add #import
  • In viewDidLoad, add the following lines:
  • MyLib *x = [[MyLib alloc] init];
  • NSLog(@"%@", x.greetings);
  • Run the project and you should see the message in the debug window. -

For a Swift app

  • In ViewController.swift, add import MyLib
  • in viewDidLoad, add the following lines:
  • var x: MyLib = MyLib()
  • println("(x.greetings())") -

By doing it this way, the app is dependent on the framework so if you make a change in the framework classes, you don't have to change targets to build the framework separately, it will just compile the framework first, then the app.