mcpField
C
capacitor-plugin-spm-support

capacitor-plugin-spm-support

github.com/cap-go开发75728 次安装2 周前更新
代码仓库

关于 capacitor-plugin-spm-support

capacitor-plugin-spm-support 是一项技能,指导在保留 CocoaPods 支持的同时,为 Capacitor 插件添加 Swift Package Manager 支持,涵盖源码转换、包配置和验证。

主要功能

  1. 01SPM 清单与目标配置
  2. 02转换 Swift 插件注册
  3. 03保留 CocoaPods podspec
  4. 04配置依赖与资源
  5. 05验证软件包和应用

适用场景

  1. 01让插件可安装于基于 SPM 的应用
  2. 02处理缺少 Package.swift 的警告
  3. 03准备面向 Capacitor 9 的插件分发
  4. 04检查 SPM 与 CocoaPods 构建

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-plugin-spm-support

安装后在 Claude Code 中输入/capacitor-plugin-spm-support确认已加载。

附带文件metadata.jsonreferences/package-swift-templates.md

详细介绍

为 Capacitor 插件添加 Swift Package Manager 支持

让插件可安装到基于 SPM 的 Capacitor 应用中,同时为 CocoaPods 应用保留其 podspec。

适用场景

在以下情况下触发:

  • 插件仓库包含 ios/Plugin/*.swift 和 *.m/*.h,其中有 CAP_PLUGIN(...),且根目录没有 Package.swift。
  • 用户维护的插件在应用执行 npx cap sync ios 时,输出 <plugin id> does not have a Package.swift。
  • 插件在 CocoaPods 中运行正常,但在 SPM 应用中,JS 收到 "X" plugin is not implemented on ios。
  • 为 Capacitor 9 / CocoaPods Trunk 只读做好插件准备。

不要用于:

  • 应用侧移除 CocoaPods → cocoapods-to-spm。
  • 插件的 Capacitor 主版本升级 → capacitor-plugin-upgrades、capacitor-plugin-upgrade-v8-to-v9。
  • 仅涉及 Android 的插件工作,或非 Capacitor 插件(纯 Cordova、React Native)。

CLI 强制执行的规则(容易忽略)

  • Package.swift 必须位于 npm 包根目录(与 package.json 同级),而不能放在 ios/ 下。应用 CLI 只会检查 <plugin root>/Package.swift。
  • CLI 会在应用的 CapApp-SPM/Package.swift 中以 .package(name: "<Name>", path: ...) 和 .product(name: "<Name>", package: "<Name>") 引用插件,其中 <Name> 根据 npm 名称生成:去掉 @,将 / 和 - 转换为单词分隔符,再转为 PascalCase。@capgo/capacitor-updater -> CapgoCapacitorUpdater,@acme/capacitor-foo-bar -> AcmeCapacitorFooBar。Package(name:) 和 .library(name:) 产品都必须等于 <Name>,否则应用构建时无法解析该产品。
  • 运行时注册使用 ios/App/App/capacitor.config.json 中的 packageClassList,该列表通过扫描插件的 iOS 源文件(package.json 中的 capacitor.ios.src,默认为 ios)并查找 @objc(ClassName) 来填充。请在类上保留 @objc(<Class>Plugin);没有它,插件就永远不会注册。
  • capacitor-swift-pm 依赖必须使用 from: "<major>.0.0"。如果主版本与应用中的 Capacitor 不同,应用同步会在 node_modules 中重写该版本,并警告 <id> is built for Capacitor <N>, it might cause issues。
  • Capacitor 9:只依赖 .product(name: "Capacitor", package: "capacitor-swift-pm")。移除无条件添加的 Cordova 产品;该产品仅存在于安装了 Cordova 插件的应用中。只有当代码导入 Cordova 时,才在 Capacitor 8 中保留它。

操作步骤

1. 检查

阅读 package.json(名称、files、capacitor.ios.src、脚本)、.podspec(s.name、s.ios.deployment_target、s.dependency、s.resources、s.vendored_frameworks)、ios/ 中的每个文件,以及 .m 文件中的 CAP_PLUGIN(...) 宏。

记录:SPM <Name>(按上述规则)、类名、jsName、每个 CAP_PLUGIN_METHOD(name, returnType)、iOS 部署目标、第三方 pod、资源、供应商提供的框架,以及桥接文件以外的 ObjC/C 源文件。

检查每个第三方 pod 是否有官方 SPM 包。编辑前报告没有官方 SPM 包的依赖;询问是要移除、作为 .xcframework 引入,还是让插件仅支持 CocoaPods。

2. 快速路径:转换器

如果 iOS 代码除 [Name]Plugin.m / .h 桥接文件外仅包含 Swift,官方转换器即可完成大部分工作(添加 CAPBridgedPlugin、创建 Package.swift、将代码移至 ios/Sources 和 ios/Tests、移除 Plugin.xcodeproj/xcworkspace/Podfile,更新 podspec 中的 source_files、files 和 verify:ios):https://github.com/ionic-team/capacitor-plugin-converter。根据上述规则检查其差异,尤其要检查包名和产品名。

3. 手动转换
  1. 移动源文件:ios/Plugin/ -> ios/Sources/<ClassName>/,测试文件 -> ios/Tests/<ClassName>Tests/。
  2. 转换该类(方法名和返回类型必须与 .m 宏中的完全一致):
    import Capacitor
    
    @objc(FooPlugin)
    public class FooPlugin: CAPPlugin, CAPBridgedPlugin {
        public let identifier = "FooPlugin"     // first CAP_PLUGIN argument
        public let jsName = "Foo"               // second CAP_PLUGIN argument (registerPlugin name)
        public let pluginMethods: [CAPPluginMethod] = [
            CAPPluginMethod(name: "doThing", returnType: CAPPluginReturnPromise),
            CAPPluginMethod(name: "watch", returnType: CAPPluginReturnCallback),
            CAPPluginMethod(name: "fireAndForget", returnType: CAPPluginReturnNone)
        ]
        @objc func doThing(_ call: CAPPluginCall) { call.resolve() }
    }
    
  3. 删除 FooPlugin.m 和 FooPlugin.h(CAP_PLUGIN 桥接文件),以及 ios/ 下过时的 Plugin.xcodeproj、Plugin.xcworkspace、Podfile、Info.plist 文件。
  4. 添加根目录下的 Package.swift。模板和变体(资源、二进制目标、第三方包、混合 ObjC)见 references/package-swift-templates.md。
  5. 更新 podspec:s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}',保留 s.dependency 'Capacitor',并同步部署目标和资源配置。
  6. 更新 package.json:
    • files:添加 ios/Sources/、Package.swift;保留 .podspec;移除旧的 ios/Plugin/。
    • verify:ios:xcodebuild -scheme <Name> -destination generic/platform=iOS。

验证

# Package resolves and builds standalone (from plugin root)
swift package describe >/dev/null && echo "manifest ok"
xcodebuild -scheme <Name> -destination generic/platform=iOS build
# Published tarball contains the manifest and sources
npm pack --dry-run 2>&1 | grep -E 'Package.swift|ios/Sources'
# No leftover ObjC bridge
grep -rn "CAP_PLUGIN(" ios/ && echo "LEFTOVER BRIDGE"

然后在 SPM 示例/测试应用中(包含 capacitor.config.* 的目录):安装插件(npm install ../path 或已打包的 tarball),运行 npx cap sync ios,确认没有 does not have a Package.swift 警告,确认 <Name> 出现在 ios/App/CapApp-SPM/Package.swift 中,且该类出现在 ios/App/App/capacitor.config.json 的 packageClassList 中,进行构建,并从 JS 调用一个方法。如果 podspec 仍在发布,也要运行 pod lib lint(或使用 CocoaPods 示例应用)。

错误处理

错误修复方法
product '<Name>' required by package 'capapp-spm' target 'CapApp-SPM' not found in package '<Name>'Package(name:) / .library(name:) 与 CLI 推导出的 <Name> 不匹配。
"Foo" plugin is not implemented on ios缺少 @objc(FooPlugin)、jsName 错误,或类不在 packageClassList 中;修复后重新同步。
"Foo.bar()" is not implemented on ios方法缺少 pluginMethods 声明,或未标记为 @objc。
No such module 'Capacitor' building the package缺少 capacitor-swift-pm 依赖,或产品名称错误。
public headers ("include") directory path for 'X' is invalid or not contained in the target混合 ObjC 目标未设置 publicHeadersPath;将 ObjC 拆分到单独的目标中(见参考资料)。
<id> is built for Capacitor <N>, it might cause issues (in app)将 capacitor-swift-pm 的 from: 升级到与应用相同的主版本。
Cordova product missing (Capacitor 9 app)移除 Cordova 产品依赖。
运行时找不到资源声明 resources: 并通过 Bundle.module 而非 Bundle.main 加载。

参考资料

仅在涉及相关主题时加载:

  • references/package-swift-templates.md:基础清单、资源和隐私清单、第三方 SPM 依赖、二进制 .xcframework、混合 Swift/ObjC 目标、Capacitor 8 与 9 的依赖配置块。

评论

支持 Markdown