Reputation: 2103
I have created swift based Cocoa Touch Framework
project named TestLib
then I have added new target for Cocoa Framework
named TestLibOSX
. When I use the framework on iOS app it seems to be working without any issue, but when I create OSX console application it XCode is complaining that it couldn't find TestLibOSX
module. Am I missing something ?
P.S This is not the same :)
EDIT: Seems this must be possible since I can see Lister is implemented that way.
Upvotes: 6
Views: 2062
Reputation: 1352
Alright, universal frameworks are really a pain. Not only for iOS and OSX but also just within iOS since you need 2 frameworks: one for the simulator and one for the devices. The way you handle iOS is with an "Aggregate" target. I believe the same avenue could be exploited to integrate an OS X target.
When you build a framework, you get a .framework (lego block) folder. In there, there are 2 very important things to be had:
In both of these places, you have to have implementation to support all the architectures you desire to support. If you where to build your frameworks separately and wanted to fuse them together, you would have to do the following:
In practical terms, it's a mess so here's what I do!
The script is rather straightforward and with a little dabbling, I'm sure it can be tweaked to add OSX support to it. I hope this points you in the right direction :)
Contents of the script:
#!/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'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}"
Upvotes: 1
Reputation: 1069
If you wish to create a single dynamic framework binary, here are the steps you can follow (as outlined in http://colemancda.github.io/programming/2015/02/11/universal-ios-osx-framework/):
This should change your framework's and test unit's valid architectures and supported platforms as well. If not, then manually change them to inherit from the project's build settings.
Base SDK: I recommend OS X, but it will work with iOS too. Note that with with iOS as the base SDK, "My Mac" target is separated into 3 different targets.
Supported Platforms: macosx iphoneos iphonesimulator
Valid Architectures: arm64 armv7 armv7s i386 x86_64
Runpath Search Paths: $(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks
Framework Search Paths: $(SDKROOT) $(inherited)
This will allow you to import it as import MyFramework
instead of
#if os(iOS)
import MyFramework
#else
import MyFrameworkOSX
#endif
Upvotes: 3