Lipo Error while creating Universal frameworks in xcode 12 - ios

I am facing problem while making universal frameworks in xcode 12. following is the command that i ran:-
lipo -create build/simulator/FrameworkName.framework/FrameworkName build/devices/FrameworkName.framework/FrameworkName -output build/universal/FrameworkName.framework/FrameworkName
And following is the error that i am facing:-
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: build/simulator/FrameworkName.framework/FrameworkName and build/devices/FrameworkName.framework/FrameworkName have the same architectures (arm64) and can't be in the same fat output file
when i googled this error i found solution to set my 'Architectures', in 'Build Settings', to Standard, however it was already set to standard find the screenshot attached
Note: I was following this tutorial:- https://medium.com/#anuragajwani/how-to-build-universal-ios-frameworks-74b6b07bf31d

The error tells you that both your frameworks in build/simulator and build/device folders have been built for the same architecture (arm64, which is a device architecture). You can verify this by yourself, by looking inside the .framework file: FrameworkName.framework/Modules/FrameworkName.swiftmodule.
It is possible, that one of the folders (or both) contain more than one architecture like this:
Personally, I like to build my 'fat' frameworks outside the Xcode.app folders (just to make sure I have complete control over what is where). First, run your framework for simulator (select any simulator as build target). After the process has completed, go to Products folder in Xcode Navigator, click Show in Finder on FrameworkName.framework file. Copy the shown .framework somewhere more convenient (e.g. Desktop/simulator folder)
Then, build the framework again, only this time for device (select Any iOS device as build target). Copy second .framework somewhere like Desktop/iphone folder.
Create empty Desktop/universal folder for output framework. Copy .framework file there from Desktop/iphone folder and remove Desktop/universal/FrameworkName.framework/Framework executable file. This file will later be replaced by lipo.
Next, do the lipo magic:
lipo -create ~/Desktop/iphone/FrameworkName.framework/FrameworkName ~/Desktop/simulator/FrameworkName.framework/FrameworkName -output ~/Desktop/universal/FrameworkName.framework/FrameworkName
Last step, go to Desktop/simulator/FrameworkName.framework/Modules/FrameworkName.swiftmodule copy all files that start with x86_64 prefix, and paste them to Desktop/universal/FrameworkName.framework/Modules/FrameworkName.swiftmodule. Now your Desktop/universal/FrameworkName.framework contains both device and simulator architectures. Congrats, you've got your 'fat' library!
Disclaimer: Yes, I realise there are easier ways to do this with various scripts and terminal commands, but all of them do pretty much the same thing. Once you try to do this manually step by step, it will help you understand what goes where, and what are architectures and how they can be combined.
Disclaimer 2: Starting from Xcode 12, Apple insists you build .xcframeworks instead of 'fat' libraries. See here

Related

Will changing the info.plist of custom framework manually create problems in installing on device?

I made a custom framework from a xcode project with "example.com.a" bundle identifier using lipo -create command by joining simulator and iphone architecture frameworks. So it has a bundle identifier "example.com.a" in it's info.plist file by default. I am able to use this framework in my app and my app installs on device without any error
Now when i try to change the bundle identifier of the custom framework to something like "myapp.custom.framework" by manually editing the info.plist inside the framework folder instead of xcode project .
By doing this I am unable to install the .ipa in the device. It shows "Unable to install the app".
So my question is
1) Is manually changing the bundle identifier or adding keys to custom framework's info.plist affects the custom framework functionality ?
2) For changing the bundle identifier of custom framework do we need to change it in the main xcode project? Right now i am changing and adding keys in the info.plist which is there in framework folder.
After long research and trial i found that if we change the bundle identifier in info.plist inside the custom framework folder, it will create error while adding in a sample project, instead we need to change the bundle identifier from the XCode project for framework and then generate iPhone and Simulator .framework and use lipo -create output to combine them and create a universal library.
Following are the steps :
To build and distribute universal/fat frameworks:
In the framework project:
Build xcode framework project for simulator and build for device, this will produce two frameworks in the derived data folder.
Find the derived data path for the project. Look for the folder Build->Products. Inside it should be '-iphoneos' and '-iphonesimulator'. Inside each is a .framework folder. Copy one of those to some nice folder. From each of those .frawework folders, copy the binary that is in there to one folder.
In Terminal:
In terminal run the command lipo -create -output <outputName> <binaryFromiphoneos> <binaryFromiphonesimulator>. This will create a fat binary with all architectures for both simulator and devices. Replace the one in the copied .framework directory with the newly generated one preferably inside the folder of iPhone platform framework.
Run lipo -info <framework path> in terminal to know about the architecture of the framework . Eg: X86 denotes simulator , arm64, arm7 denotes iphone devices.
To use the framework in another app:
Select the Project in the Project Navigator, select the target, and select General tab.
drag the .framework folder onto where it says 'Add embedded binaries here'.
In the build settings of the target, add the path to the .framework folder to 'Framework Search Paths'.
Import files in your source code using #import <frameworkName/frameworkName.h>

