Se você trabalha com Kotlin Multiplatform e precisa integrar dependências iOS, provavelmente já enfrentou a dor de configurar CocoaPods ou lidar com frameworks manualmente. A boa notícia é que o suporte ao Swift Package Manager (SwiftPM) chegou como feature experimental no Kotlin 2.4.0-Beta2 — e promete simplificar drasticamente a forma como projetos KMP consomem bibliotecas do ecossistema Apple.

Neste artigo, vamos explorar como funciona essa integração, como configurar seu projeto e quais são os benefícios e limitações atuais.

Por que Swift Package Manager no KMP?

O Swift Package Manager é o gerenciador de dependências oficial da Apple, integrado nativamente ao Xcode e ao ecossistema Swift. Até agora, projetos Kotlin Multiplatform que precisavam de dependências iOS tinham basicamente duas opções:

  • CocoaPods: funcional, mas adiciona complexidade ao setup e exige Ruby instalado na máquina
  • Frameworks manuais: flexível, mas trabalhoso de manter

Com o suporte a SwiftPM, o plugin Gradle do Kotlin Multiplatform consegue importar APIs Objective-C e Swift diretamente de pacotes SwiftPM declarados nos seus targets Apple. Isso significa que você pode usar bibliotecas como Alamofire, Kingfisher ou qualquer outro pacote Swift sem sair do Gradle.

Se você já leu nosso guia de Kotlin Multiplatform Mobile, essa novidade complementa perfeitamente aquele fluxo de trabalho.

Requisitos

Para usar a importação via SwiftPM, você precisa:

  • Kotlin 2.4.0-Beta2 ou superior
  • Xcode 16 ou superior instalado (necessário para resolução de pacotes)
  • Plugin Gradle do Kotlin Multiplatform atualizado

Configurando o projeto

A configuração acontece no bloco kotlin do seu build.gradle.kts. Veja um exemplo completo:

// build.gradle.kts
plugins {
    kotlin("multiplatform") version "2.4.0-Beta2"
}

kotlin {
    iosArm64()
    iosSimulatorArm64()
    iosX64()

    sourceSets {
        iosMain {
            dependencies {
                // Dependências Kotlin normais
                implementation("io.ktor:ktor-client-darwin:3.1.2")
            }
        }
    }

    // Configuração SwiftPM para targets Apple
    appleTargets {
        swiftPackageDependencies {
            // Pacote remoto via URL do repositório
            package("Alamofire") {
                url("https://github.com/Alamofire/Alamofire.git")
                from("5.10.0")
            }

            // Pacote local
            package("MeuFrameworkInterno") {
                path("../ios-frameworks/MeuFramework")
            }
        }
    }
}

Depois de configurar, o plugin Gradle resolve automaticamente as dependências SwiftPM durante o build, e você pode importar as APIs no código Kotlin:

// src/iosMain/kotlin/networking/HttpClient.kt
import cocoapods.Alamofire.AF
import cocoapods.Alamofire.request

class IosNetworkClient {
    fun fetchData(url: String, callback: (String?) -> Unit) {
        // Usando Alamofire diretamente do Kotlin
        AF.request(url).responseString { response ->
            callback(response.value)
        }
    }
}

Versionamento de dependências

O SwiftPM no KMP suporta as mesmas estratégias de versionamento do Swift Package Manager nativo:

swiftPackageDependencies {
    // Versão mínima (semver)
    package("Biblioteca") {
        url("https://github.com/autor/biblioteca.git")
        from("2.0.0")
    }

    // Range exato
    package("OutraBiblioteca") {
        url("https://github.com/autor/outra.git")
        exact("1.5.3")
    }

    // Branch específico
    package("BibliotecaDev") {
        url("https://github.com/autor/dev.git")
        branch("main")
    }
}

Mecanismo de lock: Package.resolved

Para garantir builds reproduzíveis, o tooling do SwiftPM no KMP introduz um mecanismo de lock baseado em arquivos Package.resolved. Funciona assim:

  1. Cada subprojeto gera seu próprio Package.resolved
  2. O plugin Gradle mescla todos em um único arquivo raiz
  3. Todos os subprojetos usam as mesmas versões resolvidas

Isso é análogo ao gradle.lockfile ou ao package-lock.json — garante que toda a equipe e o CI usem exatamente as mesmas versões. Se você utiliza Gradle Version Catalogs no seu projeto, o SwiftPM complementa essa estratégia de versionamento centralizado.

Dependências transitivas

Uma das grandes vantagens é que dependências transitivas são resolvidas automaticamente. Se o pacote A depende do pacote B, o plugin Gradle fornece o código de máquina necessário de B sem configuração adicional. Isso funciona tanto para testes Kotlin/Native quanto para linking de frameworks.

// Não precisa declarar dependências transitivas manualmente
// O plugin resolve automaticamente
kotlin {
    appleTargets {
        swiftPackageDependencies {
            // Se Moya depende de Alamofire internamente,
            // Alamofire é resolvido automaticamente
            package("Moya") {
                url("https://github.com/Moya/Moya.git")
                from("15.0.0")
            }
        }
    }
}

Exemplo prático: app com analytics nativo

Vamos montar um exemplo mais completo — um módulo KMP que usa uma biblioteca de analytics nativa do iOS via SwiftPM:

// shared/build.gradle.kts
kotlin {
    androidTarget()
    iosArm64()
    iosSimulatorArm64()

    appleTargets {
        swiftPackageDependencies {
            package("TelemetryDeck") {
                url("https://github.com/TelemetryDeck/SwiftSDK.git")
                from("2.0.0")
            }
        }
    }

    sourceSets {
        commonMain {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
            }
        }
    }
}

No código compartilhado, você usa o padrão expect/actual para abstrair a implementação:

// src/commonMain/kotlin/analytics/Analytics.kt
expect class AnalyticsTracker {
    fun trackEvent(name: String, params: Map<String, String>)
}

// src/iosMain/kotlin/analytics/Analytics.ios.kt
import cocoapods.TelemetryDeck.TelemetryManager

actual class AnalyticsTracker {
    actual fun trackEvent(name: String, params: Map<String, String>) {
        TelemetryManager.send(name, with = params)
    }
}

Esse padrão funciona muito bem com a arquitetura que descrevemos no artigo sobre Kotlin Multiplatform.

SwiftPM vs CocoaPods no KMP

AspectoSwiftPMCocoaPods
SetupApenas GradleRequer Ruby + Podfile
Integração XcodeNativaVia plugin
Dependências transitivasAutomáticasAutomáticas
Lock filePackage.resolvedPodfile.lock
Pacotes locaisSuportadoSuportado
Exportar KMP como pacoteAinda nãoSuportado
Maturidade no KMPExperimentalEstável

Para projetos novos, o SwiftPM tende a ser a escolha mais natural — especialmente se a equipe iOS já usa SwiftPM em projetos nativos. Para projetos existentes com CocoaPods funcionando, a migração pode esperar até a feature ficar estável.

Limitações atuais

Como feature experimental, existem algumas limitações importantes:

  • Exportação não suportada: você pode importar pacotes SwiftPM, mas ainda não pode exportar módulos KMP como Swift packages
  • Xcode obrigatório: a resolução de pacotes depende do Xcode, então CI Linux puro não funciona para targets Apple
  • Opt-in necessário: por ser experimental, mudanças na API podem ocorrer entre releases

Para acompanhar a evolução, fique de olho no roadmap oficial do Kotlin e nas atualizações que trazemos aqui no blog.

Migrando de CocoaPods para SwiftPM

Se você já tem um projeto KMP usando CocoaPods e quer migrar gradualmente:

  1. Identifique quais dependências iOS possuem suporte a SwiftPM (a maioria das bibliotecas populares já tem)
  2. Adicione o bloco swiftPackageDependencies mantendo o cocoapods existente
  3. Migre uma dependência por vez, testando cada mudança
  4. Remova o bloco cocoapods quando todas as dependências estiverem no SwiftPM

Se você trabalha com coroutines no seu projeto KMP, a boa notícia é que o SwiftPM não interfere em nada no funcionamento — as suspend functions continuam funcionando normalmente com os wrappers nativos.

Conclusão

O suporte a Swift Package Manager no Kotlin Multiplatform é um passo importante para tornar a integração iOS mais natural e menos dependente de ferramentas externas. Embora ainda experimental, a feature já está funcional o suficiente para experimentar em projetos novos ou módulos isolados.

Com o KotlinConf 2026 se aproximando (maio, em Munique), é provável que tenhamos novidades sobre a estabilização dessa feature. Enquanto isso, aproveite para testar e dar feedback à equipe do Kotlin.

Se você desenvolve para múltiplas plataformas, vale conferir como outras linguagens abordam o problema: em Go, o gerenciamento de módulos é nativo desde o Go 1.11, enquanto em Rust, o Cargo resolve dependências de forma similar ao que o SwiftPM propõe para o ecossistema Apple.