Fat binaries and Xcode 11
With Xcode 11, the IPA export process can now result in an error if you try to export an app that contains fat binaries. Until now, we only encountered this error when trying to send it to the App Store, but Xcode now seems to be attempting to give us a “little help.”
If you tried to do this in Xcode 11, you might have faced an error like this:
Upon checking the logs, we found some valuable, though not very clear, information:
2020-03-22 22:14:41 +0000 /Applications/Xcode.app/Contents/Developer/usr/bin/ipatool exited with 1
2020-03-22 22:14:41 +0000 ipatool JSON: {
alerts = (
{
code = 3620;
description = "Configuration issue: platform AppleTVSimulator.platform doesn't have any non-simulator SDKs; ignoring it";
info = {
};
level = WARN;
},
{
code = 3620;
description = "Configuration issue: platform WatchSimulator.platform doesn't have any non-simulator SDKs; ignoring it";
info = {
};
level = WARN;
},
{
code = 3620;
description = "Configuration issue: platform iPhoneSimulator.platform doesn't have any non-simulator SDKs; ignoring it";
info = {
};
level = WARN;
}
);
}
The fat binary problem
We have some issues here. Besides Apple’s rejection of the binary, exporting an app with fat binaries significantly increases the size of your exported IPA. See the example below:
Fat binaries
Stripped Architectures:
We can clearly see that the IPA with fat binaries increases the size of the exported file by 96% in a simple example with only one embedded framework.
Removing the simulator architectures will reduce the size of our IPA and enable Apple to accept our app upload.
Removing Simulator Architectures While Building Your App
In the Build Phase of your main app, add a new run script phase and paste the code below:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
# If some frameword doesn't have an invalid architecture, the script does
# nothing to it and just goes to the next one
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"
if xcrun lipo -info "${FRAMEWORK_EXECUTABLE_PATH}" | grep -v --silent "i386\|x86_64"; then
echo "This framework does not contain simulator archs: $FRAMEWORK_EXECUTABLE_NAME"
continue
fi
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
Based on Daniel Kennett’s original script, available at: https://medium.com/@maximbilan/ios-submission-unsupported-architectures-issues-733917a98cc3