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
Answers
To answer your questions:
Q1. I think what makes SPM choose to embed the ffmpegkit.xcframework framework but not the others is most likely because SPM treats each binaryTarget as an isolated framework and doesn’t attempt to look inside the .xcframework to resolve any additional dependencies (such as the libav* frameworks). It only includes the main framework specified in your Package.swift. In this case, ffmpegkit.xcframework is the only one explicitly listed, and thus the only one SPM included.
In short! I will say SPM does not go beyond what is directly specified.
Q2. To make SPM just use all the frameworks that are already packaged together. You need to explicitly declare all the dependent frameworks within your Package.swift file, even if they are contained inside the main ffmpegkit.xcframework. SPM doesn’t resolve these internal dependencies on its own, so you must include all the necessary .xcframework files as separate binaryTargets.
Let me give an instance of how you can modify the
Package.swift
to include all of the dependent frameworksAdded each
.xcframework
as abinaryTarget
: I included each of the 7 additional frameworks (libavcodec
,libavdevice
, etc.) as abinaryTarget
with its own URL and checksum.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:
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:
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:
2 – Create the Package.swift file with the content above inside the FFmpegKit folder.
3 – In Xcode:
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:
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.