DEV Community

Quang
Quang

Posted on

Building your own XCFramework

XCFramework is born to replace the traditional universal framework format .framework, which can contain both simulator and physical device architectures code. Besides, XCFramework can also support Catalyst, Mac, watchOS inside a framework

Using Apple provided tool

From Terminal, Using xcodebuild -create-xcframework which takes input -framework (from your previous archives) and -output

For example:

xcodebuild archive -workspace Alamofire.xcworkspace -scheme "Alamofire iOS" -sdk iphoneos13.0 OBJROOT=build/iOS
xcodebuild archive -workspace Alamofire.xcworkspace -scheme "Alamofire iOS" -sdk iphonesimulator13.0 OBJROOT=build/simulator
xcodebuild -create-xcframework -framework build/iOS/UninstalledProducts/iphoneos/Alamofire.framework -framework build/simulator/UninstalledProducts/iphonesimulator/Alamofire.framework -output build/Alamofire.xcframework

Xcode build phase script

create new Aggregate target, add to New Run Script Phase. This new target should be in the same Xcode project with your framework target.

# Release dir path
OUTPUT_DIR_PATH="${PROJECT_DIR}/XCFramework"

function archivePathSimulator {
  local DIR=${OUTPUT_DIR_PATH}/archives/"${1}-SIMULATOR"
  echo "${DIR}"
}

function archivePathDevice {
  local DIR=${OUTPUT_DIR_PATH}/archives/"${1}-DEVICE"
  echo "${DIR}"
}

# Archive takes 3 params
#
# 1st == SCHEME
# 2nd == destination
# 3rd == archivePath
function archive {
    echo "▸ Starts archiving the scheme: ${1} for destination: ${2};\n▸ Archive path: ${3}.xcarchive"
    xcodebuild clean archive \
    -project "${PROJECT_NAME}.xcodeproj" \
    -scheme ${1} \
    -configuration ${CONFIGURATION} \
    -destination "${2}" \
    -archivePath "${3}" \
    SKIP_INSTALL=NO \
    OBJROOT="${OBJROOT}/DependentBuilds" \
    BUILD_LIBRARY_FOR_DISTRIBUTION=YES | xcpretty
}

# Builds archive for iOS simulator & device
function buildArchive {
  SCHEME=${1}

  archive $SCHEME "generic/platform=iOS Simulator" $(archivePathSimulator $SCHEME)
  archive $SCHEME "generic/platform=iOS" $(archivePathDevice $SCHEME)
}

# Creates xc framework
function createXCFramework {
  FRAMEWORK_ARCHIVE_PATH_POSTFIX=".xcarchive/Products/Library/Frameworks"
  FRAMEWORK_SIMULATOR_DIR="$(archivePathSimulator $1)${FRAMEWORK_ARCHIVE_PATH_POSTFIX}"
  FRAMEWORK_DEVICE_DIR="$(archivePathDevice $1)${FRAMEWORK_ARCHIVE_PATH_POSTFIX}"

  xcodebuild -create-xcframework \
            -framework ${FRAMEWORK_SIMULATOR_DIR}/${1}.framework \
            -framework ${FRAMEWORK_DEVICE_DIR}/${1}.framework \
            -output ${OUTPUT_DIR_PATH}/xcframeworks/${1}.xcframework
}

### Static Libraries cant be turned into frameworks
function createXCFrameworkForStaticLibrary {

  LIBRARY_ARCHIVE_PATH_POSTFIX=".xcarchive/Products/usr/local/lib"
  LIBRARY_SIMULATOR_DIR="$(archivePathSimulator $1)${LIBRARY_ARCHIVE_PATH_POSTFIX}"
  LIBRARY_DEVICE_DIR="$(archivePathDevice $1)${LIBRARY_ARCHIVE_PATH_POSTFIX}"

  xcodebuild -create-xcframework \
            -library ${LIBRARY_SIMULATOR_DIR}/libStaticLibrary.a \
            -library ${LIBRARY_DEVICE_DIR}/libStaticLibrary.a \
            -output ${OUTPUT_DIR_PATH}/xcframeworks/${1}.xcframework
}

echo "#####################"
echo "▸ Cleaning the dir: ${OUTPUT_DIR_PATH}"
rm -rf $OUTPUT_DIR_PATH

#### Dynamic Framework ####

DYNAMIC_FRAMEWORK="${PROJECT_NAME}"

echo "▸ Archive $DYNAMIC_FRAMEWORK"
buildArchive ${DYNAMIC_FRAMEWORK}

echo "▸ Create $DYNAMIC_FRAMEWORK.xcframework"
createXCFramework ${DYNAMIC_FRAMEWORK}

The above script build XCFramework for two architectures: generic/platform=iOS Simulator and generic/platform=iOS; saving to your project folder while assuming your framework scheme has the same name with project name.

Visit Gist

Using Carthage

While XCFramework is not fully supported, you can currently build XCFramework with this script:

carthage build --platform iOS --no-skip-current --create-xcframework

Follow this issue request on Carthage GitHub for future updates

Top comments (0)