Umbrella framework - ios

I've created a framework in which is inserted the second framework, the so-called "umbrella framework". When I insert the framework in the test application(embedded binaries and linked frameworks and libraries, both) can not build app, I get the following error:
ld: framework not found 'embeddedInMyFramework' for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Than add that framework(embeddedInMyFramework) also in embedded binaries and linked frameworks and libraries and try to build than works ok. Later remove that framework from both, embedded binaries and linked frameworks and libraries and still works fine. Can someone help me with this, not sure what happens when I add framework to embedded binaries for the first time, and how to fix that (could it work somehow without adding to embedded binaries at all)

I was able to set up a working Umbrella Framework and wrote down my approach.
Step 5 should remove your linker error ld: framework not found ..
Setup:
A Swift based "client" project that has the Umbrella Framework as dependency
A dynamic Framework (mainly C++ and ObjC) that is a dependency of the Umbrella Framework
Steps:
Link the Umbrella Framework with its dependent (sub-)Framework and make sure that it is copied into the product upon building.
2. Add the location of the dependent (sub-)framework to the Framework Search Paths of the Umbrella Framework project.
3. In the "client" project make sure to link and embed the Umbrella Framework
4. Make sure the Umbrella Framework is copied into the (client-) app bundle to avoid dyld: Library not loaded: #rpath/... errors.
The (client-) app, usually under ...Build/Products/Debug-iphoneos/YOUR_CLIENT_APP.app should now contain your Umbrella Framework in a folder called Frameworks.
5. In the "client" project Make sure to add the path to the Umbrella Framework to Framework Search Paths.
If the ld: framework not found '[Framework_Name]' for
architecture ... error persists you can also add the path to the (sub-) Framework here.

HERE IS AN DEMO PROJECT:
Umbrella Framework Demo
All answers under this line are wrong, cause they just do the thing that manually copy sub frameworks into "umbrella framework"
Embedding a framework within a framework (iOS 8+)
How to create an umbrella framework in iOS SDK?
How to add a framework inside another framework (Umbrella Framework)
Umbrella framework
First thing we should know that "umbrella framework" is a conception in Mac OS not in iOS, the official document is here
https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/CreationGuidelines.html#//apple_ref/doc/uid/20002254-BAJHGGGA
if you want to create an un-recommend "UmbrellaFramework", you must do these process step by step, and know details during the compile and link periods
Change all sub frameworks Mach-O to Static Library, it means compile this target as Static Library(.a)
Manually copy all sub-Framework into UmbrellaFramework during the build phase(Like other answers did)
Add "FakeBundleShellScript" to Target "UmbrellaFramework", it makes all sub frameworks package itself resources as bundle to join "UmbrellaFramework"
Change the framework load function, you must load the sub-framework resources via path or url, cause it became an bundle, this step means you should have the supreme control of all codes both sub-frameworks & umbrella
!!Here is an example of "FakeBundleShellScript" you can refer
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
BUNDLE_IN_ROOT="$APP_PATH/${FRAMEWORK_EXECUTABLE_NAME}.bundle"
if [[ -e "$FRAMEWORK_EXECUTABLE_PATH" ]]; then
FRAMEWORK_MACH_O="$(otool -a "$FRAMEWORK_EXECUTABLE_PATH" | head -n 1)"
FRAMEWORK_FAT_ARCH="$(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")"
else
FRAMEWORK_MACH_O="NO EXIST"
FRAMEWORK_FAT_ARCH="NO EXIST"
fi
echo "FRAMEWORK_EXECUTABLE_NAME is $FRAMEWORK_EXECUTABLE_NAME"
echo "FRAMEWORK_EXECUTABLE_PATH is $FRAMEWORK_EXECUTABLE_PATH"
echo "FRAMEWORK_MACH_O is $FRAMEWORK_MACH_O"
echo "FRAMEWORK_FAT_ARCH is $FRAMEWORK_FAT_ARCH"
echo "BUNDLE_IN_ROOT is $BUNDLE_IN_ROOT"
if [[ "$FRAMEWORK_MACH_O" =~ "Archive :" ]]; then
echo "Rmove Static-Mach-O is $FRAMEWORK_EXECUTABLE_PATH"
rm "$FRAMEWORK_EXECUTABLE_PATH"
defaults write "$FRAMEWORK/Info.plist" CFBundlePackageType "BNDL"
defaults delete "$FRAMEWORK/Info.plist" CFBundleExecutable
if [[ -d "$BUNDLE_IN_ROOT" ]]; then
rm -rf "$BUNDLE_IN_ROOT"
fi
mv -f "$FRAMEWORK" "$BUNDLE_IN_ROOT"
elif [[ "$FRAMEWORK_FAT_ARCH" =~ "Architectures in the fat file" ]]; then
#statements
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
fi
done
http://alanli7991.github.io/2017/07/17/%E6%A8%A1%E5%9D%97%E5%8C%9617Framework%E4%B8%8EStaticFramework%E4%BC%AA%E8%A3%85Bundle/
As all I said, the key point of to make an un-recommend "UmbrellaFramework" is !!!! [Compile the sub-frameworks as Static, process the resources via fake a bundle], REMEMBER!! Apple always said DONT'T CREATE AN UmbrellaFramework
if you can understand Chinese, more details to make an "UmbrellaFramework" can be obtained from my blog
Alan.li 2017年的文章

