Skip to content

Instantly share code, notes, and snippets.

@joncardasis
Last active March 2, 2020 17:14
Show Gist options
  • Save joncardasis/ab6efec234ca46f15f9fe31adf6669e1 to your computer and use it in GitHub Desktop.
Save joncardasis/ab6efec234ca46f15f9fe31adf6669e1 to your computer and use it in GitHub Desktop.
Build universal ios fat framework
#!/bin/bash
#
# Builds the a framework for both the 64bit iOS architecture and
# a 64bit simulator architecture, combining the two into a single FAT framework.
#
set -e -o pipefail
print_available_options() {
printf "Usage: ./build_universal_ios_framework.sh -workspace <workspacepath> -target <targetname> -configuration <configurationname> -destination <destinationpath>\n\n"
printf "Options:\n"
printf " %-40s %s\n" "-workspace PATH" "the PATH to the workspace to build"
printf " %-40s %s\n" "-target NAME" "the target NAME to build"
printf " %-40s %s\n" "-configuration NAME" "the build configuration NAME for building all targets (ex. 'Debug', 'Release')"
printf " %-40s %s\n" "-destination PATH" "the destination of the universal framework described by PATH (ex. /path/to/MyFramework.framework)"
printf " %-40s %s\n" "-configuration-simulator NAME" "the build configuration NAME for building simulator target. Optional."
printf " %-40s %s\n" "-configuration-device NAME" "the build configuration NAME for building physical device target. Optional."
}
# Fills the options needed for the script to run. If the mandatory options are not given
# the script terminates with exit code 1.
# Parameters: 1. `$@` - all command arguments.
get_options() {
while test $# -gt 0; do
case "$1" in
-workspace )
WORKSPACE_PATH=$2
shift 2
;;
-configuration )
CONFIGURATION=$2
shift 2
;;
-configuration-simulator )
CONFIGURATION_SIM=$2
shift 2
;;
-configuration-device )
CONFIGURATION_IOS=$2
shift 2
;;
-target )
TARGET_NAME=$2
shift 2
;;
-destination )
FRAMEWORK_OUTPUT_PATH=$2
shift 2
;;
*)
echo "$1 is not a recognized flag."
exit 1;
;;
esac
done;
if [ -z "$CONFIGURATION_IOS" ] && [ -z "$CONFIGURATION_SIM" ]; then
CONFIGURATION_IOS="$CONFIGURATION"
CONFIGURATION_SIM="$CONFIGURATION"
elif [ -z "$CONFIGURATION_IOS" ] || [ -z "$CONFIGURATION_SIM" ]; then
echo "Both -configuration-simulator and -configuration-device must be specified when using separate configurations Use -configuration to use the same config for both targets."
exit 1
fi
if [ -z "$WORKSPACE_PATH" ] || [ -z "$CONFIGURATION_IOS" ] || [ -z "$CONFIGURATION_SIM" ] || [ -z "$TARGET_NAME" ] || [ -z "$FRAMEWORK_OUTPUT_PATH" ]; then
echo "Not all parameters were given."
print_available_options
exit 1
fi
}
# Get command line arguments
get_options $@
# Workspace Setup
BUILD_DIR="$(mktemp -d)"
BUILD_ROOT="${BUILD_DIR}"
UNIVERSAL_OUTPUT_DIR="${BUILD_DIR}/${TARGET_NAME}-universal.framework"
mkdir -p "${UNIVERSAL_OUTPUT_DIR}"
# Build Simulator
xcodebuild \
-workspace "${WORKSPACE_PATH}" \
-scheme "${TARGET_NAME}" \
-configuration ${CONFIGURATION_SIM} \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone X' \
ONLY_ACTIVE_ARCH=NO ARCHS='x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES SKIP_BUNDLING=YES \
SKIP_BUNDLING=1 \
clean build test | xcpretty
# Build Physical Device
xcodebuild \
-workspace "${WORKSPACE_PATH}" \
-scheme "${TARGET_NAME}" \
-configuration "${CONFIGURATION_IOS}" \
-sdk iphoneos \
-destination='generic/platform=iOS' \
ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES \
clean build | xcpretty
# Copy the framework structure from the iphoneos build to universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION_IOS}-iphoneos/${TARGET_NAME}.framework/" "${UNIVERSAL_OUTPUT_DIR}"
# Copy Swift modules from the iphonesimulator build to the universal folder
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION_SIM}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUT_DIR}/Modules/${TARGET_NAME}.swiftmodule"
fi
# Create universal binary from the simulator and physical device architecture builds
echo "Linking..."
lipo -create \
"${BUILD_DIR}/${CONFIGURATION_SIM}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" \
"${BUILD_DIR}/${CONFIGURATION_IOS}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}" \
-output "${UNIVERSAL_OUTPUT_DIR}/${TARGET_NAME}"
# Copy fat framework to desired output location
if [ -d "${FRAMEWORK_OUTPUT_PATH}" ]; then rm -Rf "${FRAMEWORK_OUTPUT_PATH}"; fi
mkdir -p $(dirname "${FRAMEWORK_OUTPUT_PATH}")
cp -R "${UNIVERSAL_OUTPUT_DIR}/." "${FRAMEWORK_OUTPUT_PATH}"
# Cleanup
rm -rf "${BUILD_DIR}"
echo "Finished creation of fat framework. Output: ${FRAMEWORK_OUTPUT_PATH}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment