8.3 KiB
SwiftPM Import DSL Reference
Complete reference for the swiftPMDependencies {} DSL in Kotlin Multiplatform.
Basic Structure
swiftPackage() and localSwiftPackage() are annotated with @ExperimentalKotlinGradlePluginApi (warning level). Add the opt-in at the top of build.gradle.kts:
@file:OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
kotlin {
iosArm64()
iosSimulatorArm64()
swiftPMDependencies {
// Deployment versions
iosMinimumDeploymentTarget = "16.0"
macosMinimumDeploymentTarget = "13.0"
tvosMinimumDeploymentTarget = "16.0"
watchosMinimumDeploymentTarget = "9.0"
// Module discovery (default: true)
discoverClangModulesImplicitly = true
// Package declarations
swiftPackage(...)
localSwiftPackage(...)
}
}
Package Declaration
The DSL has two API forms. Use the simple string API for most packages. Use the typed API only when you need exact(), branch(), revision(), or platform constraints.
Simple API (Preferred)
Plain strings for URL, version, and products. The version parameter maps to a minimum version (from()) internally. The importedClangModules defaults to the products list automatically.
swiftPackage(
url = "https://github.com/owner/repo.git",
version = "1.0.0", // Equivalent to from("1.0.0") — minimum version
products = listOf("ProductName", "AnotherProduct"),
)
Typed API (Advanced)
Use when you need exact version pinning, branch tracking, platform constraints, or explicit Clang module control:
swiftPackage(
url = url("https://github.com/owner/repo.git"),
version = exact("1.0.0"),
products = listOf(
product("ProductName"),
product("PlatformSpecific", platforms = setOf(iOS()))
),
importedClangModules = listOf("CustomClangModuleName"),
)
Remote Package (Swift Package Registry)
swiftPackage(
repository = id("scope.package-name"),
version = from("1.0.0"),
products = listOf(product("ProductName")),
packageName = "package-name",
)
Local Package
localSwiftPackage(
directory = layout.projectDirectory.dir("../LocalPackage"),
products = listOf("LocalPackage"),
)
To create a new local package (e.g., a Swift/ObjC wrapper around a Swift-only library):
cd /path/to/shared
mkdir LocalPackage && cd LocalPackage
swift package init --type library --name LocalPackage
Then use it in Kotlin:
// src/appleMain/kotlin/useLocalPackage.kt
import swiftPMImport.<group>.<module>.HelloFromLocalPackage
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun useLocalPackage() {
HelloFromLocalPackage().hello()
}
Version Specification
| Syntax | Description | Use Case |
|---|---|---|
version = "1.0.0" (simple API) |
Minimum version — equivalent to from("1.0.0") |
Most packages |
version = exact("1.0") |
Exact version pin | Strict dependencies, migration |
version = from("1.0") |
Minimum version (explicit) | Same as simple string |
version = branch("name") |
Git branch | Development, testing |
version = revision("hash") |
Git commit hash | Pinning specific commits |
version = range("1.0", "2.0") |
Version range | Constraining upper bound |
Important for migration: The simple string version = "X.Y.Z" resolves to a minimum version (from()), which may pull a newer version than what was in CocoaPods. For exact version preservation during migration, use the typed API: version = exact("X.Y.Z").
Product Configuration
Simple API
products = listOf("FirebaseAnalytics", "FirebaseAuth")
With the simple API, importedClangModules defaults to the same list as products. This works when product names match Clang module names.
Typed API — Platform Constraints
For packages that only support certain platforms, use the typed product() function:
products = listOf(
product("GoogleMaps", platforms = setOf(iOS())) // iOS only
)
Available platforms: iOS(), macOS(), tvOS(), watchOS()
Typed API — Per-Product Clang Module Override
products = listOf(
product("FirebaseDatabase", importedClangModules = setOf("FirebaseDatabaseInternal"))
)
Module Import Configuration
Automatic Discovery (Default)
By default, discoverClangModulesImplicitly = true. SwiftPM import automatically discovers and imports all accessible Clang modules.
IMPORTANT: When discoverClangModulesImplicitly = true, the importedClangModules parameter is ignored. Only set importedClangModules when discoverClangModulesImplicitly = false.
IMPORTANT for Firebase: Set discoverClangModulesImplicitly = false when using Firebase. Firebase's transitive C++ dependencies (gRPC, abseil, leveldb, BoringSSL) contain Clang modules that fail cinterop generation. Disable implicit discovery and explicitly list only the Firebase modules you need in importedClangModules.
Explicit Module Import
When automatic discovery is disabled and the Clang module name differs from the product name, use the typed API:
swiftPMDependencies {
discoverClangModulesImplicitly = false // Disable auto-discovery
swiftPackage(
url = url("https://github.com/firebase/firebase-ios-sdk.git"),
version = from("12.6.0"),
products = listOf(
product("FirebaseAnalytics"),
product("FirebaseFirestore")
),
importedClangModules = listOf(
"FirebaseAnalytics",
"FirebaseCore",
"FirebaseFirestoreInternal" // Note: different from product name
),
)
}
When to Use importedClangModules
| Scenario | Use importedClangModules? |
|---|---|
| Simple API, product name = Clang module name | No (auto-defaulted from products) |
| Product name != Clang module name | Yes (typed API) |
| Multiple modules per product | Yes (typed API) |
| Using discoverClangModulesImplicitly = false | Yes (typed API) |
Deployment Versions
Set minimum deployment targets for each platform:
swiftPMDependencies {
iosMinimumDeploymentTarget = "16.0"
macosMinimumDeploymentTarget = "13.0"
tvosMinimumDeploymentTarget = "16.0"
watchosMinimumDeploymentTarget = "9.0"
}
Complete Example
plugins {
alias(libs.plugins.kotlinMultiplatform)
}
group = "org.example.myproject"
version = "1.0-SNAPSHOT"
kotlin {
iosArm64()
iosSimulatorArm64()
// Framework configuration (moved from cocoapods block)
listOf(iosArm64(), iosSimulatorArm64()).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "SharedModule"
isStatic = true
}
}
swiftPMDependencies {
iosMinimumDeploymentTarget = "16.0"
// Simple API — most packages
swiftPackage(
url = "https://github.com/lukaskubanek/LoremIpsum.git",
version = "2.0.1",
products = listOf("LoremIpsum"),
)
// Simple API — Google Maps
swiftPackage(
url = "https://github.com/googlemaps/ios-maps-sdk.git",
version = "10.3.0",
products = listOf("GoogleMaps"),
)
// Local package
localSwiftPackage(
directory = layout.projectDirectory.dir("LocalWrapper"),
products = listOf("LocalWrapper"),
)
}
compilerOptions {
optIn.add("kotlinx.cinterop.ExperimentalForeignApi")
}
}
Transitive Dependencies
SwiftPM dependencies are handled automatically. When you run Kotlin/Native tests or link a framework, the Kotlin Gradle Plugin will provision necessary machine code from transitive SwiftPM dependencies. This behavior is automatic.
You can optionally declare transitive dependencies explicitly to pin specific versions:
swiftPMDependencies {
// Main dependency
swiftPackage(
url = "https://github.com/firebase/firebase-ios-sdk.git",
version = "12.5.0",
products = listOf("FirebaseAnalytics"),
)
// Transitive dependency with explicit version pin
swiftPackage(
url = url("https://github.com/apple/swift-protobuf.git"),
version = exact("1.32.0"),
products = listOf(product("SwiftProtobuf")),
)
}