XCFramework with Pods Dependencies - ios

Our goal is to create a framework that hides our internal code and provide SDK to our customers.
We have thought of creating XCFramework which fulfills our requirement. Umbrella framework is also suggested over the internet but mostly suggested to avoid that approach. Our Framework is dependent on some third-party libraries which we are using via Pods.
Issue: XCFramework does not compile pods framework. We got an error like "Xyz(Pod) module not found". Even if we add pods from the client-side it does not work.
Code to create XCFramework is as bellow
1) Create an archive for iOS platform
xcodebuild archive -workspace ABC.xcworkspace \
-scheme ABC \
-sdk iphoneos \
-archivePath "./archives/ios_devices.xcarchive" \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
SKIP_INSTALL=NO
2) Create an archive for iOS-Simulator platform
xcodebuild archive -workspace ABC.xcworkspace \
-scheme ABC \
-sdk iphonesimulator \
-archivePath "./archives/ios_simulators.xcarchive" \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
SKIP_INSTALL=NO
3) Create an XCFramework from Archives
xcodebuild -create-xcframework \
-framework ./archives/ios_devices.xcarchive/Products/Library/Frameworks/ABC.framework \
-framework ./archives/ios_simulators.xcarchive/Products/Library/Frameworks/ABC.framework \
-output build/ABC.xcframework
We got ABC XCFramework successfully but dependencies are not included in XCFramework. Any solution for this? or Is there any way where we can set framework search path to client-side? or Any alternate approach?

You can create a pod and publish it.
Check https://guides.cocoapods.org/making/making-a-cocoapod.html
Sample Podspec file with XCFramework + Third party dependency
Pod::Spec.new do |s|
s.name = 'XCFrameworkTest' # Name for your pod
s.version = '0.0.1'
s.summary = 'Sample Spec'
s.homepage = 'https://www.google.com'
s.author = { 'Sample' => 'sample#sample.com' }
s.license = { :type => "MIT", :text => "MIT License" }
s.platform = :ios
# change the source location
s.source = { :http => 'http://localhost:8080/XCFrameworkTest.zip' }
s.ios.deployment_target = '10.0'
s.ios.vendored_frameworks = 'XCFrameworkTest.xcframework' # Your XCFramework
s.dependency 'PromisesSwift', '1.2.8' # Third Party Dependency
end
After you publish your pod, Customer can use cocopods to get our framework.
In Customer's Podfile
pod 'XCFrameworkTest' #Your pod name

I have created a template for this purpose. You can test it by running the command
pod lib create YourLibName --template-url="https://github.com/zalazara/pod-template-xcframework.git"
The template basically generates an example project together with its podfile file where, in turn, the framework to be developed is embedded, then the generation file compiles the framework using the workspace.
BUILD_DIR="Build"
TMP_DIR="${BUILD_DIR}/Tmp"
IOS_ARCHIVE_PATH="${TMP_DIR}/iOS.xcarchive"
IOS_SIM_ARCHIVE_PATH="${TMP_DIR}/iOSSimulator.xcarchive"
rm -rf ${BUILD_DIR}
rm -rf "${FRAMEWORK_NAME}.xcframework"
xcodebuild archive \
-workspace "Example/${WORKSPACE}" \
-scheme ${SCHEME} \
-archivePath ${IOS_SIM_ARCHIVE_PATH} \
-sdk iphonesimulator \
SKIP_INSTALL=NO \
| xcpretty
xcodebuild archive \
-workspace "Example/${WORKSPACE}" \
-scheme ${SCHEME} \
-archivePath ${IOS_ARCHIVE_PATH} \
-sdk iphoneos \
SKIP_INSTALL=NO \
| xcpretty
xcodebuild -create-xcframework \
-framework ${IOS_SIM_ARCHIVE_PATH}/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework \
-framework ${IOS_ARCHIVE_PATH}/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework \
-output ${FRAMEWORK_NAME}.xcframework \
| xcpretty
For more information : https://github.com/zalazara/pod-template-xcframework.git

Ayyanar's solution do the trick for me, but get an error on build: "Failed to build module from its module interface; it may have been damaged or it may have triggered a bug in the Swift compiler when it was produced".
I solve it linking the target to the .xcframwork from Pod.
Hope it helps somebody.

