Swift 6.1 Package Traits:让依赖管理更灵活
Swift 6.1 引入的 Package Traits 为 Swift Package Manager 带来了更灵活的条件编译和可选依赖管理能力。
为什么需要它?
实际开发中经常遇到这些问题:
- 可插拔依赖:比如 Swift OpenAPI Generator 支持 URLSession、AsyncHTTPClient、Vapor 等多种传输层。为了不把全部依赖都打进二进制,往往要拆成多个仓库,维护和发现都麻烦。
- 平台差异:Apple 平台用 OSLog,服务器端用 swift-log,需要一种优雅的方式来处理这种差异。
- 实验性 API:想发布新功能但又不想承诺稳定 API,加下划线或特殊注解会影响代码补全,不够理想。
基本用法
在 Package.swift 中定义特性:
let package = Package(
name: "MyLibrary",
traits: [
"Logging",
.trait(name: "Networking", enabledTraits: ["Logging"]),
.default(enabledTraits: ["Logging"])
],
)
上面定义了两个特性:Logging 和 Networking。启用 Networking 时会自动启用 Logging,默认只开启 Logging。
依赖时指定特性:
dependencies: [
.package(url: "...", from: "1.0.0", traits: [.defaults, "Networking"]),
// 禁用所有特性(包括默认)
.package(url: "...", from: "1.0.0", traits: []),
]
也可以根据当前包的特性条件化开启依赖的特性:
dependencies: [
.package(url: "...", from: "1.0.0", traits: [
.trait(name: "AdvancedLogging", condition: .when(traits: ["Debug"]))
]),
]
实战示例:主题色 UI 库
// swift-tools-version: 6.3
import PackageDescription
let package = Package(
name: "MyLibraryTest",
products: [.library(name: "MyLibraryTest", targets: ["MyLibraryTest"])],
traits: [
.trait(name: "Red"),
.trait(name: "White"),
.trait(name: "Blue"),
.trait(name: "Yellow"),
.default(enabledTraits: ["Blue"])
],
targets: [
.target(
name: "MyLibraryTest",
cSettings: [
.define("SHAULA_RED", .when(traits: ["Red"])),
.define("SHAULA_WHITE", .when(traits: ["White"])),
.define("SHAULA_BLUE", .when(traits: ["Blue"])),
.define("SHAULA_YELLOW", .when(traits: ["Yellow"])),
]
),
]
)
客户端包可以按需覆盖默认主题:
dependencies: [
.package(path: "../../", traits: ["Red", "Yellow"])
]
条件编译
在代码中用 #if 检查特性:
#if Blue
import BlueTheme
#endif
func applyTheme() {
#if Red
ThemeManager.apply(.red)
#elseif Blue
ThemeManager.apply(.blue)
#else
ThemeManager.apply(.default)
#endif
}
命令行控制
swift build --traits Red,White # 启用指定特性
swift build --enable-all-traits # 启用所有
swift build --disable-default-traits # 禁用默认
几点建议
- 特性应该是累加的:启用一个特性不要移除其他 API。如果确实有互斥需求,用编译时错误检查:
#if Red && Blue #error("不能同时启用") #endif - 默认特性要谨慎:移除默认特性属于破坏性变更(SemVer major)。选大多数用户都会用的那个。
- 命名规范:符合 Swift 标识符规则,别用
default/defaults。用Networking、Crypto这类描述性名称。
小结
Package Traits 解决了长期困扰 Swift 包管理器的可选依赖和条件编译问题。合理使用可以让你的库更加灵活,为不同场景的用户提供最佳体验。