Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build Cocoa Touch Framework with CocoaPod dependencies, don't embed

Tags:

xcode

ios

swift

I have an SDK that I built into a CocoaTouch Framework. This SDK uses CocoaPods, because it depends on some other libraries. I build the framework using this build script:

# 1
# Set bash script to exit immediately if any commands fail.
set -e
# 2
# Setup some constants for use later on.
FRAMEWORK_NAME="MyFrameworkName"
OUTPUT_DIR="${SRCROOT}/framework/build"
# 3
# If remnants from a previous build exist, delete them.
if [ -d "${OUTPUT_DIR}" ]; then
rm -rf "${OUTPUT_DIR}"
fi
# 4
# Build the framework for device and for simulator (using
# all needed architectures).
xcodebuild -workspace "${FRAMEWORK_NAME}.xcworkspace" -scheme "${FRAMEWORK_NAME}" -configuration Release -arch arm64 -arch armv7 -arch armv7s only_active_arch=no defines_module=yes -sdk "iphoneos" -derivedDataPath "${OUTPUT_DIR}"
xcodebuild -workspace "${FRAMEWORK_NAME}.xcworkspace" -scheme "${FRAMEWORK_NAME}" -configuration Release -arch x86_64 -arch i386 only_active_arch=no defines_module=yes -sdk "iphonesimulator" -derivedDataPath "${OUTPUT_DIR}"
# 5
# Remove .framework file if exists from previous run.
if [ -d "${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework" ]; then
rm -rf "${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework"
fi
# 6
# Copy the device version of framework.
cp -r "${OUTPUT_DIR}/Build/Products/Release-iphoneos/${FRAMEWORK_NAME}.framework" "${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework"
# 7
# Replace the framework executable within the framework with
# a new version created by merging the device and simulator
# frameworks' executables with lipo.
lipo -create -output "${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${OUTPUT_DIR}/Build/Products/Release-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${OUTPUT_DIR}/Build/Products/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"
# 8
# Copy the Swift module mappings for the simulator into the
# framework. The device mappings already exist from step 6.
cp -r "${OUTPUT_DIR}/Build/Products/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule/" "${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule"

This all works fine, also using the framework is not a problem. But since this framework is built using other dependencies, for example Alamofire and Firebase, there are traces of this in the MyFrameworkName.framework.

When I run an app that uses this my framework, and CocoaPods to add the needed dependencies to the project, I get these errors:

objc[7299]: Class APMPBDynamicFilterResultTimestamp is implemented in both /private/var/containers/Bundle/Application/9966CA12-11F5-42FE-91FF-BB7A91C07571/MyProject.app/Frameworks/MyFrameworkName.framework/MyFrameworkName (0x101b34158) and /var/containers/Bundle/Application/9966CA12-11F5-42FE-91FF-BB7A91C07571/MyProject.app/MyProject (0x1007416e8). One of the two will be used. Which one is undefined.

How would I go about building the framework with the dependencies (otherwise it won't build of course), but without including any of it in the framework?

Thanks

like image 473
Jeroen Avatar asked Nov 06 '22 14:11

Jeroen


1 Answers

The problem comes from the fact you are using cocoapods dependencies in your SDK. As you mentioned, everything works fine, until the host app has the same dependencies. Unfortunately, there is no simple way to fix the problem, due to symbols for the same dependencies were linked into both SDK and the app. However, there are a few approaches you might consider.

  1. If you are willing to release your SDK through cocoapods, then you can specify dependencies in your podspec. However, in that case, the SDK should be built by cocoapods. e.g. podspec example
  2. The other approach would be adding an abstraction layer to your SDK. You should use the Bridge pattern to work with your abstraction.

I hope that helps.

like image 92
P_O Avatar answered Nov 15 '22 06:11

P_O