So far, I have learnt four ways of adding frameworks, manually, CocoaPods, Carthage and Swift Package Manager. This article is a summary of how to creating your own Swift Packages.
What is Swift Package?
A Swift Package is a bundle of source files with a meaningful name.
Platform
If unspecified, Swift Package works in all versions of Apple Operation Systems, this make a lot of version warnings. So a better idea is to provide the platform your package could work with.
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyAppStore",
platforms: [
.macOS(.v11)
],
Dependencies
Adding dependencies is easy. However, you must added the dependencies to both targets and test targets.
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyAppStore",
platforms: [
.macOS(.v11)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "MyAppStore",
targets: ["MyAppStore"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "git@github.com:owenzhao/QRCodeKit.git", Package.Dependency.Requirement.branch("1.0.0")),
.package(url: "git@github.com:weichsel/ZIPFoundation.git", "0.9.12"..<"1.0.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "MyAppStore",
dependencies: ["QRCodeKit", "ZIPFoundation"]),
.testTarget(
name: "MyAppStoreTests",
dependencies: ["MyAppStore", "QRCodeKit", "ZIPFoundation"]),
]
)
Versioning
For versioning, there is a trick. There is no where in the swift part to set the version of your package. The version is set by git tag. So you need to do the versioning in your git tool.
Resources
Swift Packages can get some kinds of sources as resources automatically, but you may also need to add sources manually.
You can add them as files one by one. Or you can add the folder directly. If you use process
, Xcode maybe take further optimization to the resources. If you want to keep them unchanged, you can use copy
.
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "MyAppStore",
dependencies: ["QRCodeKit", "ZIPFoundation"],
resources: [
.process("icons"),
.process("AllApps.zip")
]),
Localization
Add default localizedation in Package.swift
let package = Package(
name: "MyAppStore",
defaultLocalization: "en",
platforms: [
.macOS(.v11),
.iOS(.v14)
],
You must use genstrings
to get localized strings.
- Go to the directory of swift files.
- Create a directory named
en.lpproj
.
- Run code
find ./ -name "*.swift" -print0 | xargs -0 genstrings -o en.lproj
.
- Copy
en.lpproj
as the name of you intent, say zh.lpproj
.
- Translate the localized strings under
zh.lpproj
.
$ tree
.
├── AppInfoSwiftUIView.swift
├── MainSwiftUIView.swift
├── en.lproj
│ └── Localizable.strings
└── zh.lproj
└── Localizable.strings
Using String resources in Swift Packages
Swift Package is built alone with the main bundle, it is called module Bundle, so you have to explicitly tell the bundle by name, or the system will try to find the string resources in the main bundle.
Button(action: download, label: {
Text("Download", bundle: .module)
})
You should also notice that there are still some subtle issues. I found that the lang.lpproj
directories must be under the target directory directly, or the preview won't take the environment
effect.
However, running app goes fine whenever the directory goes.
References