Xcode 6 iOS Creating a Cocoa Touch Framework - Architectures issues

后端 未结 10 1810
眼角桃花
眼角桃花 2020-11-27 09:54

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 i

相关标签:
10条回答
  • 2020-11-27 10:00

    Few additional points around the approach shared by vladof that are more applicable to swift based Frameworks

    1. The script in the associated link needs modification to copy all files from both iphonesimulator and iphoneos since the swift has separate compiled files for arm and i386
    2. Ensure that you have ARCHS="x86_64" ONLY_ACTIVE_ARCH=NO in the build for iphonesimulator to avoid linker issues for simulator
    3. Ensure that your interface/class extends NSObject otherwise you will run into issues when you try to use the code in swift (it will complain about not being able to create object using ().
    0 讨论(0)
  • 2020-11-27 10:06

    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.

    0 讨论(0)
  • 2020-11-27 10:07

    I've changed someone's script a bit to support all Simulator's 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's directory
    cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
    
    # Step 5. Delete temporary build directory in the project's directory
    rm -rf "${PROJECT_DIR}/build"
    
    # Step 6. Convenience step to open the project's directory in Finder
    open "${PROJECT_DIR}"
    
    0 讨论(0)
  • 2020-11-27 10:08

    Sorry I've let this topic open for such a long time... Some of you has correctly answered to my question. When I wrote this question I didn't catch there were two slices in a complete (also called fat) framework (ready to use). One for the iOS devices and one for the simulator. When I discovered that I made a script using lipo command to fusion the two slices and got automatically a complete framework.

    0 讨论(0)
  • 2020-11-27 10:11

    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.

    0 讨论(0)
  • 2020-11-27 10:12

    Wanted to add something to the lipo script answer provided by skywinder here. I followed the steps but still couldn't get my framework to run on simulator, only device. To fix that:

    -I went into the debug-iphonesimulator version of the framework, and in Modules/[FrameworkName].swiftmodule, I copied all of the i386 and X86 files.

    -I then went into the newly-created fat version of the framework, and navigated to that same folder. I pasted in the i386 and X86 files (to go with the ARM files already in there), and then added my fat framework to my project.

    Voila, she works on simulator and real device! This is Xcode 10 / Swift 4.2 btw

    0 讨论(0)
提交回复
热议问题