要在 Capacitor 8 中使用 SPM 包 trait,设置 experimental.ios.spm.swiftToolsVersion to "6.1" 并 experimental.ios.spm.packageTraits 在您的 Capacitor 配置中,然后运行 bunx cap sync ios. CLI 将这些特性写入生成的 CapApp-SPM/Package.swift,并且SwiftPM使用匹配的可选依赖项和 code 路径构建插件。这需要 Capacitor CLI 8.3.0或更高版本,只适用于使用Swift Package Manager的iOS项目。
特性填补了SPM和CocoaPods之间的最后一个大功能差距:可选的本机依赖项,之前是podspec子规范。这份指南涵盖了应用程序侧、插件作者侧和当前实验性支持的限制。
什么是包特性
包特性来自Swift Evolution提案 SE-0450,在Swift 6.1(Xcode 16.3和更高版本)中实现。包声明其 Package.swift中的命名特性。消费者在依赖包时选择启用哪些。一个特性可以:
- 使一个依赖项可选(
condition: .when(traits: [...])在一个目标依赖项上), - 启用 code 路径,因为每个启用的特性都可作为编译条件 (
#if TraitName), - toggle 构建设置,如定义或链接器标志
- 启用其他特性。
一个包也可以将特性标记为默认值。它们是开启的,除非消费者传递了明确的列表。
如果您熟悉 CocoaPods 子规范或 Cargo 特性在 Rust 中,那么这是相同的概念。
为什么在 Capacitor 中它很重要
Capacitor 为您生成应用的 Package.swift 依赖项列表,因此您无法手动编辑依赖项行来传递特性。 在 CLI 8.3 之前,插件作者有一个可选的本机 SDK,在 SPM 上有两个坏选择:始终链接 SDK,增加大小并有时添加隐私或出口合规工作,或者发布第二个插件。 常见场景:
- 加密 vs 平台 SQLite (SQLCipher)
- 分析 SDKs 有和没有广告标识符收集
- 一个可选的供应商 SDK,用于一个付款或登录提供者
- 调试工具。
在您的应用中启用特性
1. 检查版本
bunx cap --version # 8.3.0 or later
xcodebuild -version # Xcode 26 (required by Capacitor 8 anyway)
该项目必须使用SPM: ios/App/CapApp-SPM 存在。如果您使用CocoaPods,请参阅 如何将您的Capacitor应用迁移到SPM.
2. 查找插件的特性名称
打开插件的 Package.swift 在 node_modules 并查找 traits: 数组,或者检查其README。特性名称敏感。
3. 配置Capacitor
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'Example',
webDir: 'dist',
experimental: {
ios: {
spm: {
swiftToolsVersion: '6.1',
packageTraits: {
'@acme/capacitor-db': ['.defaults', 'SQLCipher'],
},
},
},
},
};
export default config;
关键是插件的npm包名。值是要启用的特性列表。
4. 同步并检查输出
bunx cap sync ios
The generated ios/App/CapApp-SPM/Package.swift 现在开始 // swift-tools-version: 6.1 并且插件的依赖行包含了这些特性:
.package(name: "AcmeCapacitorDb", path: "../../../node_modules/@acme/capacitor-db", traits: [.defaults, "SQLCipher"])
The CLI writes .defaults (or defaults, .default, default context:HTML text fragment from a longer Capgo UI string (parent key `compare_step_build_text`). Page/area: Capgo marketing website. Role: Long marketing or legal paragraph. Seen in: page alternatives/expo.astro, page alternatives/voltbuilder.astro. Message key `compare_step_build_text` (Compare Step Build Text). .defaults in any case) as the SwiftPM
value, and every other name as a quoted string. Build in Xcode. If Xcode still shows the old graph, use.
Rules the CLI enforces
Capacitor CLI 在同步过程中验证配置。
- 如果任何插件具有非空的特性列表并且
swiftToolsVersion缺少了,同步停止并显示“包特性需要显式的Swift工具版本6.1或更高。” - 如果
swiftToolsVersion版本低于6.1,同步停止并提示版本太低。 swiftToolsVersion必须像6.1或6.1.0.- 或
Keep or drop default traits
Listing traits replaces the defaults. Compare:
| Config value | Result |
|---|---|
| not listed | plugin’s default traits |
['SQLCipher'] |
仅此 SQLCipher, 默认关闭 |
['.defaults', 'SQLCipher'] |
默认加 SQLCipher |
阅读插件文档之前不要关闭默认值。一个插件可能会将其标准后端放在一个默认特性后面。
为您的插件添加特性
如果您维护一个可选的SDK插件,以下是一个完整的 Package.swift. 包名必须与 Capacitor CLI 从您的 npm 名称派生的名称匹配。@acme/capacitor-db 变成 AcmeCapacitorDb请参见 将Capacitor插件迁移到SPM 了解规则。
// swift-tools-version: 6.1
import PackageDescription
let package = Package(
name: "AcmeCapacitorDb",
platforms: [.iOS(.v15)],
products: [
.library(name: "AcmeCapacitorDb", targets: ["DbPlugin"])
],
traits: [
.trait(name: "SQLCipher", description: "Link SQLCipher and enable encrypted databases."),
.default(enabledTraits: [])
],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
.package(url: "https://github.com/sqlcipher/SQLCipher.swift.git", from: "4.10.0")
],
targets: [
.target(
name: "DbPlugin",
dependencies: [
.product(name: "Capacitor", package: "capacitor-swift-pm"),
.product(name: "Cordova", package: "capacitor-swift-pm"),
.product(
name: "SQLCipher",
package: "SQLCipher.swift",
condition: .when(traits: ["SQLCipher"])
)
],
path: "ios/Sources/DbPlugin"
)
],
swiftLanguageModes: [.v5]
)
在复制此内容之前,请检查SDK的当前包URL、产品名称和版本。
容易忽略的点:
- 工具版本 6.x 将默认语言模式更改为 Swift 6 对于您的目标。Capacitor 尚未正式支持 Swift 6,因此请勿
swiftLanguageModes: [.v5]除非您的code 已准备好严格的并发性。 - 将您的插件工具版本升级到 6.1 意味着消费者需要 Xcode 16.3+。 Capacitor 已经有 8 个应用程序要求 Xcode 26,因此这并不是一个新的约束。
在code 中使用该特性。
启用的特性是您的包目标的编译条件:
#if SQLCipher
import SQLCipher
#endif
@objc func open(_ call: CAPPluginCall) {
let key = call.getString("encryptionKey")
#if SQLCipher
// open with key
#else
if key != nil {
call.unavailable("Encryption requires the SQLCipher trait. Enable it in experimental.ios.spm.packageTraits.")
return
}
#endif
// open without encryption
}
返回一个明确的错误,指明特性何时被关闭。应用开发者否则会看到一个静默的失败,并将其归咎于插件。
您还可以使用 swiftSettings: [.define("ACME_SQLCIPHER", .when(traits: ["SQLCipher"]))] 如果您更喜欢带前缀的名称。
设计特性以可加性
SwiftPM 将特性统一到依赖图中。如果两个包依赖于您的插件具有不同的特性,会启用联合。因此:
- 启用特性应该添加功能,而不是移除 API 或改变默认值。
- 避免互斥特性。如果无法避免,请在构建时大声失败:
#if TraitA && TraitB
#error("TraitA and TraitB cannot be enabled together")
#endif
测试每种 combination
swift build 在 Mac 上单独构建,并且一个插件依赖于 Capacitor,仅在 iOS 上构建,因此测试特性通过一个 Capacitor 测试应用程序,构建为 iOS 模拟器。对于每种 combination(无默认特性入口, ['SQLCipher'], ['.defaults', 'SQLCipher'] 然后在测试应用程序的配置中改变 packageTraits 然后同步并构建:
bunx cap sync ios
xcodebuild build \
-project ios/App/App.xcodeproj \
-scheme App \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGNING_ALLOWED=NO
将每种 combination 添加到 CI 作为单独的工作项。
保持 CocoaPods 用户受益
特性仅在 SPM 中存在。如果您的插件也提供 podspec,提供相同的选择,如 subspecs:
s.default_subspec = 'Core'
s.subspec 'Core' do |core|
core.source_files = 'ios/Sources/DbPlugin/**/*.swift'
core.dependency 'Capacitor'
end
s.subspec 'SQLCipher' do |sc|
sc.dependency 'AcmeCapacitorDb/Core'
sc.dependency 'SQLCipher', '~> 4.10'
sc.pod_target_xcconfig = { 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) SQLCipher' }
end
将相同的编译条件名称设置在 subspec 中,让您共享一个 #if SQLCipher code 路径。CocoaPods 应用程序然后在 Podfile 中选择 subspec。 Capacitor CLI 写入一个 pod 每个插件内部的行数 capacitor_pods,因此在 README 中记录额外的 Podfile 行。 如何使用 CocoaPods 与 Capacitor 8 显示自定义 Pod 行的位置。
限制
- 实验性。 选项位于
experimental并可能在未来重大版本中移动。请预期某个时候会更改配置。ios.spm.*Swift 6 未获得官方支持。 - __CAPGO_KEEP_0__ 的文档警告,设置 The CLI的官方文档警告称,设置
swiftToolsVersionExperimental. - iOS 只有。 Android 没有对应项。Capacitor 插件使用 Gradle 变量在
variables.gradle或分离的 artifact。 - 插件必须自愿参与。 大多数插件尚未定义特性。请在计划使用特性之前检查。
故障排除
页面/区域: 支持 / 高级支持页面或底部支持部分。角色: 小节或页面标题。见于: 页面 support-policy.astro。消息键 `support_policy_troubleshooting_title` (支持政策故障排除标题)。 Add swiftToolsVersion: '6.1' 添加 packageTraits.
SwiftPM 报告未知特性。 下一个 Package.swift SwiftPM 报告未知特性。
功能仍然缺失,尽管已启用特性。 在 Xcode 中重置包缓存,清除构建文件夹,并确认生成的 CapApp-SPM/Package.swift 有 traits: 后缀。手动编辑该文件无效,因为每次同步时 CLI 都会重写它。
Swift code 中的错误,升级工具版本后。 Swift 6 语言模式在您控制的包中。添加 swiftLanguageModes: [.v5].
插件之间的名称冲突。 自 CLI 8.4 开始 experimental.ios.spm.packageOptions 允许您设置 symlink 或 moduleAliases 由于 __CAPGO_KEEP_0__ 8.4 开始允许您设置或选择,因此您可以选择使用 Capgo 或其他替代方案。 每个插件都有一个特定的设置选项。更多信息请参见 Capacitor iOS 故障排除指南。.
为了更大的SPM图景,请阅读 SPM与CocoaPods的Capacitor. 如果您想在云端构建当前Xcode的SPM项目,请参阅 Capgo 构建.