Swift Packages with Resources, but never added to app

Good Evening,

I made a Package which has defined a class and some resources. Defined class uses those resources.

 Package
 Sources
   ┝ UnicodeData
   |    ┝ flatUnicode.txt
   |    ┕ glyphNames.txt
   ┕ UnicodeNames
         ┕ UnicodeNames.swift

In package manifest they are defined as:

       ....
       targets: [
            .target(
                name: "UnicodeNames",
                resources: [
                    .copy("UnicodeData")]
            ),
       ....

I call resources from class by:

        let bundle = Bundle(for: Self.self)
        if let myResource = bundle.path(forResource: "flatUnicode", ofType: "txt")  {
        ....

I can add package to an application, it is visible under Frameworks, Libraries and Embedded Content and Package Dependency. I can compile it and run, but resources are never found and app crashes. When I'm looking inside an app (Show Package Content from Finder, resources delivered by package do not exist inside)

How to copy resources from a Package to an App?

First, .copy("UnicodeData") does not match path(forResource: "flatUnicode", ofType: "txt") (i.e. UnicodeDataflatUnicode.txt).

Second, the bundle you are looking for is Bundle.module, not anything locatable with Bundle(for:). The resources will not necessarily be placed the same bundle as either the code or the main application.

Additionally, in case the names you posted are just placeholders, note that resource names which differ between NFC and NFD seem not to work on some platforms (i.e. ή is a problem but η is not). Whether the bug is in Xcode or in Foundation I do not know.

UnicodeData is a folder with flatUnicode.txt file inside. As I found in documentation .copy copies whole content of a folder with no change. Yes - UnicodeDataflatUnicode.txt.

Bundle.module exist in story about Bundle, but not documentation and API anymore, I found Bundle(for: as a replacement.

I use only ascii for file names.

And don't plan to move with this package outside of macOS for a while.

I'm not sure what the documentation should be saying, but Bundle.module is added by the package manager as an extension of Bundle when you build a module. The module property doesn't exist on Bundle unless SwiftPM is building a package with resources, and thus it's not exactly part of the Bundle API but part of SwiftPM, which probably explains why it's not in Bundle's documentation.

As for Bundle(for:) that takes a class, note that SwiftPM will link the library statically, so the compiled code and that class will become part of the main executable. Meanwhile the resources are put in a separate resource bundle (I assume to avoid potential clashes in file names), so you really have to use Bundle.module as provided by SwiftPM to get to the resources.

1 Like

You can find the name that Xcode had given the Package’s bundle by right clicking on the ‘.app’, click show package contents, and then navigating to Contents/Resources and looking inside (if it’s a macos app). On iOS bundles are either in the root of the app or in ./Resources, i can’t quite remember which. If Xcode only has an ipa you can rename it to a .zip and extract it iirc. All of that could be wrong cause im just going from memory. If it doesn’t work I’ll check my code that uses bundles to actually check for you. Hopefully that helps