Skip to content

Instantly share code, notes, and snippets.

@evnik
Created December 30, 2020 20:23
Show Gist options
  • Save evnik/6762d5c3a4b21f61f13b100e03b62c38 to your computer and use it in GitHub Desktop.
Save evnik/6762d5c3a4b21f61f13b100e03b62c38 to your computer and use it in GitHub Desktop.
This script allows to convert an iOS framework binary to XCFramework
# Copyright (c) 2020 Eugene Berdnikov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# This script allows to convert an iOS framework binary to XCFramework.
# It might be useful to resolve the "Building for iOS Simulator, but the linked
# and embedded framework was built for iOS + iOS Simulator" error in Xcode 12.3.
# The script can accept working directory as a first argument.
# If no arguments passed, script looks for frameworks in the current directory.
IOS_ARCHITECTURES=(arm64 armv7 armv7s)
SIMULATOR_ARCHITECTURES=(i386 x86_64)
realpath() {
echo "$(cd "$(dirname "$1")" || exit; pwd)/$(basename "$1")"
}
remove_architectures() {
local FRAMEWORK_EXECUTABLE_PATH="$1"
shift
local ARCHITECTURES=("$@")
for ARCH in "${ARCHITECTURES[@]}"; do
if lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "$ARCH"; then
echo "Removing $ARCH from $(pwd)/$FRAMEWORK_EXECUTABLE_PATH"
lipo -remove "$ARCH" -output "$FRAMEWORK_EXECUTABLE_PATH" "./$FRAMEWORK_EXECUTABLE_PATH"
fi
done
}
if [[ "$#" -gt 0 ]]; then
SOURCE_PATH=$(realpath "$1")
else
SOURCE_PATH=$(pwd)
fi
cd "$SOURCE_PATH" || exit
find "$SOURCE_PATH" -name '*.framework' -type d | while read -r FRAMEWORK_PATH; do
echo "Handling framework in '$FRAMEWORK_PATH'"
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK_PATH/Info.plist" "CFBundleExecutable")
FRAMEWORK_DIRECTORY_NAME="$FRAMEWORK_EXECUTABLE_NAME.framework"
mkdir iOS
cp -R "$FRAMEWORK_PATH" "iOS/$FRAMEWORK_DIRECTORY_NAME"
cd iOS || exit
remove_architectures "$FRAMEWORK_DIRECTORY_NAME/$FRAMEWORK_EXECUTABLE_NAME" "${SIMULATOR_ARCHITECTURES[@]}"
cd ..
mkdir Simulator
cp -R "$FRAMEWORK_PATH" "Simulator/$FRAMEWORK_DIRECTORY_NAME"
cd Simulator || exit
remove_architectures "$FRAMEWORK_DIRECTORY_NAME/$FRAMEWORK_EXECUTABLE_NAME" "${IOS_ARCHITECTURES[@]}"
defaults write "$SOURCE_PATH/Simulator/$FRAMEWORK_DIRECTORY_NAME/Info.plist" CFBundleSupportedPlatforms -array iPhoneSimulator
cd ..
xcodebuild -create-xcframework -framework "iOS/$FRAMEWORK_DIRECTORY_NAME" -framework "Simulator/$FRAMEWORK_DIRECTORY_NAME" -output "$FRAMEWORK_EXECUTABLE_NAME.xcframework"
rm -rf iOS
rm -rf Simulator
done
@evnik
Copy link
Author

evnik commented Dec 30, 2020

This script allows to convert an iOS framework binary to XCFramework.
It might be useful to resolve the Building for iOS Simulator, but the linked and embedded framework was built for iOS + iOS Simulator error in Xcode 12.3.
The script can accept working directory as a first argument. If no arguments passed, script looks for frameworks in the current directory.
Based on @ryanthon's comment.

@pietermuller
Copy link

Nice script! Maybe add a set -e at the top to catch errors, and a #!/bin/bash shebang?

@MatejBalantic
Copy link

Thanks for this! The defaults was throwing errors for me because it doesn't seem to support reading/writing to arbitrary plist files anymore on the newer macOS versions.

Here's what I replaced it with:
Line 55:

FRAMEWORK_EXECUTABLE_NAME=$(/usr/libexec/PlistBuddy -c "Print :CFBundleExecutable" "$FRAMEWORK_PATH/Info.plist")

Line 68:

  /usr/libexec/PlistBuddy -c "Add :CFBundleSupportedPlatforms array iPhoneSimulator" "$SOURCE_PATH/Simulator/$FRAMEWORK_DIRECTORY_NAME/Info.plist"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment