At last, in Swift 5.3, the updated Swift Package Manager (SPM) now supports resources! Yipee~
This post is a guide to adding resources to your package.
1. Add to Target
The convention is to add them in a “Resources” subfolder for the target. So if you have a target called MyTarget
, you will add resources to
/Sources/MyTarget/Resources/
But you could actually add to anywhere in “MyTarget”.
2. Edit Package.swift
Add defaultLocalization
to the package descriptor.
let package = Package(
name: "MyPackage",
defaultLocalization: "en",
...)
3. Implicit & Explicit Resources
Xcode automatically recognize for these known resources:
- XIB, storyboards
- Core Data xcdatamodeld
- Asset Catalogs
- strings files
.lproj
So for the above known resources, there is nothing else to do.
For for other resources, you need to declare them explicitly.
targets: [
.target(
name: "MyLibrary",
resources: [
.process("flu.jpg"),
.copy("pandemic.json") // Do NOT process
]
),
]
process
will have Xcode optimize the resource for the platform, while copy
will not.
4. Expose in the package
You should expose resources from within the package, instead of having the app accessing them directly. So let’s say you have this localized string “Okay”, you will publicly expose with
public let localizedOkay = NSLocalizedString("Okay", bundle: Bundle.module, comment: "")
There is something new here: Bundle.module
This is a generated code for the package (specifically the target)! Prior to this, we make use of Bundle(name:inFramework:)
.
You cannot (and it does not make sense) to use Bundle.module
in an app. Though it doesn’t stop you from exposing it with
public let bundleForMyTarget = Bundle.module
Then in the app, you can use NSLocalizedString("Okay", bundle: bundleForMyTarget, comment: "")
. Just suggesting.
PITFALL: App must add localization
Even if a package supports a certain localization, the app has to add it first under the app’s Project > Localizations.
It seems like Xcode will optimize and strip out localizations, if they are not supported in the app.
PITFALL: Bundle.module
If you tried to use Bundle.module
and runs into the following error:
Bundle ‘module’ is inaccessible due to ‘internal’ protection level
The reason could be that the target don’t have a “Resources”. Bundle.module
is automatically generated, but the package’s target must have at leat a resource in order for Xcode to generate.
The fix is simply creating a “Resources” folder in the target directory.