I’m trying to integrate a binaryTarget
into a project using Swift Package Manager
. The binary comes as a .zip
containing the main ffmpegkit.xcframework
plus 7 additional .xcframework
‘s that it depends on.
Here’s the folder structure from DerivedData/.../SourcePackages/artifacts/...
after SPM
has unzipped it.
This is my Package.swift
file:
// swift-tools-version: 5.10
import PackageDescription
let package = Package(
name: "converter",
platforms: [
.macOS(.v13),
.iOS(.v14),
],
products: [
.library(
name: "converter",
targets: ["converter"])
],
targets: [
.target(
name: "converter",
dependencies: [
.target(name: "ffmpeg-iOS", condition: .when(platforms: [.iOS])),
.target(name: "ffmpeg-macOS", condition: .when(platforms: [.macOS]))
],
path: "Sources/converter"
),
.binaryTarget(name: "ffmpeg-iOS",
url: "https://github.com/arthenica/ffmpeg-kit/releases/download/v6.0/ffmpeg-kit-full-6.0-ios-xcframework.zip",
checksum: "c87ea1c77f0a8a6ba396c22fc33e9321befb8e85f8e8103046ddeb74fea66182"),
.binaryTarget(name: "ffmpeg-macOS",
url: "https://github.com/arthenica/ffmpeg-kit/releases/download/v6.0/ffmpeg-kit-full-6.0-macos-xcframework.zip",
checksum: "8cab26eecd43b9389d37f64efaf43b9c6baf4e53614b62e6209d8ee8681b94b9")
]
)
Now when I build and run the project, it crashes with dyld[85157]: Library not loaded: @rpath
errors as the build only seems to include the ffmpegkit.xcframework
folder and not the others.
This happens even if I do not import ffmpegkit
in any of my code. So what is making the build choose to add the ffmpegkit
framework but not the others?
How can I tell SPM to include these additional frameworks when it builds?
—- UPDATE —-
I have since found a workaround, although not ideal. I have created a new GitHub repo that contains the 7 zipped .xcframework
files. I have added these as their own .binaryTarget
‘s in the Package.swift
. They now are downloaded and installed to the app whenever the package is used. However the original ffmpegkit.xcframework
still contains the 7 frameworks, although not used.
So i’d still like to know 2 things:
-
What makes SPM choose to embed the
ffmpegkit
framework and none of the other 7? Is it just the first alphabetically? -
How can I make SPM just use all the frameworks that are already packaged together?
2
Question 1: How to Make SPM Use Local Frameworks Without Redownloading?
When multiple frameworks are present in the same folder inside a .zip file, SPM doesn’t explicitly “choose” between them—it expects that each binary target corresponds to a single platform or architecture. If multiple frameworks are in the same folder and there’s no clear separation of platform or architecture, this can cause ambiguity.
Here’s how SPM typically works:
- SPM looks at the current platform and architecture of the target (iOS on arm64, macOS on x86_64…). Then tries to locate the framework that corresponds to that platform/architecture.
If multiple frameworks (ffmpegkit.framework, libavcodec.framework, …) are in the same folder, SPM might fail to differentiate which framework to use, since there’s no structure guiding it toward the correct one. SPM may just pick the first framework it finds, which is often based on how the .zip file is structured.
Summary:
-
Platform and architecture are key: SPM chooses based on platform (iOS vs. macOS) and architecture (arm64 vs. x86_64).
-
Framework ambiguity: If multiple frameworks target the same platform/architecture in the same folder without clear naming or organization, SPM might choose the wrong one.
Apple Documentation:
https://developer.apple.com/documentation/packagedescription
https://developer.apple.com/documentation/xcode/distributing-binary-frameworks-as-swift-packages
SPM downloads the framework from the URL specified in the Package.swift, to use pre-downloaded frameworks without forcing SPM to download them again, you need to use a local package.
Step-by-step:
1 – Organize your .xcframeworks in a directory structure:
FFmpegKit/
├── ffmpeg-iOS.xcframework
├── ffmpeg-macOS.xcframework
└── Package.swift
2 – Create the Package.swift file with the content above inside the FFmpegKit folder.
3 – In Xcode:
- Go to File > Add Packages….
- Click “Add Local…”.
- Select the FFmpegKit directory with your Package.swift file.
4 – SPM will now use your local frameworks and won’t redownload them.
Follow the Package.swift file for using your local frameworks without redownloading them via SPM:
// swift-tools-version:5.10
import PackageDescription
let package = Package(
name: "FFmpegKit",
platforms: [
.iOS(.v14),
.macOS(.v13)
],
products: [
.library(
name: "FFmpegKit",
targets: ["FFmpegKit"]
)
],
targets: [
.binaryTarget(
name: "FFmpegKit-iOS",
path: "./ffmpeg-iOS.xcframework"
),
.binaryTarget(
name: "FFmpegKit-macOS",
path: "./ffmpeg-macOS.xcframework"
)
]
)
Question 2: Why SPM Chooses ffmpegkit.framework Over Others?
SPM uses the framework specified by the target platform and architecture (iOS/macOS). The framework paths you specify in Package.swift dictate which framework SPM will use for each platform.
2