SwiftPM can't dynamically link resources

I'm writing a tutorial about how to use SPM to create dynamic frameworks to share code between an app and plugins without the duplication in the final binary which comes from embedding static libraries into each target.

Initially, it seems like this is very simple, setting the library type to .dynamic:

let package = Package(
    name: ...,
    products: [
        .library(
            name: ...,
            type: .dynamic,
            targets: ...
        ),
    ],

This approach allows me to wrap my code and sub-dependencies in a .framework and reduces resource duplication.

However, when there are any resources in the package (such as an Assets library or JSON data), the compiled .app places these resources separately in a .bundle file, which is itself duplicated across both the app and its plugins.

It's possible to get the behaviour we want by using Xcode to manually create a framework that contains these assets, and manually importing and linking the framework to each target.

This is of course not optimal, not obvious, and appears to be a limitation (or bug?) in the way Swift Package Manager handles resources.

I'd love to know whether there is a better workaround; whether the Swift team is aware of the issue; and whether it's likely to be addressed. The scope of the problem is pretty high - there are many, many apps wasting many MB of space because of how unintuitive it is to create frameworks via SPM.

Thanks for reading and I look forward to your responses.

Update:

I found a working SPM-solution to the problem, that works, however it's a little painful.

A framework containing resources can be turned into an .xcframework for each architecture using xcodebuild commands, then imported as a binary framework to a SwiftPM wrapper module. This module can then be imported into a dynamic Swift package and behaves as we'd expect, with no duplication.

1 Like