Xcode project giving pod file error for FIRAnalyticsConnector.framework . How to solve it?

I'm working on a book project and the project is connected by API . I'm working on the book app which has different libraries imported from the various places.
Recently, i cloned the project from bitbucket in Xcode and tried to run it. The result i got i error as follows:
enter image description here
It shows :
ld: in /Users/ishinfoservices/Documents/vadltaldhambooks/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector(FIRAnalyticsConnector_a8eeba373b74508311b8b22b8d3202a6.o), building for iOS Simulator, but linking in object file built for iOS, file '/Users/ishinfoservices/Documents/vadltaldhambooks/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector' for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Help needed to fix the error, as the project has lots of mixes of old libraries along with .h and .m files, the swift files with wireframes
According to the image I saw that you are trying run the app on the iOS simulator, then you could try to add the arm64 to the Excluded Architectures on the Build Settings section of your project or target, it would be like:
Take in mind that if you use Cocoa Pods is possible that also you should add the arm64 to the Exclude Architectures into the Pods project
After the above, clean, build and run the project on the iOS simulator, is possible that on your physical device you must remove the arm64 from the Exclude Architectures, it could depend on what you use in your project.
On the other hand, you can try the following: Select the project -> Select the target -> Go to the Build Phases -> Expand the Link Binary with libraries and add all pod libraries (remove if they exist in embedded binaries or Remove the old FrameWorks), after that, clean and build the project

Unable to build framework

I am unable to build a framework doing following->
1.Select a simulator in run devices
2.Under Product -> build in Xcode tool bar
3.Right click on the product section ->show in finder
now in terminal I execute following command->
lipo -info /path/to/debugfolder/
it gives me follwing error -
fatal error: /Applications/Xcode
app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo:
can't map input file:
/Users/Imacshubhendra/Library/Developer/Xcode/DerivedData/SendOTPFramework-hkrvnvttlmwijudmlfcaxdowqhpz/Build/Products/Debug-iphoneos/SendOTPFramework.framework
(Invalid argument)
I am follwing these steps->
In the framework project:
Set the build setting for the target (and for the project, just to be safe) 'Build Active Architectures only' to NO. We want to build all architectures so that the binary can be used in all supported devices, not just the one we happen to build for. Depending on your deployment target (and as a consequence of that, the devices you support), you might need to add the architecture ARMv7s
Build for simulator and build for device, this will produce two frameworks in the derived data folder.
In Terminal:
Find the derived data path for the project. Look for the folder 'Build->Products'. Inside it should be '-iphoneos' and '-iphonesimulator'. Inside each is a .framework folder. Copy one of those to some nice folder. From each of those .frawework folders, copy the binary that is in there to one folder.
In terminal run the command 'lipo -create -output '. This will create a fat binary with all architectures for both simulator and devices. Replace the one in the copied .framework directory with the newly generated one.
To use the framework in another app:
Select the Project in the Project Navigator, select the target, and select 'General' tab.
drag the .framework folder onto where it says 'Add embedded binaries here'.
In the build settings of the target, add the path to the .framework folder to 'Framework Search Paths'.
Import files in your source code using #import

How to use Realm (installed with Carthage) with a framework in a Swift app?

