Analyzing a SPM Framework (iOS)
Due to technical and standardization requirements, Emerge Tools only supports analyzing frameworks packaged as xcframeworks. If you want to analyze your Swift Package Manager (SPM) framework, the easiest way is to build it using the script provided below:
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd -P)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
PROJECT_BUILD_DIR="${PROJECT_BUILD_DIR:-"${PROJECT_ROOT}/build"}"
XCODEBUILD_BUILD_DIR="$PROJECT_BUILD_DIR/xcodebuild"
XCODEBUILD_DERIVED_DATA_PATH="$XCODEBUILD_BUILD_DIR/DerivedData"
PACKAGE_NAME=$1
if [ -z "$PACKAGE_NAME" ]; then
echo "No package name provided. Using the first scheme found in the Package.swift."
PACKAGE_NAME=$(xcodebuild -list -workspace . | awk 'schemes && NF>0 { print $1; exit } /Schemes:$/ { schemes = 1 }')
echo "Using: $PACKAGE_NAME"
fi
backup_package_swift() {
cp Package.swift Package.swift.bak
}
restore_package_swift() {
mv Package.swift.bak Package.swift
}
modify_package_swift() {
sed -i '' 's/type: .static,//g' Package.swift
sed -i '' 's/type: .dynamic,//g' Package.swift
sed -i '' -e ':a' -e 'N' -e '$!ba' -e 's/\(library[^,]*name: [^,]*,\)/\1 type: .dynamic,/g' Package.swift
}
build_framework() {
local sdk="$1"
local destination="$2"
local scheme="$3"
local XCODEBUILD_ARCHIVE_PATH="./$scheme-$sdk.xcarchive"
rm -rf "$XCODEBUILD_ARCHIVE_PATH"
xcodebuild archive \
-scheme $scheme \
-archivePath $XCODEBUILD_ARCHIVE_PATH \
-derivedDataPath "$XCODEBUILD_DERIVED_DATA_PATH" \
-sdk "$sdk" \
-destination "$destination" \
-workspace . \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
INSTALL_PATH='Library/Frameworks' \
OTHER_SWIFT_FLAGS=-no-verify-emitted-module-interface
FRAMEWORK_MODULES_PATH="$XCODEBUILD_ARCHIVE_PATH/Products/Library/Frameworks/$scheme.framework/Modules"
mkdir -p "$FRAMEWORK_MODULES_PATH"
cp -r \
"$XCODEBUILD_DERIVED_DATA_PATH/Build/Intermediates.noindex/ArchiveIntermediates/$scheme/BuildProductsPath/Release-$sdk/$scheme.swiftmodule" \
"$FRAMEWORK_MODULES_PATH/$scheme.swiftmodule"
# Delete private swiftinterface
rm -f "$FRAMEWORK_MODULES_PATH/$scheme.swiftmodule/*.private.swiftinterface"
}
echo "Modifying Package.swift"
backup_package_swift
modify_package_swift
build_framework "iphonesimulator" "generic/platform=iOS Simulator" "$PACKAGE_NAME"
build_framework "iphoneos" "generic/platform=iOS" "$PACKAGE_NAME"
echo "Builds completed successfully."
rm -rf "$PACKAGE_NAME.xcframework"
xcodebuild -create-xcframework -framework $PACKAGE_NAME-iphonesimulator.xcarchive/Products/Library/Frameworks/$PACKAGE_NAME.framework -framework $PACKAGE_NAME-iphoneos.xcarchive/Products/Library/Frameworks/$PACKAGE_NAME.framework -output $PACKAGE_NAME.xcframework
cp -r $PACKAGE_NAME-iphonesimulator.xcarchive/dSYMs $PACKAGE_NAME.xcframework/ios-arm64_x86_64-simulator
cp -r $PACKAGE_NAME-iphoneos.xcarchive/dSYMs $PACKAGE_NAME.xcframework/ios-arm64
zip -r "$PACKAGE_NAME.xcframework.zip" "$PACKAGE_NAME.xcframework"
echo "Restoring Package.swift"
restore_package_swift
This script will automatically detect the first product listed inside your Package.swift file. If your package contains multiple products, you can specify the desired product’s name as an argument:
sh buildXCFrameworkArchive.sh MY_PRODUCT_NAMEAfter running the script, you will have an xcframework located at the root of your project, named MY_PRODUCT_NAME.xcframework.
Example GitHub Actions Workflow
Github does provide 200 minutes of macOS runners for free, you can use them to build and upload your framework when generating a new version, like this:
- Create a new file called buildXCFramework.sh at the root of your project and add the previously shared script.
- Create a new file at
.github/workflows/release.ymland add the following content:
name: Build
on:
push:
branches: [main]
jobs:
build:
name: Build XCFramework
runs-on: macos-latest
env:
PRODUCT_NAME: MY_PRODUCT_NAME
steps:
- uses: actions/checkout@v4
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Build XCFramework
run: sh buildXCFrameworkArchive.sh $PRODUCT_NAME
- name: Upload artifact to Emerge
uses: EmergeTools/[email protected]
with:
build_type: release
artifact_path: ./${{ env.PRODUCT_NAME }}.xcframework.zip
emerge_api_key: ${{ secrets.EMERGE_API_KEY }}
- Replace
MY_PRODUCT_NAMEin the workflow with the actual name of your package. - Obtain your Emerge Tools API key. Follow the instructions in Uploading Basics to get your API key.
- Set the
EMERGE_API_KEYas a secret in your GitHub repository settings.
Now, whenever a new commit is pushed to the main branch, the workflow will automatically build and upload the new framework version to Emerge Tools.
Updated 9 months ago
