kotlin-tooling-cocoapods-spm-migration
Migrate KMP projects from CocoaPods (kotlin("native.cocoapods")) to Swift Package Manager (swiftPMDependencies DSL) — replaces pod() with swiftPackage(), transforms cocoapods.* imports to swiftPMImport.*, and reconfigures the Xcode project.
What this skill does
# CocoaPods to SwiftPM Migration for KMP
Migrate Kotlin Multiplatform projects from `kotlin("native.cocoapods")` to `swiftPMDependencies {}` DSL.
## Requirements
- **Kotlin**: 2.4.0-Beta2 or later (first public release with `swiftPMDependencies` support, available on Maven Central)
- **Xcode**: 16.4 or 26.0+
- **iOS Deployment Target**: 16.0+ recommended
## Migration Overview
**IMPORTANT**: Keep the `cocoapods {}` block and plugin active until Phase 6. The migration adds `swiftPMDependencies {}` alongside the existing CocoaPods setup first, reconfigures Xcode, and only then removes CocoaPods.
| Phase | Action |
|-------|--------|
| 1 | Analyze existing CocoaPods configuration |
| 2 | Update Gradle configuration (repos, Kotlin version) |
| 3 | Add `swiftPMDependencies {}` alongside existing `cocoapods {}` |
| 4 | Transform Kotlin imports |
| 5 | Reconfigure iOS project and deintegrate CocoaPods |
| 6 | Remove CocoaPods plugin from Gradle |
| 7 | Verify Gradle build and Xcode project build |
| 8 | Write MIGRATION_REPORT.md |
---
## Phase 1: Pre-Migration Analysis
### 1.0 Verify the project builds
Before starting migration, identify the module to migrate and confirm it compiles successfully.
1. **Find the module that uses CocoaPods** — look for `build.gradle.kts` files containing `cocoapods`:
```bash
grep -rl "cocoapods" --include="build.gradle.kts" .
```
Extract the module name from the path (e.g., `./shared/build.gradle.kts` → module name is `shared`). Note: multiple modules may use CocoaPods — record all of them. Typically only the module that produces the framework linked into the iOS app needs `swiftPMDependencies`; the others only need CocoaPods removed (Phase 6).
2. **Compile Kotlin code** — run the Kotlin compilation task for that module to verify the Kotlin source compiles:
```bash
./gradlew :moduleName:compileKotlinIosSimulatorArm64
```
Replace `moduleName` with the directory name of the module (e.g., `:shared:compileKotlinIosSimulatorArm64`). This is faster than a full `build` (which also runs release linkage) and sufficient to verify Kotlin code correctness.
3. **Build the iOS app (optional)** — try to locate the Xcode project and build it to confirm the full app compiles:
```bash
# Find the Xcode project
find . -name "*.xcworkspace" -not -path "*/Pods/*" -maxdepth 2
# Build (replace scheme name with the actual app scheme)
cd /path/to/iosApp
xcodebuild -workspace *.xcworkspace -scheme "<AppScheme>" -destination 'generic/platform=iOS Simulator' ARCHS=arm64
```
If the user wants to skip the Xcode build or no Xcode project is found, proceed without it — the Kotlin compilation from step 2 is sufficient to continue.
4. **If the Kotlin compilation fails**, ask the user to either:
- Provide the correct Gradle command to verify the module builds, or
- Confirm the module is in a working state and it's safe to proceed
If the user confirms without providing a build command, **record that the pre-migration build could not be verified** and warn about this at the end of migration (Phase 7).
### 1.0a Confirm Kotlin version with Swift Import support
Read the current Kotlin version from `gradle/libs.versions.toml` (or `build.gradle.kts`).
**If the project already uses Kotlin 2.4.0-Beta2 or later** → record the version and skip Phase 2.1 (no version change needed).
**If the project uses an older Kotlin version** → Phase 2.1 will upgrade it to `2.4.0-Beta2` (the first public release with `swiftPMDependencies` support, available on Maven Central — no custom repository needed). Warn the user: "⚠️ Kotlin version jump — upgrading across minor versions can introduce breaking changes unrelated to this migration. Recommended: update first, verify it builds, then re-run this migration." If the user confirms, proceed.
### 1.1 Check for deprecated CocoaPods workaround property
Search `gradle.properties` for the deprecated property:
```properties
kotlin.apple.deprecated.allowUsingEmbedAndSignWithCocoaPodsDependencies=true
```
This property was a workaround (see [KT-64096](https://youtrack.jetbrains.com/issue/KT-64096)) for projects using `embedAndSign` alongside CocoaPods dependencies. It suppresses an error about unsupported configurations that can cause runtime crashes or symbol duplication. After migrating to SwiftPM import, this property is no longer needed and **must be removed** in Phase 6. Record its presence if found.
### 1.2 Check for EmbedAndSign disablers
Search all `build.gradle.kts` files for code that disables `EmbedAndSign` tasks (e.g., `TaskGraph.whenReady` filters, `tasks.matching` blocks). This is a CocoaPods-era workaround that **breaks the migration** because `integrateEmbedAndSign` (needed in Phase 5) gets disabled too. Record any such code — it **must be removed** in Phase 6, and may need to be removed earlier. See [troubleshooting.md](references/troubleshooting.md) § "`integrateEmbedAndSign` Skipped" for patterns.
### 1.3 Check for third-party KMP libraries with bundled cinterop klibs
Some KMP libraries ship pre-built cinterop klibs with `cocoapods.*` package namespaces. After migration, the swiftPMDependencies cinterop generator detects these existing bindings and **skips generating new bindings** for those Clang modules to avoid duplicates. This means `cocoapods.*` imports for those modules must be **kept as-is** — they resolve to the third-party library's bundled klib, not to actual CocoaPods.
**Known libraries with bundled `cocoapods.*` klibs:**
| Library | Maven artifact | Bundled klib namespace | Classes provided |
|---------|---------------|----------------------|-----------------|
| [KMPNotifier](https://github.com/mirzemehdi/KMPNotifier) | `io.github.mirzemehdi:kmpnotifier` | `cocoapods.FirebaseMessaging` | `FIRMessaging`, `FIRMessagingAPNSTokenType`, etc. |
**How to detect:** Search Gradle dependency declarations for known libraries, then cross-reference their bundled namespaces against the `import cocoapods.*` statements found in step 4. Mark any matches — these imports will NOT be transformed in Phase 4.
If unsure whether a third-party KMP library bundles cinterop klibs, check if it has a `linkOnly = true` pod dependency in the project — this is a strong indicator that the library provides its own klib for those classes.
To inspect klib contents and verify bundled bindings, see [troubleshooting.md](references/troubleshooting.md) § "Third-Party KMP Libraries with Bundled Klibs".
**Find and record:**
1. **CocoaPods configuration** - Search for `cocoapods` in `build.gradle.kts` files
2. **Pod dependencies** - Extract pod names, versions from `cocoapods {}` blocks
3. **Framework configuration** - Record `baseName`, `isStatic`, deployment target from `cocoapods.framework {}`
4. **linkOnly pods** - Record pods declared with `linkOnly = true`. These have two common patterns:
- **KMP wrapper libraries** (e.g., `dev.gitlive:firebase-*`): the wrapper provides Kotlin APIs, and the pod is only linked. See [common-pods-mapping.md](references/common-pods-mapping.md) for implications.
- **Multi-module projects**: the consuming module declares `linkOnly = true` because a child module already provides cinterop bindings for that pod. In SwiftPM, the `swiftPackage()` declaration should go **only** in the child module that uses the pod directly. The consuming module must NOT redeclare the same packages — it only needs a `swiftPMDependencies {}` block without those packages (or an empty one if all pods were `linkOnly`). **Import namespace implication:** when the consuming module imports SPM classes that come from a child module's `swiftPMDependencies`, the import path uses the **child module's** group and name as the namespace (see Phase 4 Import Namespace Formula).
5. **Kotlin imports** - Find all `import cocoapods.*` statements. Cross-reference with step 1.3 to identify which imports come from bundled klibs (and must be preserved) vs. which come from direcRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.