Adding to embedded libraries also sets certain Build Settings, which are not removed when removing the library from embedded libraries.
Most probably the Framework Search Paths contain the path to the previously missing library.
It will not work without somehow adding the embedded library. You might want to use some dependency management tool (like CocoaPods or Carthage) to do the more or less of the work for you.

Related

Xcode 12.3: Building for iOS Simulator, but the linked and embedded framework was built for iOS + iOS Simulator [duplicate]

This question already has answers here:
Building for iOS Simulator, but the linked framework '****.framework' was built for iOS
(11 answers)
Closed 2 years ago.
I have an app using a linked and embedded custom framework. The app built properly for iOS devices and simulators until Xcode 12.2. Starting from Xcode 12.3 however, I'm getting the following error:
Building for iOS Simulator, but the linked and embedded framework 'My.framework' was built for iOS + iOS Simulator.
The framework is built for both devices and simulators (as the error actually says) and merged using lipo, so it should be able to run everywhere without issues.
Am I missing something here? Is there a relevant change in Xcode 12.3?
I'm afraid that this is actually the correct error and the framework shouldn't contain iOS and iOS Simulator code at the same time. Apple tries to force us to use XCFrameworks for this purpose. They started it in Xcode 11 and just tightened up the restrictions.
The only correct way to resolve this is to rebuild the framework as an XCFramework. Which is easy to do:
xcrun xcodebuild -create-xcframework \
-framework /path/to/ios.framework \
-framework /path/to/sim.framework \
-output combined.xcframework
You can start with a combined .framework. Make two copies of the framework, and use lipo to remove the slices from the binary that are associated with a different SDK.
It is based on the original answer from Apple here.
My particular case is that I'm getting this error using Rome, which produces these frameworks (a possible solution is here). Also, a lot of struggling is going on on the Carthage side.
You have to exclude device architectures while building for simulator and while building for the device you have to exclude simulator's architectures.
To do that, navigate to Build Settings of your project -> Excluded Architectures -> Select the configuration(Debug/Release/Etc...) -> Tap + -> Any iOS Simulator SDK -> Add arm64, arm64e, armv7
Similarly, add x86_64, i386 to Any iOS SDK.
PS: You can check all the architectures which are present in your framework by running file <path_to_framework_binary> or lipo -info <path_to_framework_binary>.
Ex. file /Users/srikanth.kv/MyProject/MyLibrary.framework/MyLibrary
I have a framework with a universal binary that contains x86_64 and arm64 which I merge with lipo with a custom script at framework build time. I encountered this same issue for Xcode 12.3 and have created a work around for now. Hopefully this will get fixed in Xcode quickly, but until then, one quick fix would be to thin the architectures and use the framework that you need.
Please see my answer here on how to start producing .xcframeworks which is the long term solution for framework authors
For instance, let's assume I'm in a terminal in the working directory where my universal framework some_framework.framework is. If I want to run on an actual physical device, I execute the following command:
lipo -thin arm64 some_framework.framework/some_framework -output some_framework
With the above command, you extract the arm64 binary. Afterwards, replace the current some_framework.framework/some_framework with the newly generated arm64 only binary
mv some_framework some_framework.framework
If you have a universal framework built only from Objective-C sources, your job is done. But if you've got Swift code too, then you would need to update some_framework.framework/Modules/some_framework.swiftmodule so that it does not contain any references to architectures that are not arm64.
You would follow a similar process for running on the simulator except that you need x86_64. I'm currently now maintaining two versions of my framework until this is fixed. Whenever I switch between the simulator and the device, I simply switch out which framework is in my project.
In addition to mistahenry's answer, you can handle this automatically in your project with this workaround.
Set your Universal framework that does not work in Xcode 12.3 to Do not embed (in General → Frameworks, Libraries and Embedded Content)
Add this "new run script phase" in "Build Phases":
FRAMEWORK_APP_PATH="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
# 1. Copying FRAMEWORK to FRAMEWORK_APP_PATH
find "$SRCROOT" -name '*.framework' -type d | while read -r FRAMEWORK
do
if [[ $FRAMEWORK == *"MY_WONDERFUL_UNIVERSAL_FRAMEWORK.framework" ]]
then
echo "Copying $FRAMEWORK into $FRAMEWORK_APP_PATH"
cp -r $FRAMEWORK "$FRAMEWORK_APP_PATH"
fi
done
# 2. Loops through the frameworks embedded in the application and removes unused architectures.
find "$FRAMEWORK_APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
if [[ $FRAMEWORK == *"MY_WONDERFUL_UNIVERSAL_FRAMEWORK.framework" ]]
then
echo "Strip invalid archs on: $FRAMEWORK"
FRAMEWORK_EXECUTABLE_NAME=$(/usr/libexec/PlistBuddy -c "Print CFBundleExecutable" "$FRAMEWORK/Info.plist")
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements $FRAMEWORK_EXECUTABLE_PATH
else
echo "Ignored strip on: $FRAMEWORK"
fi
done
Replace MY_WONDERFUL_UNIVERSAL_FRAMEWORK by the name of your framework and be sure that it is located at SRCROOT

