I would like to ship my library using Apple's Swift Package Manager. However my lib includes a .bundle file with several strings translated in different languages. Using cocoapods, I can include it using spec.resource. But in SwiftPM, I cannot do it. Any solution?
6 Answers
The package manager does not yet have any definition for how resources will be bundled with targets. We are aware of the need for this, but don't yet have a concrete proposal for it. I filed https://bugs.swift.org/browse/SR-2866 to ensure we have a bug tracking this.

- 3,465
- 1
- 21
- 13
-
There's now a draft proposal for this: https://forums.swift.org/t/draft-proposal-package-resources/2994 – Klaas Nov 06 '19 at 21:00
-
1Slight typo above, draft proposal is https://forums.swift.org/t/draft-proposal-package-resources/29941 – lewis Nov 07 '19 at 09:47
-
1Looks like the proposal [passed](https://forums.swift.org/t/accepted-with-modifications-se-0271-package-manager-resources/31021) as [SE-0271](https://github.com/apple/swift-evolution/blob/master/proposals/0271-package-manager-resources.md). Still needs to be implemented though. – John M. Dec 02 '19 at 22:56
-
4Update : It is coming for sure with Swift 5.3 released somewhere between May & September 2020. https://forums.swift.org/t/se-0271-package-manager-resources/30730/74 – Bioche Apr 05 '20 at 10:12
Using Swift 5.3 it's finally possible to add localized resources
The Package initializer now has a defaultLocalization
parameter which can be used for localization resources.
public init(
name: String,
defaultLocalization: LocalizationTag = nil, // New defaultLocalization parameter.
pkgConfig: String? = nil,
providers: [SystemPackageProvider]? = nil,
products: [Product] = [],
dependencies: [Dependency] = [],
targets: [Target] = [],
swiftLanguageVersions: [Int]? = nil,
cLanguageStandard: CLanguageStandard? = nil,
cxxLanguageStandard: CXXLanguageStandard? = nil
)
Let's say you have an Icon.png
which you want to be localised for English and German speaking people.
The images should be included in Resources/en.lproj/Icon.png
& Resources/de.lproj/Icon.png
.
After you can reference them in your package like that:
let package = Package(
name: "BestPackage",
defaultLocalization: "en",
targets: [
.target(name: "BestTarget", resources: [
.process("Resources/Icon.png"),
])
]
)
Please note LocalizationTag
is a wrapper of IETF Language Tag.
Credits and input from following proposals overview, please check it for more details.

- 8,770
- 2
- 50
- 71

- 8,132
- 4
- 50
- 71
-
1How would I access a resource within a Swift Package assuming the above is followed? Ex: Parent app has a Swift package "ImageHelper" and I want to access a specific image resource within from the parent app, how is this done? Bundle.Something.path? – Jerland2 Jun 24 '20 at 02:14
Due to framework bundles not being supported yet, the only way to provide bundle assets with an SPM target is through a Bundle. If you implement code in your framework to search for a particular bundle in your main project (supporting asset bundles), you can load resources from said bundle.
Example:
Access the bundled resources:
extension Bundle {
static func myResourceBundle() throws -> Bundle {
let bundles = Bundle.allBundles
let bundlePaths = bundles.compactMap { $0.resourceURL?.appendingPathComponent("MyAssetBundle", isDirectory: false).appendingPathExtension("bundle") }
guard let bundle = bundlePaths.compactMap({ Bundle(url: $0) }).first else {
throw NSError(domain: "com.myframework", code: 404, userInfo: [NSLocalizedDescriptionKey: "Missing resource bundle"])
}
return bundle
}
}
Utilize the Bundled resources:
let bundle = try! Bundle.myResourceBundle()
return UIColor(named: "myColor", in: bundle, compatibleWith: nil)!
You can apply the same logic for all resource files, including but not limited to storyboards, xibs, images, colors, data blobs, and files of various extensions (json, txt, etc).
Note: Sometimes this makes sense, sometimes it doesn't. Determine use to own project's discretion. It would take very specific scenarios to justify separating Storyboards/Xibs into bundled assets.

- 5,987
- 8
- 76
- 112

- 3,436
- 4
- 30
- 53
starting on Swift 5.3, thanks to SE-0271, you can add bundle resources on swift package manager by adding resources
on your .target
declaration.
example:
.target(
name: "HelloWorldProgram",
dependencies: [],
resources: [.process(Images), .process("README.md")]
)
if you want to learn more, I have written an article on medium, discussing this topic

- 634
- 5
- 12
The solution I use for this is to build the data I need into a Swift object. To this end I have a shell script that will read an input file, base64 encode it, then write a Swift file that presents it as an InputStream. Then, when I want to add a data item to my Swift package, I run the script to read the file and write the output file. Of course the output file needs to be checked in so that the resource is available to those who use the project even if they do not have the script. (Typically I place my input files in a Resources
directory and write the output to the Sources
directory, but the script itself does not depend on that.)
I consider this a less than ideal solution, and am looking forward to when the package manager has this ability built in. But in the meantime, it is a workable solution.
The following example shows how it is used:
First, here is the script itself:
#!/usr/bin/env bash
# Read an input file, base64 encode it, then write an output swift file that will
# present it as an input stream.
#
# Usage: generate_resource_file.sh <inputfile> <outputfile> <streamName>
#
# The <streamName> is the name presented for the resulting InputStream. So, for example,
# generate_resource_file.sh Resources/logo.png Sources/Logo.swift logoInputStream
# will generate a file Sources/Logo.swift that will contain a computed variable
# that will look like the following:
# var logoInputStream: InputStream { ...blah...
#
set -e
if [ $# -ne 3 ]; then
echo "Usage: generate_resource_file.sh <inputfile> <outputfile> <streamName>"
exit -1
fi
inFile=$1
outFile=$2
streamName=$3
echo "Generating $outFile from $inFile"
echo "Stream name will be $streamName"
if [ ! -f "$inFile" ]; then
echo "Could not read $inFile"
exit -1
fi
echo "// This file is automatically generated by generate_resource_file.sh. DO NOT EDIT!" > "$outFile"
echo "" >> "$outFile"
echo "import Foundation" >> "$outFile"
echo "" >> "$outFile"
echo "fileprivate let encodedString = \"\"\"" >> "$outFile"
base64 -i "$inFile" >> "$outFile"
echo "\"\"\"" >> "$outFile"
echo "" >> "$outFile"
echo "var $streamName: InputStream {" >> "$outFile"
echo " get {" >> "$outFile"
echo " let decodedData = Data(base64Encoded: encodedString)!" >> "$outFile"
echo " return InputStream(data: decodedData)" >> "$outFile"
echo " }" >> "$outFile"
echo "}" >> "$outFile"
echo "Rebuilt $outFile"
Then, given an input file t.dat
shown here:
Hello World!
Running the command generate_resource_file.sh t.dat HelloWorld.swift helloWorldInputStream
generates the following HelloWorld.swift
file:
// This file is automatically generated by generate_resource_file.sh. DO NOT EDIT!
import Foundation
fileprivate let encodedString = """
SGVsbG8gV29ybGQhCgo=
"""
var helloWorldInputStream: InputStream {
get {
let decodedData = Data(base64Encoded: encodedString)!
return InputStream(data: decodedData)
}
}

- 1,401
- 12
- 26
-
1Now that Swift Package Manager supports this in a nicer framework, you should no longer use my solution (unless of course you have to support a legacy version for some reason). Instead you should use the solution posted by @bilalreffas. – Steven W. Klassen Dec 03 '20 at 00:37
Important note:
Resources doesn't seem to be included in the Xcode project generated by
swift package generate-xcodeproj
But they are when you open the Package folder on Xcode (xed .
) and then double click on the package to resolve dependencies.
I'm including a nice tutorial as well: https://medium.com/better-programming/how-to-add-resources-in-swift-package-manager-c437d44ec593

- 2,519
- 26
- 23