Xcode 6 iOS Creating Cocoa Touch Framework - Architecture Issues

I am trying to create a dynamic framework for an iOS application. Thanks to the new version of Xcode (6), we can select the Cocoa Touch Framework when we create a new project, and we no longer need to add an aggregated goal, run the script and do it like that. I have no problem creating the framework. But when I try to use it in an iOS application, I get some architecture 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 tried to change the settings of the project and the target of the framework (Architecture and Create only valid architecture and Virtual architectures). I did the same for the iOS app project, but nothing works. I think I didn’t understand something.

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

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, the file was created for x86_64, which is not related to architecture (i386) ...

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

+48
cocoa ios8 xcode6
Jun 04 '14 at
source share
8 answers

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

By following these steps, I was able to create a Cocoa Touch structure (including Swift and Objective-C files) that contains all the architectures for both the simulator and the device:

  • Create a new (aggregated) goal in your structure project
  • In the "Build Phases" section, select "Add Script Run" and copy the contents of this file
  • Select a goal Aggregate goal in the Scheme drop-down list
  • Create Target for aggregate circuit

Hope this helps :)

UPDATE: Fixed a bug in the entity where the paths in step 3 were incorrect. Thanks Tokuriku !!

UPDATE . In Xcode 7 and 8, click File> New> Target ... and select Other to select Group Target.

+62
Nov 01 '14 at 16:02
source share

Try the following steps to create a workspace containing a framework project and an application project.

Workspace:

  • Create a workspace.

Framework project:

  • Create an iOS Cocoa touch Framework project inside the workspace.
  • Add a simple Objective-C class MyClass (header .h and implementation file .m) and create a method greeting - (void).
  • Go project Build Phases > Headers > Move MyClass.h from Project to General .
  • Change the scheme to the project framework and select iOS simulator, and then execute. (Select an iOS Device if the application integrating this infrastructure runs on the device. I will continue to use the simulator in this example)
  • You should not have a problem, the frame assembly is located in the Derived Data strong> directory , which you can find in the Organizer .

Application Design:

  • Create a Swift Single View application inside the workspace.
  • Drag and drop above the framework of the iOS framework (found in Debug-iphonesimulator or Release-iphonesimulator) into your project.
  • Create a header for the bridge to open the methods of the Objective-C class for Swift.
  • Import MyClass.h in the header file assembly.
  • Note that if the MyClass definition is not found, add the Headers structure path to create the Header Search Contours settings.
  • Create an instance of MyClass in viewDidLoad from ViewController.swift, then call greetings.
  • Add framework to target> Embedded binaries
  • Change the scheme to the project and select the iOS simulator , then create.
  • You should be able to see welcome messages.

Please note that the above example shows how to create an application running in the simulator . If you need to create a universal static library that works both on the simulator and on devices, then the general steps are:

  • Simulator Build Library
  • Assembly library for the device
  • Combine them with lipo

There are good links on the Internet here .

Create a universal binary for the framework: go to the Derived Data directory, then / Build / Products , the following command should help you create a universal binary in the 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 frame project name.

+47
Jun 18 '14 at 21:14
source share

Below are the steps to create a bold (universal) structure:

  • Set ONLY_ACTIVE_ARCH=NO to Build Settings in your project.

    • Simulator Build Library
    • Assembly library for the device
  • Open the folder for your framework in the Products console (you can open it through the open folder of the framework and cd .. from there)

enter image description hereenter image description here

  1. Run this script from Products . A fat Framework is created in this folder. (or do it manually, as described below in 4. 5. )

     framework_name="${$(basename $(find ./Debug-iphoneos -type d -name '*.framework' -maxdepth 1))%.*}" && \ cp -R Debug-iphoneos/$framework_name.framework ./$framework_name.framework && \ lipo -create -output "$framework_name.framework/$framework_name" "Debug-iphonesimulator/$framework_name.framework/$framework_name" "Debug-iphoneos/$framework_name.framework/$framework_name" 



Or:

  1. Combine these 2 Framework with lipo using this script (replace YourFrameworkName with your Framework name)

     lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName" 
  2. Replace the new binary with one of the existing frameworks:

     cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName 



    1. Profit: ./YourFrameworkName.framework - - ready to use bold binary! . You can import it into your project!


For a project, this is not in xcworkspace -es:

You can also try to use this meaning. But it seems that it does not work for projects in workspaces.

+12
Apr 15 '15 at 13:45
source share

The way I did this is similar to vladof, but hopefully a little easier. I made the structure a subproject of the application project.

Framework project

  • Create the new iOS Cocoa Touch Framework. Call it MyLib. This will create one MyLib.h
  • Add a simple Cocoa Touch Obj-C class, MyClass (.h and .m) and into the .m implementation, create a method that returns a string - greetings (NSString *);
  • In MyLib.h add this below, #import "MyClass.h"
  • In the target “Phase / Header Assembly” section, move MyClass.h from the “Project” section to the “Publication” section.
  • Build (cmd-B)
  • Close the project

Application project

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

For Obj-C application

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

For the Swift application

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

Thus, the application depends on the framework, so if you make changes to the infrastructure classes, you do not need to change the goals to create the structure separately, it first compiles the structure, then the application.

+10
Jun 24 '14 at 17:39
source share

I slightly modified someone's script to support all Simulator architectures:

 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}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator VALID_ARCHS="x86_64 i386" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Step 2. Copy the framework structure to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 3. 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 4. Convenience step to copy the framework to the project directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 5. Delete temporary build directory in the project directory rm -rf "${PROJECT_DIR}/build" # Step 6. Convenience step to open the project directory in Finder open "${PROJECT_DIR}" 
+6
Jul 10 '15 at 20:21
source share

A step-by-step article on creating Cocoa Touch Frameworks with screenshots found at this link → How to create a Cocoa touch structure

+2
Dec 02 '14 at 10:15
source share
Finally, I have earned from me! And it’s a pity the big yellow frame, I have no idea how to format it better.

The solution was obtained from Claudio Romandi, but the script associated with it has a slight problem. I can not comment on his message, because I need a reputation of 50, so I was left without a choice, but to copy his message in order to have a complete solution.

  • Create a new (aggregate) goal in your Framework project
  • Select an aggregate in the workspace and add "New Run script Phase"
  • Paste the following code into it:

     #!/bin/sh 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/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.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 directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 6. Convenience step to open the project directory in Finder open "${PROJECT_DIR}" 
  • Select "Unit in the drop-down list of schemes"

  • Assembly, you're done!

The problem was that the simulator directory pointed to a nonexistent directory, changing the "Framework" to "$ {PROJECT_NAME}" in 2 places, did the trick :)

+2
Jan 17 '15 at 16:02
source share

A few additional points around the vladof shared approach that are more applicable to high-speed platforms

  • The script in the linked link requires modification to copy all files from iphonesimulator and iphoneos, since swift has separate compiled files for arm and i386
  • Make sure you have ARCHS = "x86_64" ONLY_ACTIVE_ARCH = NO in the assembly for iphonesimulator to avoid problems with linkers for the simulator
  • Make sure your interface / class extends NSObject, otherwise you will encounter problems when trying to use code in swift (it will complain about the inability to create an object using ().
+1
Jul 06 '14 at 15:50
source share



All Articles