Adding an existing framework with different architecture in two different target in xcode?

I have a framework. It has simulator's architectures as well as device's. When we try to upload our code appstore it did not allow and error summarises to remove simulator archs from the framework. Then we run lipo command to remove simulator archs. Now we have two copies of frameworks.
MyFramework.framework (with out simulators archs)
MyFramework.framework (with all archs)
I thought of creating two targets one with a framework without simulator's archs and another with all archs.
But as both frameworks are having same name in the bundle, Xcode always considering the framework without simulator's archs. So I'm unable to run it in simulator?
Any suggestion on how to add different architecture frameworks in different targets?
Rather than using the lipo command to create separate versions of the framework, I would recommend using this script to remove unneeded architectures during a buid:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
If your framework file came packaged with documentation, etc., it's possible some version of that script is already included in there for you. (That was the case for me when I ran into this problem.)
Add that script as a .sh file in your project
Add a "Run Script" phase in your target's build phases after the "Embed Frameworks" phase. (Mine is currently the very last phase).
Set the "shell" line to /bin/sh
Set the command to /bin/sh <path to the script file>
Now you will be able to run on a sim and submit to the store without issue.

Unable to submit archive including Here Maps Premium SDK with Xcode 8.2.1

archive upload failure messages screenhot
Xcode was failing to submit a project including dynamic library "NMAKit.framework" required for Here Map Premium for iOS functionality.
(uploading the sample project included in Here Maps Premium SDK for iOS to avoid side effects caused by my project leading also to upload failure)
Bitcode was disabled in project's build settings.
I'am using the latest Xcode Version 8.2.1.
I don't have trouble submitting the app without NMAKit.framework.
It seems like the actual version (Here SDK V. 3.3) of the library is not accepted by Apple.
What steps would it take to get my project including the NMAKit.framework submitted to iTunes-Connect?
Step 1:
Project->Target->Build Phase->Run Script
Add Run Script
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
you can follow this Link.
Step 2:
Project->Target->General->Embedded Binaries
Add NMAKit.framework like below image
I try with .sh script and this is working for me.
Please follow below steps
Unzip.tar file (i.e HERE_Premium_iOS_SDK_v3.7.0.118.tar)
Open extracted folder 'HERESDK-Premium'. ('HERESDK-Premium' folder generated when you extract 'HERE_Premium_iOS_SDK_v3.7.0.118.tar' file)
Open terminal
Go to extracted folder path ('HERESDK-Premium->framework' you can found 'strip_sim.sh' file in this folder and NMAKit.framework)
Run scrip in terminal with this command sh strip_sim.sh and press enter. (NMAKit.framework will be modified with this script).
Wait for complete process.
Copy new modify framework in your project and try to submit your build.
Note : When you run sh strip_sim.sh script your NMAKit.framework will be modified. Make sure replace new framework to old framework after uploading your build to iTunes.
New framework is not running in simulator.