Related

Missing Required Module 'RxCocoaRuntime'

I am using RxCocoa in custom framework, so I am trying to inject dependencies with SPM and make that .xcframework.
I made the .xcframework, but the following error keeps appearing.
The process of creating and configuring the framework project and creating the xcframework was as follows.enter image description here
Development Environment
CPU : Apple slicon (M1 PRO)
MacOS : Ventura 13.1
Xcode : 14.2(14C18)
Step
Create framework project (km-ios-sdk)
Set Build Active Architecture Only YES from NO
Mach-O Type is Dynamic Library
Write simple code using RxSwift, RxCocoa
Create .xcarchive and .xcframework
xcodebuild archive \
-scheme km-ios-sdk \
-archivePath ./archive/km-ios-sdk.framework-iphoneos.xcarchive \
-sdk iphoneos \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
xcodebuild archive \
-scheme km-ios-sdk \
-archivePath ./archive/km-ios-sdk.framework-iphonesimulator-arm64.xcarchive \
-sdk iphonesimulator \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
xcodebuild -create-xcframework \
-framework './archive/km-ios-sdk.framework-iphoneos.xcarchive/Products/Library/Frameworks/km_ios_sdk.framework' \
-framework './archive/km-ios-sdk.framework-iphonesimulator-arm64.xcarchive/Products/Library/Frameworks/km_ios_sdk.framework' \
-output './KmSDK.xcframework'
Created Package.swift as below and uploaded it to git.
enter image description here
If you download and import km-ios-sdk as spm in the sample app, the error appears
enter image description here
It is the same even if you manually download .xcframework, and it is the same even if you download it with cocoapod. Is there any way to solve it?

Cannot install CocoaPod which includes iOS framework with 'LibTorch-Lite' CocoaPod dependency

