Compare the two main ways to package a KMP framework for iOS consumers: the CocoaPods Gradle plugin versus the Swift Package Manager (SwiftPM) integration. What does each generate and when would you pick one?
answer
- CocoaPods plugin: kotlin("native.cocoapods") + cocoapods {} -> podspec
- pod(...) consumes existing Obj-C Pods via cinterop
- SwiftPM: build XCFramework -> .binaryTarget in Package.swift
- CocoaPods needs Ruby gem; SwiftPM is Pod-free
- Both ship the same Kotlin/Native framework
basics
~20 sThe CocoaPods plugin makes your shared module a Pod the iOS app pulls via a Podfile. The SwiftPM route publishes the framework as an XCFramework referenced by a Package.swift. Pick CocoaPods if the app already uses Pods; SwiftPM for a Pod-free, native Apple toolchain.
solid answer
~40 sCocoaPods: apply the kotlin("native.cocoapods") plugin and add a cocoapods { } block (summary, homepage, framework { baseName = ... }, podfile = project.file(...)). Gradle generates a .podspec; the iOS app references it via pod 'Shared', :path => '...'. It can also pull in existing Pods as Kotlin dependencies (pod("AFNetworking")) with cinterop. SwiftPM: build an XCFramework (local, or hosted as a binary target), then reference it in Package.swift as a .binaryTarget. No Ruby/CocoaPods toolchain; integrates with Xcode's native package manager. Choose CocoaPods when the iOS app already depends on Pods or you need to consume Obj-C Pods from Kotlin; choose SwiftPM for a modern, dependency-light Apple-native setup. Both ultimately deliver the same Kotlin/Native framework.
go deeper
Knows iOS apps can pull the shared module via CocoaPods or SwiftPM but few specifics.
Configures the cocoapods {} block and knows the XCFramework + Package.swift SwiftPM path and when to pick each.
Explains cinterop for consuming Pods, build-machine requirements, and remote binaryTarget distribution.
Weighs org-wide tooling, CI build agents, and distribution model (local vs hosted, versioning, checksums) when standardizing packaging.
## The goal After you compile `iosArm64()`/`iosSimulatorArm64()` into a framework, the iOS app must consume it. Two first-class packaging routes exist. ## CocoaPods integration Apply the bundled plugin and configure the DSL: ```kotlin plugins { kotlin("multiplatform"); kotlin("native.cocoapods") } kotlin { iosArm64(); iosSimulatorArm64() cocoapods { summary = "Shared KMP module" homepage = "https://example.com" ios.deploymentTarget = "15.0" framework { baseName = "Shared"; isStatic = true } podfile = project.file("../iosApp/Podfile") pod("AFNetworking") { version = "~> 4.0" } // consume an Obj-C pod from Kotlin } } ``` What it does: - Generates a **`.podspec`** for your shared module so the iOS app can `pod 'Shared', :path => '...'`. - Lets Kotlin **consume existing CocoaPods** via `pod(...)`, generating cinterop bindings so you call Obj-C Pod APIs from Kotlin. - Runs `pod install` for you when `podfile` is set. - Best when the iOS app **already uses CocoaPods** or you must depend on Obj-C/Swift Pods from shared code. Requires the CocoaPods Ruby gem installed on the build machine. ## Swift Package Manager (SwiftPM) integration Approach: produce an **XCFramework** and expose it as a Swift package binary target. - Build the XCFramework via the `XCFramework()` helper (`assembleSharedXCFramework`). - Reference it in **`Package.swift`**: ```swift .binaryTarget(name: "Shared", path: "./Shared.xcframework") ``` - For remote distribution, zip the XCFramework, host it, and use `.binaryTarget(name:url:checksum:)`. - Newer Kotlin tooling provides direct SwiftPM export support so the package can be regenerated as part of the build. - No Ruby/CocoaPods dependency; integrates with Xcode's native package resolution. Best for **Pod-free, Apple-native** projects. ## Choosing | Need | Pick | |------|------| | App already on CocoaPods | CocoaPods | | Consume Obj-C/Swift Pods from Kotlin | CocoaPods (`pod(...)` + cinterop) | | Avoid Ruby/CocoaPods, native Xcode packages | SwiftPM (XCFramework binary target) | | Distribute a prebuilt binary to many teams | SwiftPM remote binaryTarget (or a Pod) | Both deliver the **same Kotlin/Native framework**; they differ in the consumer-side dependency manager and build-machine requirements.
- How can Kotlin code call an existing Objective-C CocoaPod?Declare it with pod("Name") in the cocoapods {} block; the plugin runs cinterop to generate Kotlin bindings for the Pod's Obj-C API.
- What makes XCFramework the right unit for SwiftPM distribution?An XCFramework bundles multiple architectures/platforms (device + simulator) in one artifact, which a Package.swift binaryTarget can reference directly.
saying these in an interview costs you the question
- Claims SwiftPM requires CocoaPods installed
- Doesn't know CocoaPods can consume Obj-C Pods into Kotlin via cinterop
- Thinks the two routes produce fundamentally different frameworks
- Forgets SwiftPM consumes an XCFramework, not a bare .framework