capacitor-release
Capacitor release pipeline
This skill owns the last mile: turning a feature-complete Ionic/Capacitor app into a signed artifact in TestFlight or a Play testing track, and deciding what ships over-the-air versus through a fresh store binary. The app itself - UI, lifecycle, permissions, plugin wrapping - is ionic; per-plugin install/config is fetched live (context7 / the plugin README); this file picks up where the build is done. Floored at Capacitor 6, current on 8 - prefer the 8 path and treat anything newer as optional. Native Swift / Kotlin source edits are out of scope: this skill configures the native projects (signing, versions, symbols), it does not write platform code - that boundary stays with the platform tooling, not the agent.
The artifact - sync then build
- The web build comes first, then the bridge copy, then the native build. Never build native off a stale
www/: runnpm run build->npx cap sync(copies web assets and updates native deps) -> the native build.cap syncis the step that makes the native shell match the code you just shipped. - Prefer
npx cap build ios/npx cap build android(stable, not experimental in 6+) for a one-shot signed artifact: iOS produces an.ipa, Android an.aab(default) or.apk. It wraps the platform tools so local and CI agree on flags. - In CI, or when you need archive control, drive the platform tools directly:
xcodebuild -workspace ios/App/App.xcworkspace -scheme App -configuration Release archivethen-exportArchivefor the.ipa;./gradlew bundleReleasefor the.aab(assembleReleaseonly when a raw.apkis genuinely needed). Ship the.aabto Play, not the.apk- Play requires the bundle and serves device-optimized splits from it. - Match the iOS archive target to the dependency manager: Capacitor 8 defaults new iOS projects to Swift Package Manager, which has no CocoaPods
.xcworkspace- archive it with-project ios/App/App.xcodeproj, not the-workspace ...App.xcworkspaceabove. A CocoaPods project (older, orcap add ios --packagemanager CocoaPods) keeps the workspace;npx cap build iosresolves the right target either way, andnpx cap migrateapplies the mechanical changes on a version bump.
Signing and store submission - the invariants
The mechanics - certificate + provisioning-profile setup, App Store Connect API keys and Fastlane match, keystore flags and apksigner, the TestFlight / Play track ladder - live in references/signing.md; load it when actually wiring signing or a submission. What holds regardless:
- iOS signs with a distribution certificate + App Store provisioning profile; in CI authenticate with an App Store Connect API key (a
.p8), never a hand-copied personal cert - the API key removes the 2FA prompt that breaks an unattended pipeline. - Android uses Play App Signing, and the two keys must differ: the upload key you hold and sign the
.aabwith, and the app-signing key Google holds and re-signs the served APKs with. That split is the key-loss story - a leaked upload key gets reset by Google without touching your app identity. Never check a keystore or its passwords into the repo - they are CI secrets (see below). - A release proves itself in a testing track - TestFlight / a Play testing track - before any production promotion; both stores promote the same build without rebuilding.