Say you’re part of an iOS mobile development team with its own Apple Developer Enterprise account. You create an app, you distribute it to other employees at your company, and everything works great.
But now say you need to send your app to another team who will distribute it via the App Store. So you send them your Enterprise .ipa
, they resign it with their standard Apple Developer (App Store) account, and they submit it to Apple. If your app is sufficiently complex, you may receive this error:
ITMS_90426: Invalid Swift Support – The SwiftSupport folder is missing. Rebuild your app using the current public (GM) version of Xcode and resubmit it.
Why does this happen? Why does it matter which type of account was used to generate the .ipa
?
Well, App Store .ipa
s are very different from Enterprise ones:
As you can see above, Enterprise .ipa
s don’t include the SwiftSupport
folder. This has to do with the processing Apple has to do before it will release an app to the App Store. So what are your options? How can you resolve this Invalid Swift Support issue?
Get an App Store account
The easiest thing to do would be to get your own standard Apple Developer (App Store) account. When you generate the .ipa
using that account it will include all of the necessary files and Apple won’t reject it once it’s submitted. But that’s no fun, and it’ll cost you $99/year.
Manually add the SwiftSupport folder
It turns out, the SwiftSupport
folder is included in the .xcarchive
that is used to generate an .ipa
. It can also be generated by scanning the .app
Frameworks
directory for .dylib
files, and copying the matching ones from the Xcode toolchain.
Even knowing all of this, it’s still not easy to actually execute. The folders need to have a certain structure with certain names, the .ipa
needs to be unzipped and zipped back up, etc. That’s why I created a script that will do it for you:
#!/bin/bash
for ARGUMENT in "$@"
do
KEY=$(echo $ARGUMENT | cut -f1 -d=)
VALUE=$(echo $ARGUMENT | cut -f2 -d=)
case "$KEY" in
ipa_path) ipaPath=${VALUE} ;; # Format: "Path/to/app.ipa"
archive_path) archivePath=${VALUE} ;; # Format: "Path/to/app.xcarchive"
toolchain_path) toolchainPath=${VALUE} ;; # Format: "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0/iphoneos"
*)
esac
done
# Derived Variables
ipaDirectory=$(dirname "$ipaPath")
ipaName=$(basename "$ipaPath")
zipName=${ipaName/.ipa/.zip}
appName=${ipaName/.ipa/}
zipSuffix=-unzipped
unzippedDirectoryName=${appName}${zipSuffix}
newIpaSuffix=-with-swift-support
newIpaName=${appName}${newIpaSuffix}
swiftSupportPath=SwiftSupport/iphoneos
ipaSwiftSupportDirectory=${ipaDirectory}/${unzippedDirectoryName}/${swiftSupportPath}
# Changes the .ipa file extension to .zip and unzips it
function unzipIPA {
mv "${ipaDirectory}/${ipaName}" "${ipaDirectory}/${zipName}"
unzip "${ipaDirectory}/${zipName}" -d "${ipaDirectory}/${unzippedDirectoryName}"
}
# Copies the SwiftSupport folder from the .xcarchive into the .ipa
function copySwiftSupportFromArchiveIntoIPA {
mkdir -p "$ipaSwiftSupportDirectory"
cd "${archivePath}/${swiftSupportPath}"
for file in *.dylib; do
cp "$file" "$ipaSwiftSupportDirectory"
done
}
# Creates the SwiftSupport folder from the Xcode toolchain and copies it into the .ipa
function copySwiftSupportFromToolchainIntoIPA {
mkdir -p "$ipaSwiftSupportDirectory"
cd "${ipaDirectory}/${unzippedDirectoryName}/Payload/${appName}.app/Frameworks"
for file in *.dylib; do
cp "${toolchainPath}/${file}" "$ipaSwiftSupportDirectory"
done
}
# Adds the SwiftSupport folder from one of two sources depending on the presence of an .xcarchive
function addSwiftSupportFolder {
if [ -z "$archivePath" ]
then
copySwiftSupportFromToolchainIntoIPA
else
copySwiftSupportFromArchiveIntoIPA
fi
}
# Zips the new folder back up and changes the extension to .ipa
function createAppStoreIPA {
cd "${ipaDirectory}/${unzippedDirectoryName}"
zip -r "${ipaDirectory}/${newIpaName}.zip" ./*
mv "${ipaDirectory}/${newIpaName}.zip" "${ipaDirectory}/${newIpaName}.ipa"
}
# Renames original .ipa and deletes the unzipped folder
function cleanUp {
mv "${ipaDirectory}/${zipName}" "${ipaDirectory}/${ipaName}"
rm -r "${ipaDirectory}/${unzippedDirectoryName}"
}
# Execute Steps
unzipIPA
addSwiftSupportFolder
createAppStoreIPA
cleanUp
Usage
First, save a copy of the script and make it executable like so:
chmod +x path/to/script
Then, if you have access to the .xcarchive
, you can execute the script like this:
path/to/script \
ipa_path="path/to/app.ipa" \
archive_path="path/to/app.xcarchive"
If you don’t have access to the .xcarchive
, the SwiftSupport
folder can still be generated from the Xcode toolchain. In this case, provide the path to the SwiftSupport
.dylib
s for your version of Xcode and target sdk, making sure that the toolchain_path
you provide contains a list of .dylib
files:
path/to/script \
ipa_path="path/to/app.ipa" \
toolchain_path="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0/iphoneos"
Either of these approaches will create a new .ipa
in the same directory as the original one, but with -with-swift-support
added to its name. And if you submit a resigned version of this .ipa
, Apple will have its precious SwiftSupport
folder and you can get on with your life.
I hope this can help someone and thanks for reading!