Using a third party framework into a AppStore app pulls in the iPhoneSimulator bits

I am integrating a third party framework into my AppStore app using Xcode 6.4. The framework from the third party is a universal binary which has the following when I do the file command :
DeviceTester (for architecture i386): Mach-O dynamically linked shared library i386
DeviceTester (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
DeviceTester (for architecture armv7): Mach-O dynamically linked shared library arm
DeviceTester (for architecture arm64): Mach-O 64-bit dynamically linked shared library
I have tried adding this framework as a Embedded Binary. This works fine it build fine however when I upload the "ipa" to the AppStore, it complains of the ipa having unsupported architecture which are the simulator pieces. when I inspect the ipa file I do see a "Frameworks" folder as is with the universal framework inside it. But I don't see this for any of the other frameworks I including eg. Crashlytics/Fabric etc. So there is something incorrect here.
I also tried adding it as a framework and then made sure it is in the copy phase, but running it gives the following error on the device :
dyld: Library not loaded: #rpath/DeviceTester.framework/DeviceTester
Referenced from: /var/mobil....
Any pointers gladly appreciated, I have spent the whole day today trying to figure out what is happening with no luck.. Cheers.
From Xcode 6.1.1 & 6.2: iOS frameworks containing simulator slices can't be submitted to the App Store. You would need to remove the simulator slices from the fat framework to be able to submit to the AppStore.
Here's a script to do the magic. Add a Run Script step to your build steps, put it after your step to embed frameworks, set it to use /bin/sh and enter the following script:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
This answer might explain what you are asking.
https://stackoverflow.com/a/31270427/4160199

Submit to App Store issues: Unsupported Architecture x86

So I am trying to use the Shopify API. When I archive the app and validate it then there are no issues but when I submit it to the app store then it gives me the following issues.
ERROR ITMS-90087: "Unsupported Architecture. Your executable contains unsupported architecture '[x86_64, i386]'."
ERROR ITMS-90209: "Invalid segment Alignment. The App Binary at SJAPP.app/Frameworks/Buy.framework/Buy does not have proper segment alignment. Try rebuilding the app with the latest Xcode version." (I am already using the latest version.)
ERROR ITMS-90125: "The Binary is invalid. The encryption info in the LC_ENCRYPTION_INFO load command is either missing or invalid, or the binary is already encrypted. This binary does not seem to have been built with Apple's Linker."
WARNING ITMS-90080: "The Executable Payload/..../Buy.framework is not a Position Independent Executable. Please ensure that ur build settings are configured to create PIE executables."
The problem is that the Buy framework contains a build for both the simulator (x86_64) and the actual devices (ARM).
Of course, you aren't allowed to submit to the App Store a binary for an unsupported architecture, so the solution is to "manually" remove the unneeded architectures from the final binary, before submitting it.
Daniel Kennett came up with a nice solution and provides this script to add to the build phase:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
I used it and it worked perfectly.
EDIT: make sure you look at the modified script posted by Varrry, as this one has some minor issues.
Answer given by pAkY88 works, but I faced the same problem as Mario A Guzman in https://stackoverflow.com/a/35240555/5272316: once we cut off unused architectures we can't run script any more since it tries to remove not existing slices, because xcode doesn't re-embed binary every time.
Idea was - just remove i386 and x86_64 slices when building for archive, so I modified script:
echo "Target architectures: $ARCHS"
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")
FRAMEWORK_TMP_PATH="$FRAMEWORK_EXECUTABLE_PATH-tmp"
# remove simulator's archs if location is not simulator's directory
case "${TARGET_BUILD_DIR}" in
*"iphonesimulator")
echo "No need to remove archs"
;;
*)
if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "i386") ; then
lipo -output "$FRAMEWORK_TMP_PATH" -remove "i386" "$FRAMEWORK_EXECUTABLE_PATH"
echo "i386 architecture removed"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
fi
if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "x86_64") ; then
lipo -output "$FRAMEWORK_TMP_PATH" -remove "x86_64" "$FRAMEWORK_EXECUTABLE_PATH"
echo "x86_64 architecture removed"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
fi
;;
esac
echo "Completed for executable $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")
done
This script simply removes i386 and x86_64 slices from fat binary (if they exist) if running not for simulator (that means destination folder isn't like "Debug-iphonesimulator").
Sorry, I'm not familiar with shell scripts, so may be someone could write it more elegant way. But it works)
If you're using Carthage then you may experience this issue because the project is:
Missing the carthage copy-frameworks build phase.
Or the build phase doesn't include all the frameworks (incomplete list).
This action filters frameworks to a list of valid architectures (code).
Setting up the copy-frameworks build phase
From the Carthage building for iOS steps:
On your application targets’ “Build Phases” settings tab, click the
“+” icon and choose “New Run Script Phase”. Create a Run Script in
which you specify your shell (ex: bin/sh), add the following contents
to the script area below the shell:
/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/Box.framework
$(SRCROOT)/Carthage/Build/iOS/Result.framework
$(SRCROOT)/Carthage/Build/iOS/ReactiveCocoa.framework
This script works around an App Store submission bug triggered by universal
binaries and ensures that necessary bitcode-related files and dSYMs
are copied when archiving.
I resolved the error ITMS-90080 by removing a framework (the excellent SVProgressHUD) from the Embedded Binaries section (Xcode target -> General tab).
If you are using Carthage make sure your Embed Frameworks Build Step is before the Carthage copy-frameworks
In some unusual cases (example: Lottie-iOS framework):
you will have it simply in "Link Library" as usual.
However you have to also explicitly add it in "Embed Frameworks" (even though that seems pointless, since it works perfectly when you have it only in "Embed Frameworks"),
and put it in copy-frameworks
and ensure copy-frameworks is after "Embed Frameworks"
Remove [x86_64, i386] from the framework using below step. [x86_64, i386] is used for simulator.
Open Terminal
open your project drag path of respective framework to Terminal
example : cd /Users/MAC/Desktop/MyProject/Alamofire.framework
set your Framework name in below command and run
lipo -remove i386 Alamofire -o Alamofire && lipo -remove x86_64 Alamofire -o Alamofire
Now open your project again, Clean, Build & Run and Create Archive...
I will add my 2 cents here (in a less scary way :-). I have encountered quite a number of fat libraries from Vendors that (for some reason) do not work the normal way by adding them to the Frameworks directory as documented by Apple. The only way we have been able to make them work is by pulling the .framekwork right into the project directory and linking the Embedded Frameworks and Link Binary with Libraries manually in Build Settings. This seem to have worked without any issues, however, as with any fat library they come with the extraneous Simulator Architectures i386 and x86_64 along with the arm architectures.
A quick way to check the architectures on the fat library is
$ cd 'Project_dir/Project'
$ lipo -info 'YourLibrary.framework/YourLibExec`
Which should spit an output something like this
Architectures in the fat file: YourLibrary.framework/YourLibExec are: i386 x86_64 armv7 arm64
This confirms that you will need to "trim the fat" (namely i386 & x86_64) from your framework prior to iTunesConnect Archival upload, which doesn't allow these architectures (since they are unsupported for iOS).
Now, all the answers (or atleast some of the answers) here provide these wonderful Run Scripts that I am sure works really well, but only if your Framework resides in the Frameworks directory. Now unless you are a shell script junkie, those scripts without modifications, won't work for the scenario I explain above. However, there is a very simple way to get rid of the i386 & x86_64 architectures from the framework.
Open terminal in your project's directory.
Change directory directly into the .framekwork, like
cd YourProjectDir/YourProject/YourLibrary.framework
Run the series of commands as shown below-
$ mv YourLibrary YourLibrary_all_archs
$ lipo -remove x86_64 YourLibrary_all_archs -o YourLibrary_some_archs
$ lipo -remove i386 YourLibrary_some_archs -o YourLibrary
$ rm YourLibrary_all_archs YourLibrary_some_archs
A few things to note here - lipo -remove has to be done once for each architecture to remove. lipo does not modify the input file, it only produces a file so you have to run lipo -remove once for x86_64 and i386. The commands above is simply doing that by first renaming the executable and then eventually removing the desired archs, and then cleaning up the left over files. And that's it, you should now see a green check mark in Application Loader Archival upload to iTunesConnect.
Things to keep in mind : The above steps should only be done while production build, since the .framework will be stripped off the simulator architectures, builds on simulators will stop working (which is expected). In development environment, there should be no need to strip the architectures off of the .framework file since you want to be able to test on both Simulator and a physical device. If your fat library resides in the Frameworks folder in the project then please look at the accepted answer.
Thanks to all the above answers. Here is a script working with swift 4.2 and 5. Replace Your_Framework_Name string with your Framework's original name.
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
FRAMEWORK_NAME="Your_Framework_Name.framework"
# Check if Framework is present.
FRAMEWORK_LOCATION=$(find "$APP_PATH" -name "$FRAMEWORK_NAME" -type d)
if [ -z $FRAMEWORK_LOCATION ]; then
echo "Couldn't find Your_Framework_Name.framework in $APP_PATH. Make sure 'Embed Frameworks' build phase is listed before the 'Strip Unused Architectures' build phase."
exit 1
fi
# This script strips unused architectures
find "$APP_PATH" -name "$FRAMEWORK_NAME" -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
I had same issue even after adding the script and updating the framework a few times.
Make sure in xCode the script is added at the end, after the embed. I think I accidentally moved the script before the embedded framework.
Note: I have xCode 9.1
Updated for Xcode 10.1, Below solution worked for me :
Just you have to remove the framework from Embedded Binaries and just add it to the Linked Frameworks and Libraries.
Refer below screenshot;
This issue was resolved for me by slightly modifying the run script from pAky88's answer and executing after embedding frameworks. Also be sure to uncheck the box for "Run Script only when installing".
/usr/local/bin/carthage copy-frameworks
#!/usr/bin/env bash
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
if [ ! -f "${FRAMEWORK_EXECUTABLE_PATH}" ]; then
continue
fi
if xcrun lipo -info "${FRAMEWORK_EXECUTABLE_PATH}" | grep --silent "Non-fat"; then
echo "Framework non-fat, skipping: $FRAMEWORK_EXECUTABLE_NAME"
continue
fi
echo "Thinning framework $FRAMEWORK_EXECUTABLE_NAME"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
xcrun lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
xcrun lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[#]}"
rm "${EXTRACTED_ARCHS[#]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
I removed architectures i386 & x64_86 from Build Settings - Valid Architectures - Release, and everything worked just fine.
Now the only issue would be that you can't run a RELEASE build for testing purposes on a SIMULATOR. But as easily as you removed the archs, you can add them back if you want to.
the simple solution that worked for me was
1- remove the framework from embedded frameworks.
2- add the framework as a linked framework
done!
This error (ITMS-90240) can also be caused by a static (.a) library. heres a script to strip the excess architectures. In Xcode add this to Target > BuildPhases > Click the + and select Run Script. Then paste this into the script box.
The script searches for .a files, checks to see if it contains an offending architecture, then if it does makes a new .a file without that architecture.
For macOS:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
STRIPARCHS="armv7 armv7s arm64"
for t in $STRIPARCHS
do
if find "$APP_PATH" -name '*.a' -exec lipo -info {} \; | grep $t ; then
find "$APP_PATH" -name '*.a' -exec lipo -remove $t {} -output {}2 \; -exec rm {} \; -exec mv {}2 {} \; ;
fi
done
exit 0
For iOS :
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
STRIPARCHS="x86_64 i386"
for t in $STRIPARCHS
do
if find "$APP_PATH" -name '*.a' -exec lipo -info {} \; | grep $t ; then
find "$APP_PATH" -name '*.a' -exec lipo -remove $t {} -output {}2 \; -exec rm {} \; -exec mv {}2 {} \; ;
fi
done
exit 0
I had same issue.
Even it was not working after adding the given Run Script.
It was Xcode related issue.
I was using the Xcode version 9.0 but latest version was 9.2.
So i installed latest Xcode (9.2) and it worked.
Your framework contains both ARM and x86 code, which allows you to use it on a device or in the simulator. If you intend to submit your app to the App Store, run the following script to strip the inactive code from the binary.
1.Select your target in the Project Navigator, and click Build Phases at the top of the project editor.
2.From the Editor menu, select Add Build Phase, then Add Run Script Build Phase (or click the + button in the upper-left corner of the Build Phases editor).
3.Expand the disclosure triangle next to the new Run Script build phase that was just added. In the script editor box, paste the following:
bash
${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/"YourframeworkName.framework"/strip-frameworks.sh
Here is a script I used to specifically remove just one framework's architecture from the executable file.
# Remove unused Framework architecture from "YourApp" framework.
FRAMEWORK_EXECUTABLE_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}/Frameworks/YourApp.framework/YourApp"
echo "$FRAMEWORK_EXECUTABLE_PATH"
cp "$FRAMEWORK_EXECUTABLE_PATH" "${FRAMEWORK_EXECUTABLE_PATH}_X86_64"
echo "Executing following command to remove x86_64 arch from YourApp framework executable"
echo "lipo -remove x86_64 \"$FRAMEWORK_EXECUTABLE_PATH\" -o \"${FRAMEWORK_EXECUTABLE_PATH}_X86_64\""
lipo -remove x86_64 "${FRAMEWORK_EXECUTABLE_PATH}_X86_64" -o "$FRAMEWORK_EXECUTABLE_PATH"
rm "${FRAMEWORK_EXECUTABLE_PATH}_X86_64"
Add this script to your projects "Build Phases" of your project target. Be sure to check the box: "Run script only when installing"

Resources