capacitor-plugin-spm-support
Skill75 starsChanged 32 days agoMITView on GitHub
Adds Swift Package Manager support to an existing Capacitor plugin repository so apps using CapApp-SPM can consume it after CocoaPods Trunk goes read-only (expected December 2, 2026). Covers root Package.swift naming rules the Capacitor CLI depends on, CAPBridgedPlugin conversion (identifier, jsName, pluginMethods), removing the ObjC CAP_PLUGIN bridge (.m/.h), Sources/Tests layout, podspec and package.json files updates, third-party pod to SPM dependency mapping, resources/PrivacyInfo.xcprivacy, binary xcframeworks, and Capacitor 9 removal of the unconditional Cordova product. Use when app sync warns "<plugin> does not have a Package.swift" for a plugin you own, or "plugin is not implemented on ios" only in SPM apps. Do not use for migrating an app project (use cocoapods-to-spm), version bumps of plugins (use capacitor-plugin-upgrades / capacitor-plugin-upgrade-v8-to-v9), or choosing plugins (use capacitor-plugins).
- Installs packages
2 other projects use a version of this.
Adopted by
Most recently taken up by
- capawesome-team/skillstheir own version, first seen Mar 24, 2026
- Aver005/agent-skillstheir own version, first seen Feb 14, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- capawesome-team/skills★ 54same name
- Aver005/agent-skills★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository56 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- capacitor-accessibilitySkill
- capacitor-app-intentsSkill
- capacitor-apple-review-preflightSkill
- capacitor-app-storeSkill
- capacitor-app-upgradesSkill
- capacitor-app-upgrade-v4-to-v5Skill
- capacitor-app-upgrade-v5-to-v6Skill
- capacitor-app-upgrade-v6-to-v7Skill
- capacitor-app-upgrade-v7-to-v8Skill
- capacitor-app-upgrade-v8-to-v9Skill
- capacitor-best-practicesSkill
- capacitor-ci-cdSkill
- capacitor-deep-linkingSkill
- capacitor-ios-resizabilitySkill
- capacitor-ios-security-hardeningSkill
- capacitor-keyboardSkill
- capacitor-mcpSkill
- capacitor-offline-firstSkill
- capacitor-performanceSkill
- capacitor-pluginsSkill
- capacitor-plugin-upgradesSkill
- capacitor-plugin-upgrade-v4-to-v5Skill
- capacitor-plugin-upgrade-v5-to-v6Skill
- capacitor-plugin-upgrade-v6-to-v7Skill
- capacitor-plugin-upgrade-v7-to-v8Skill
- capacitor-plugin-upgrade-v8-to-v9Skill
- capacitor-push-notificationsSkill
- capacitor-securitySkill
- capacitor-splash-screenSkill
- capacitor-testingSkill
- capacitor-uiscene-migrationSkill
- capawesome-live-update-migrationSkill
- capgo-cli-usageSkill
- capgo-cloudSkill
- capgo-live-updatesSkill
- capgo-native-buildsSkill
- capgo-organization-managementSkill
- capgo-release-managementSkill
- capgo-release-workflowsSkill
- cocoapods-to-spmSkill
- cordova-to-capacitorSkill
- debugging-capacitorSkill
- framework-to-capacitorSkill
- ionic-appflow-migrationSkill
- ionic-designSkill
- ionic-enterprise-sdk-migrationSkill
- ios-android-logsSkill
- konsta-uiSkill
- safe-area-handlingSkill
- skill-creatorSkill
- sqlite-to-fast-sqlSkill
- subscription-app-revenueSkill
- tailwind-capacitorSkill
- webapp-to-capacitorSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 35
Read package.json (name, files, capacitor.ios.src, scripts), the .podspec (s.name, s.ios.deployment_target, s.dependency, s.resources, …
- Very specific: line 39
Check each third-party pod has an official SPM package.
- Very specific: line 64
Delete FooPlugin.m and FooPlugin.h (the CAP_PLUGIN bridge) and stale Plugin.xcodeproj, Plugin.xcworkspace, Podfile, Info.plist files under …
- Very specific: line 65
Add root Package.swift. Template and variants (resources, binary targets, third-party packages, mixed ObjC) in …
- Very specific: line 66
Update the podspec: s.source_files = 'ios/Sources//*.{swift,h,m,c,cc,mm,cpp}', keep s.dependency 'Capacitor', and mirror deployment target …
- Distinctive: line 100
Only load when the topic is in play:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Add Swift Package Manager Support to a Capacitor Plugin
Make a plugin installable in SPM-based Capacitor apps while keeping its podspec for CocoaPods apps.
When to Use
TRIGGER when:
- A plugin repo has
ios/Plugin/*.swift+*.m/*.hwithCAP_PLUGIN(...)and no rootPackage.swift. - An app's
npx cap sync iosprints<plugin id> does not have a Package.swiftfor a plugin the user maintains. - A plugin works with CocoaPods but JS gets
"X" plugin is not implemented on iosin SPM apps. - Preparing a plugin for Capacitor 9 / CocoaPods Trunk read-only.
Do not use:
- App-side CocoaPods removal ->
cocoapods-to-spm. - Capacitor major bumps of a plugin ->
capacitor-plugin-upgrades,capacitor-plugin-upgrade-v8-to-v9. - Android-only plugin work, or non-Capacitor (pure Cordova, React Native) plugins.
Rules the CLI Enforces (non-obvious)
Package.swiftmust be at the npm package root (next topackage.json), not underios/. The app CLI only checks<plugin root>/Package.swift.- The CLI references the plugin in the app's
CapApp-SPM/Package.swiftas.package(name: "<Name>", path: ...)and.product(name: "<Name>", package: "<Name>"), where<Name>is derived from the npm name: drop@, turn/and-into word breaks, PascalCase.@capgo/capacitor-updater->CapgoCapacitorUpdater,@acme/capacitor-foo-bar->AcmeCapacitorFooBar. ThePackage(name:)and the.library(name:)product must both equal<Name>, or app builds fail to resolve the product. - Runtime registration uses
ios/App/App/capacitor.config.json->packageClassList, filled by scanning the plugin's iOS sources (capacitor.ios.srcin package.json, defaultios) for@objc(ClassName). Keep@objc(<Class>Plugin)on the class; without it the plugin is never registered. - The
capacitor-swift-pmdependency must usefrom: "<major>.0.0". If the major differs from the app's Capacitor, app sync rewrites it innode_modulesand warns<id> is built for Capacitor <N>, it might cause issues. - Capacitor 9: depend only on
.product(name: "Capacitor", package: "capacitor-swift-pm"). Remove the unconditionalCordovaproduct; it is only present in apps that install a Cordova plugin. Keep it on Capacitor 8 only if your code imports Cordova.
Procedure
1. Inspect
Read package.json (name, files, capacitor.ios.src, scripts), the .podspec (s.name, s.ios.deployment_target, s.dependency, s.resources, s.vendored_frameworks), every file in ios/, and the CAP_PLUGIN(...) macro in the .m file.
Record: SPM <Name> (rule above), class name, jsName, every CAP_PLUGIN_METHOD(name, returnType), iOS deployment target, third-party pods, resources, vendored frameworks, ObjC/C sources other than the bridge.
Check each third-party pod has an official SPM package. Report any that do not before editing; ask whether to drop, vendor as .xcframework, or keep the plugin CocoaPods-only.
2. Fast path: converter
If the iOS code is Swift-only apart from the [Name]Plugin.m / .h bridge, the official converter does most of the work (adds CAPBridgedPlugin, creates Package.swift, moves code to ios/Sources and ios/Tests, removes Plugin.xcodeproj/xcworkspace/Podfile, updates podspec source_files, files, and verify:ios): https://github.com/ionic-team/capacitor-plugin-converter. Review its diff against the rules above, especially the package/product name.
3. Manual conversion
- Move sources:
ios/Plugin/->ios/Sources/<ClassName>/, tests ->ios/Tests/<ClassName>Tests/. - Convert the class (keep method names and return types exactly as in the
.mmacro):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() } } - Delete
FooPlugin.mandFooPlugin.h(theCAP_PLUGINbridge) and stalePlugin.xcodeproj,Plugin.xcworkspace,Podfile,Info.plistfiles underios/. - Add root
Package.swift. Template and variants (resources, binary targets, third-party packages, mixed ObjC) inreferences/package-swift-templates.md. - Update the podspec:
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}', keeps.dependency 'Capacitor', and mirror deployment target and resources. - Update
package.json:files: addios/Sources/,Package.swift; keep the.podspec; remove oldios/Plugin/.verify:ios:xcodebuild -scheme <Name> -destination generic/platform=iOS.
Verification
# 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"Then in an SPM example/test app (directory with capacitor.config.*): install the plugin (npm install ../path or a packed tarball), run npx cap sync ios, confirm no does not have a Package.swift warning, confirm <Name> appears in ios/App/CapApp-SPM/Package.swift and the class appears in ios/App/App/capacitor.config.json packageClassList, build, and call one method from JS. Also run pod lib lint (or a CocoaPods example app) if the podspec is still published.
Error Handling
| Error | Fix |
product '<Name>' required by package 'capapp-spm' target 'CapApp-SPM' not found in package '<Name>' | Package(name:) / .library(name:) do not match the CLI-derived <Name>. |
"Foo" plugin is not implemented on ios | Missing @objc(FooPlugin), wrong jsName, or class not in packageClassList; re-sync after fixing. |
"Foo.bar()" is not implemented on ios | Method missing from pluginMethods or not marked @objc. |
No such module 'Capacitor' building the package | Missing capacitor-swift-pm dependency or wrong product name. |
public headers ("include") directory path for 'X' is invalid or not contained in the target | Mixed ObjC target without publicHeadersPath; split ObjC into its own target (see reference). |
<id> is built for Capacitor <N>, it might cause issues (in app) | Bump capacitor-swift-pm from: to the app's major. |
Cordova product missing (Capacitor 9 app) | Remove the Cordova product dependency. |
| Resource not found at runtime | Declare resources: and load via Bundle.module, not Bundle.main. |
References
Only load when the topic is in play:
references/package-swift-templates.md: base manifest, resources and privacy manifest, third-party SPM dependencies, binary.xcframework, mixed Swift/ObjC targets, Capacitor 8 vs 9 dependency blocks.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