I'm working on an iOS App and a Watchkit App.
I read a few things regarding best practices and I decided to create a custom framework, as NathashaTheRobot advise here:
https://realm.io/news/architecting-app-apple-watch-natashatherobot/
So I'm trying to use Realm in my framework.
I followed the installation instructions for Carthage:
Add github "realm/realm-cocoa" to your Cartfile.
Run carthage update.
Drag RealmSwift.framework and Realm.framework from the
Carthage/Build/iOS/ directory to the “Linked Frameworks and
Libraries” section of your Xcode project’s “General” settings.
On your application targets’ “Build Phases” settings tab, click the
“+” icon and choose “New Run Script Phase”. Create a Run Script with
the following contents:
/usr/local/bin/carthage copy-frameworks
and add the paths to the frameworks you want to use under “Input
Files”, e.g.:
$(SRCROOT)/Carthage/Build/iOS/Realm.framework
$(SRCROOT)/Carthage/Build/iOS/RealmSwift.framework
Then I added my framework to the Target Membership of both Realm.framework and RealmSwift.framework.
But when I try to build the project, I get this error:
ld: framework not found Realm for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Then I gave a shot to lipo:
$ lipo -info Carthage/Build/iOS/Realm.framework/Realm
Architectures in the fat file: Carthage/Build/iOS/Realm.framework/Realm are: i386 x86_64 armv7 arm64
Do you have any ideas of what I might be doing wrong here? Thank you.
EDIT:
OK so I found the problem and it was totally unrelated to Realm...
It looks like I deleted the Headers and Resources sections of my framework Build Phases somehow (which were and are still empty). I just put them back and everything compiles/works like it should.
Don't be tempted to delete those two
Is it possible that it's your test target that can't find the frameworks? You'll have to add the parent location of the frameworks to the "Frameworks Search Path" section of your unit tests (likely $(SRCROOT)/Carthage/Build/iOS).
Here's a sample project of a Swift framework bundling RealmSwift as a dependency which you might find useful to compare your build settings against: https://static.realm.io/debug/ParentFramework.tgz

Cocoa Touch Framework fails to debug on simulator in embedding project

I've got a Cocoa Touch framework built with XCode 6 targetted towards iOS >= iOS8.
This framework's target architecture settings are default, meaning that I haven't changed anything.
The architectures are set to standard (which doesn't include x86_64, more on that later).
The framework itself contains both Swift and Objective-C code, so building it using the static library workaround from Ray Wenderlich won't work.
Now, if I create a new project and add the framework project to it, the project builds for both the device and simulator, which is fine.
However, if I take the .framework file and add it to a different project just like you'd add any other framework, the project won't build for the simulator. Well, it does build, but it crashes because it can't find the relevant classes. It works fine on the device and archiving works just as expected as well.
The framework project itself already gives me a warning;
"Apple Mach-O Linker Warning - Directory not found for option ....(Debug-ophoneos)".
Any help would be highly appreciated!
I have finally found the solution to this issue.
As it turns out, XCode no longer creates fat binaries out of the box. No idea what Apple's reasoning behind this might be, too me it just seems like sometimes the guys responsible for XCode like to make fun of the developers using their product...
Anyways, you can find the definitive guide as to how to create a fat binary for simulator and all iOS devices (yes, you even have to lipo different architectures in order to get a framework that works on newer and older devices): https://kodmunki.wordpress.com/2015/03/04/cocoa-touch-frameworks-for-ios8-remix/
In short;
Create a Cocoa Touch Framework
Set the Architectures to arm64, armv7, and armv7s
Set "Build Active Architecture" to "NO"
Set "Valid Architectures" to arm64, armv1, and armv7s
Add the following script to the framework's build Scheme as an Archive Post-action;
set -e
DEVICE_BIN="${OBJROOT}/UninstalledProducts/${TARGET_NAME}.framework"
SIMULATOR_BIN="${SYMROOT}/../../../../Products/Debug- iphonesimulator/${TARGET_NAME}.framework"
ARCHIVE_PATH="${SRCROOT}/_Archive"
rm -rf "${ARCHIVE_PATH}"
mkdir "${ARCHIVE_PATH}"
if [ "${CONFIGURATION}" = "Release" ]; then
if [ -d "${DEVICE_BIN}" ]; then
DEVICE_PATH="${ARCHIVE_PATH}/Release"
mkdir "${DEVICE_PATH}"
cp -r "${DEVICE_BIN}" "${DEVICE_PATH}"
fi
if [ -d "${SIMULATOR_BIN}" ]; then
SIMULATOR_PATH="${ARCHIVE_PATH}/Debug"
mkdir "${SIMULATOR_PATH}"
cp -r "${DEVICE_BIN}" "${SIMULATOR_PATH}"
lipo -create "${DEVICE_BIN}/${TARGET_NAME}" "${SIMULATOR_BIN}/${TARGET_NAME}" -output "${SIMULATOR_PATH}/${TARGET_NAME}.framework/${TARGET_NAME}"
fi
fi
exit 0;
This will create an _Archive directory in your project's directory where you can find the frameworks for both debug and release.
Important: As of today (May 22nd 2015) you'll have to build the project with the simulator first, and then archive with a device. Otherwise you won't get a universal binary!
This post has been created in order to avoid dead link errors, for updates regarding the packaging process, please ALWAYS try the steps posted on the kodmunki website I've linked above first as the steps in this post might have been outdated already!

Resources