MyLibrary: CocoaPod that I am trying to install and run but failing. (https://github.com/steve-ham/MyLibrary) (Includes below 'MyFramework')
MyFramework: iOS framework with 'LibTorch-Lite' CocoaPod dependency. (https://github.com/steve-ham/MyFramework)
When I run 'MyLibrary App' (https://github.com/steve-ham/MyLibrary) I get below error:
libc++abi: terminating with uncaught exception of type torch::jit::ErrorReport:
Unknown custom class type quantized.Conv2dPackedParamsBase. Please ensure it is registered.:
quantized::conv1d(Tensor qx, __torch__.torch.classes.quantized.Conv2dPackedParamsBase packed_weight, float output_scale, int output_zero_point) -> Tensor
~~~~~~~~~~~~~~~~~~~~~~ <--- HERE
terminating with uncaught exception of type torch::jit::ErrorReport:
Unknown custom class type quantized.Conv2dPackedParamsBase. Please ensure it is registered.:
quantized::conv1d(Tensor qx, __torch__.torch.classes.quantized.Conv2dPackedParamsBase packed_weight, float output_scale, int output_zero_point) -> Tensor
~~~~~~~~~~~~~~~~~~~~~~ <--- HERE
I used below code to create MyFramework.xcframework from MyFramework project (https://github.com/steve-ham/MyFramework)
xcodebuild archive -workspace MyFramework.xcworkspace \
-scheme MyFramework \
-sdk iphoneos \
-archivePath "./MyFramework.xcarchive" \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
SKIP_INSTALL=NO
xcodebuild archive -workspace MyFramework.xcworkspace \
-scheme MyFramework \
-sdk iphonesimulator \
-archivePath "./MyFramework_sim.xcarchive" \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
SKIP_INSTALL=NO \
EXCLUDED_ARCHS=arm64
xcodebuild -create-xcframework \
-framework "MyFramework.xcarchive/Products/Library/Frameworks/MyFramework.framework" \
-framework "MyFramework_sim.xcarchive/Products/Library/Frameworks/MyFramework.framework" \
-output MyFramework.xcframework
There's no error like this when I do this with other CocoaPod projects instead of 'LibTorch-Lite'. Is it merely impossible to wrap 'LibTorch-Lite' into .xcframework and deploy it like above wrapping into CocoaPod? Thanks.

Pod lib lint fails for xcframework

I have xcode project with static lib and aggregate solution where I added Multi Platform Script at Build Phases so I can create xcframework:
SCHEME_NAME=${PROJECT_NAME}
FRAMEWORK_NAME=${PROJECT_NAME}
SIMULATOR_ARCHIVE_PATH="${BUILD_DIR}/${CONFIGURATION}/${FRAMEWORK_NAME}-iphonesimulator.xcarchive"
DEVICE_ARCHIVE_PATH="${BUILD_DIR}/${CONFIGURATION}/${FRAMEWORK_NAME}-iphoneos.xcarchive"
# Simulator xcarchieve
xcodebuild archive \
-scheme ${SCHEME_NAME} \
-archivePath ${SIMULATOR_ARCHIVE_PATH} \
-sdk iphonesimulator \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# Device xcarchieve
xcodebuild archive \
-scheme ${SCHEME_NAME} \
-archivePath ${DEVICE_ARCHIVE_PATH} \
-sdk iphoneos \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# Remove older version
rm -rf "${HOME}/Desktop/${FRAMEWORK_NAME}_${APPOXEE_SDK_VERSION}"
# Create Products && Documentation && SDK directories
mkdir -p "${HOME}/Desktop/${FRAMEWORK_NAME}_${APPOXEE_SDK_VERSION}/Documentation"
mkdir -p "${HOME}/Desktop/${FRAMEWORK_NAME}_${APPOXEE_SDK_VERSION}/SDK"
# Create xcframwork combine of all frameworks
xcodebuild -create-xcframework \
-library ${SIMULATOR_ARCHIVE_PATH}/Products/usr/local/lib/lib${FRAMEWORK_NAME}.a -headers ${SIMULATOR_ARCHIVE_PATH}/Products/usr/local/lib/${FRAMEWORK_NAME}Headers \
-library ${DEVICE_ARCHIVE_PATH}/Products/usr/local/lib/lib${FRAMEWORK_NAME}.a -headers ${DEVICE_ARCHIVE_PATH}/Products/usr/local/lib/${FRAMEWORK_NAME}Headers\
-output ${HOME}/Desktop/${FRAMEWORK_NAME}_${APPOXEE_SDK_VERSION}/SDK/${FRAMEWORK_NAME}.xcframework
which creates xcframework just fine. Inside that xcframework there is info.plist
which says that all architecture arm64, armv7 and i386, x86_64 are present at xcfremework, the same results I have when I do lipo -info
Podspec file looks like:
Pod::Spec.new do |s|
s.name = "TestSDK"
s.version = "6.0.4"
s.summary = "Test SDK enables developers to harnest the full power of Test Engage Platform on their iOS applications."
s.description = <<-DESC
Test SDK enables push notification in your iOS application, for engaging your application users and increasing retention.
DESC
s.homepage = "https://mapp.com"
s.license = { :type => "Custom", :file => "Licence.txt" }
s.author = { "Test Digital" => "https://test.com/contact-us/" }
s.source = { :git => "https://github.com/TestCloud/TestSDK.git", :tag => "6.0.4" }
s.ios.framework = 'UserNotifications'
s.platform = :ios, "10.0"
s.ios.vendored_frameworks = "SDK/TestSDK.xcframework"
s.preserve_paths = 'SDK/TestSDK.xcframework'
s.resource_bundle = { 'TestSDKResources' => 'SDK/TestSDKResources.bundle' }
s.requires_arc = true
end
and pod lib lint returns me an error:
Unable to find matching .xcframework slice in '../../../../../../../../Users/ssad.ter/Desktop/private_pod/TestSDK/SDK/TestSDK.xcframework RwarSDK library ios-arm64_armv7 ios-i386_x86_64-simulator' for the current build architectures (arm64 x86_64 i386).
but it contains those architecture as I explained.
the only way when pod lib lint went successfully is when I add to pod lib lint --configuration=Debug
But from the script you can see that Build for Distribution is set to YES and SKIP INSTALL to NO, same thing is done at build settings at XCode. And the Archive when you go to Edit scheme option at XCode is set to Release mode.
Can someone point me what may be the problem here?
Your plist shows you have only x86_64 and i386 architecture available for the simulator. Are you running the command on M1 mac? If yes you need to have arm64 arch support for the simulator as well or you can run pod lib lint under rosetta emulation like this:
arch -x86_64 pod lib lint

dyld: Symbol not found after importing .xcframework

I've created an .xcframework using this script:
FRAMEWORK_NAME=${PROJECT_NAME}
SCHEME=${PROJECT_NAME}
DISPLAY_NAME=${PROJECT_NAME}
echo "Archiving ${FRAMEWORK_NAME} for iOS simulator..." >> framework.log
xcodebuild archive \
-workspace "${PROJECT_DIR}/${FRAMEWORK_NAME}.xcworkspace" \
-scheme "${SCHEME}" \
-destination "generic/platform=iOS Simulator" \
-sdk iphonesimulator \
-archivePath "${PROJECT_DIR}/Archives/${FRAMEWORK_NAME}-iOS-Simulator" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
echo "Archiving ${FRAMEWORK_NAME} for iOS..." >> framework.log
xcodebuild archive \
-workspace "${PROJECT_DIR}/${FRAMEWORK_NAME}.xcworkspace" \
-scheme "${SCHEME}" \
-destination "generic/platform=iOS" \
-sdk iphoneos \
-archivePath "${PROJECT_DIR}/Archives/${FRAMEWORK_NAME}-iOS" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
echo "Creating the ${FRAMEWORK_NAME} XC Framework..." >> framework.log
xcodebuild -create-xcframework \
-framework "${PROJECT_DIR}/Archives/${FRAMEWORK_NAME}-iOS-Simulator.xcarchive/Products/Library/Frameworks/${DISPLAY_NAME}.framework" \
-framework "${PROJECT_DIR}/Archives/${FRAMEWORK_NAME}-iOS.xcarchive/Products/Library/Frameworks/${DISPLAY_NAME}.framework" \
-output "${PROJECT_DIR}/${DISPLAY_NAME}.xcframework"
However, when I import the .xcframework in another project I get this error:
dyld: Symbol not found: _$s12ReachabilityAAC10ConnectionO11unavailableyA2DmFWC
Referenced from: /private/var/containers/Bundle/Application/A5315543-8323-4270-8D40-8BB1C940801C/App.app/Frameworks/Framework.framework/Framework
Expected in: /private/var/containers/Bundle/Application/A5315543-8323-4270-8D40-8BB1C940801C/App.app/Frameworks/Reachability.framework/Reachability
in /private/var/containers/Bundle/Application/A5315543-8323-4270-8D40-8BB1C940801C/App.app/Frameworks/Framework.framework/Framework
dyld: launch, loading dependent libraries
DYLD_LIBRARY_PATH=/usr/lib/system/introspection
DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/GPUTools.framework/libglInterpose.dylib:/usr/lib/libMTLCapture.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib
Every example I've seen on creating an .xcframework doesn't archive using an .xcworkspace, so I'm thinking my issue must be related to that. I need to archive the .xcworkspace because the framework has its own Cocoapod dependencies (Reachability being one of them), but the project I'm integrating with includes those dependencies.
Has anyone successfully created an .xcframework from source code that has Pod dependencies?

How to specify output dir name for ios simulator when using xcodebuild cli in combination with a xcworkspace?

I build a xcode (6.3.1) project that uses workspace because I'm using Pods.
When I do:
xcodebuild \
build \
-workspace MyProject.xcworkspace \
-scheme MyProject \
-configuration Debug \
-sdk iphonesimulator \
-ARCHS=i386 \
VALID_ARCHS=i386 \
SYMROOT="/tmp/build/emulator" \
SHARED_PRECOMPS_DIR="/tmp/build/sharedpch"
It outputs the app to:
/tmp/build/emulator/Debug-iphonesimulator/MyProject.app
Is there a way with the xcodebuild command to get it build to
/tmp/build/emulator/MyProject.app
I have tried to replace SYMROOT with
CONFIGURATION_BUILD_DIR="/tmp/build/emulator"
Now it builds to
/tmp/build/emulator/Monsenso.app
but that do not work smoothly with CocoaPods frameworks (e.g. Typhoon for DI) ~ build fails with:
The following build commands failed:
GenerateDSYMFile /tmp/build/emulator/Typhoon.framework.dSYM /run/emulator/Typhoon.framework/Typhoon

Resources