# Kotlin Multiplatform 2026: compartilhar código Android/iOS > Como o Kotlin Multiplatform compartilha a lógica de negócio entre Android e iOS em 2026: configuração do Gradle, expect/actual, rede com Ktor, interface Compose Multiplatform e perguntas comuns de entrevista de KMP. - Published: 2026-06-26 - Updated: 2026-07-06 - Author: SharpSkill - Tags: Kotlin Multiplatform, KMP, Android, iOS, Cross-platform - Reading time: 10 min --- O Kotlin Multiplatform (KMP) permite que uma única base de código Kotlin alimente a lógica de negócio dos aplicativos Android e iOS, enquanto cada plataforma mantém sua interface totalmente nativa, seu desempenho e o acesso ao seu SDK. Em 2026, o KMP deixou de ser um experimento: a tecnologia é estável, tem o apoio oficial do [Google](https://developer.android.com/kotlin/multiplatform) e roda em produção na Netflix, no McDonald's, na Forbes e no Cash App. Esta análise detalha como o compartilhamento de código funciona de fato, como configurar um módulo compartilhado e as escolhas que vale a pena entender antes de uma entrevista de KMP. > **O que o KMP realmente compartilha** > > O Kotlin Multiplatform compartilha lógica compilada, não um runtime. O Kotlin comum é compilado para bytecode da JVM no Android e para um binário nativo (via LLVM) no iOS. Não há ponte de JavaScript, nem webview embutida, nem camada de reflexão, então o código compartilhado roda em velocidade nativa nas duas plataformas. ## Como o Kotlin Multiplatform compartilha código sem sacrificar o desempenho nativo O mecanismo central é uma hierarquia de source sets. O `commonMain` contém o Kotlin independente de plataforma: rede, serialização, regras de negócio e view models. Os source sets de plataforma como `androidMain` e `iosMain` guardam o código que acessa as APIs nativas. O compilador produz um artefato JVM a partir de `commonMain` mais `androidMain` para o Android, e um framework nativo a partir de `commonMain` mais `iosMain` para o iOS. Em 2026, o Kotlin Multiplatform prioriza compartilhar o que de fato se beneficia de uma única fonte de verdade: modelos, clientes de API, cache e validação. A interface pode ser compartilhada com o Compose Multiplatform ou permanecer totalmente nativa com SwiftUI, tela por tela. Esse modelo de «compartilhar a lógica, escolher a interface» é o motivo pelo qual as equipes adotam o KMP sem reescrever os aplicativos existentes. O Kotlin Multiplatform é uma tecnologia Kotlin que compila um módulo compartilhado para vários targets (Android na JVM, iOS como nativo, além de desktop e web), de modo que a lógica de negócio é escrita uma única vez enquanto cada plataforma mantém sua interface nativa e o acesso completo ao seu SDK. O Google agora o oferece como uma opção de primeira classe, e bibliotecas do Jetpack como Room, DataStore, ViewModel e Paging fornecem artefatos KMP. Decidir o que pertence ao módulo compartilhado é a decisão de arquitetura mais importante de um projeto KMP. A tabela a seguir reflete como a maioria das equipes em produção traça a linha em 2026: tudo o que está abaixo da camada de apresentação é um forte candidato ao compartilhamento, enquanto tudo o que toca as convenções de UX da plataforma costuma permanecer nativo. | Camada | Compartilhar em commonMain? | Motivo | |-------|---------------------|--------| | Modelos de dados e DTOs | Sim | Contrato de API idêntico nas duas plataformas | | Rede e cache | Sim | Uma única pilha HTTP, uma única superfície de bugs | | Regras de negócio e validação | Sim | O domínio não muda conforme o sistema operacional | | View models e estado | Normalmente | Compose e SwiftUI consomem o estado compartilhado | | Renderização da interface | Opcional | Compartilhada com o Compose ou nativa por tela | | APIs de plataforma (câmera, biometria) | Não | Melhor expor via expect/actual | O retorno aumenta conforme a fatia da metade inferior dessa tabela que um aplicativo abrange. Produtos com muitos dados e interfaces enxutas compartilham o máximo; aplicativos muito personalizados e movidos a animação compartilham o mínimo. Nenhum dos extremos está errado, e é por isso que o KMP combina com uma adoção incremental em vez de uma reescrita de tudo ou nada. ## Configurar o módulo compartilhado no Gradle Um módulo KMP declara seus targets e source sets em Kotlin DSL. O `build.gradle.kts` a seguir configura o Android e as três arquiteturas de iOS (dispositivo físico, simulador Intel, simulador Apple Silicon) e expõe a saída do iOS como um framework chamado `Shared`. ```kotlin // shared/build.gradle.kts plugins { kotlin("multiplatform") kotlin("plugin.serialization") id("com.android.library") } kotlin { // Android target compiles commonMain + androidMain to JVM bytecode androidTarget() // Three iOS targets: device, Intel sim, Apple Silicon sim listOf(iosArm64(), iosX64(), iosSimulatorArm64()).forEach { target -> target.binaries.framework { baseName = "Shared" // becomes "import Shared" in Swift isStatic = true } } sourceSets { commonMain.dependencies { implementation("io.ktor:ktor-client-core:3.3.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") } androidMain.dependencies { implementation("io.ktor:ktor-client-okhttp:3.3.0") } iosMain.dependencies { implementation("io.ktor:ktor-client-darwin:3.3.0") } } } ``` Cada target puxa um motor Ktor específico da plataforma (`okhttp` no Android, `darwin` no iOS), enquanto o código compartilhado depende apenas da API comum `ktor-client-core`. O conjunto completo de opções está na [documentação do Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html). ## Escrever código específico da plataforma com expect e actual Parte da lógica não pode ficar no `commonMain` porque precisa de uma API de plataforma. O mecanismo `expect`/`actual` declara o formato no código comum e fornece uma implementação concreta por target, resolvida em tempo de compilação e sem custo em tempo de execução. ```kotlin // commonMain/kotlin/Platform.kt // commonMain declares what it needs but cannot implement here expect class Platform() { val name: String val osVersion: String } // Shared logic can now depend on Platform freely fun analyticsUserAgent(): String { val platform = Platform() return "SharpSkill/" + platform.name + " " + platform.osVersion } ``` A implementação do Android lê da classe `Build` e a do iOS lê de `UIDevice`. Ambas cumprem o mesmo contrato, então o `commonMain` nunca sabe com qual delas está conversando. ```kotlin // androidMain/kotlin/Platform.kt import android.os.Build // actual supplies the Android-specific implementation actual class Platform actual constructor() { actual val name: String = "Android" actual val osVersion: String = Build.VERSION.RELEASE } ``` ```kotlin // iosMain/kotlin/Platform.kt import platform.UIKit.UIDevice // actual uses UIKit directly, no Objective-C bridging code required actual class Platform actual constructor() { actual val name: String = "iOS" actual val osVersion: String = UIDevice.currentDevice.systemVersion } ``` O Kotlin/Native traz bindings tipados para todo o SDK do iOS, de modo que `UIDevice`, `NSUserDefaults` e os tipos do Foundation podem ser chamados a partir do Kotlin sem código de ligação escrito à mão. ## Compartilhar a lógica de rede e serialização A rede é o código mais valioso para compartilhar, porque os contratos de API são idênticos nas duas plataformas. Um único cliente [Ktor](https://ktor.io/docs/) somado ao `kotlinx.serialization` substitui duas implementações paralelas. As funções `suspend` se apoiam nas [corrotinas do Kotlin](/blog/android/mastering-kotlin-coroutines), que se traduzem de forma limpa em `async`/`await` dos dois lados. ```kotlin // commonMain/kotlin/data/InterviewRepository.kt import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.get import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.Serializable // One serializable model, zero duplication across platforms @Serializable data class Question(val id: String, val prompt: String, val difficulty: String) // One HttpClient, one JSON parser, one repository for both apps class InterviewRepository { private val client = HttpClient { install(ContentNegotiation) { json() } } suspend fun fetchQuestions(tech: String): List = client.get("https://api.sharpskill.dev/questions/" + tech).body() } ``` Esse repositório, sua lógica de repetição e seus modelos de dados são escritos uma única vez. Um bug corrigido no parser fica corrigido no Android e no iOS ao mesmo tempo, e é aí que o KMP paga o custo de configuração. O mesmo padrão se estende a um banco de dados compartilhado com o SQLDelight, a um armazenamento chave-valor compartilhado e a uma injeção de dependências compartilhada com o Koin, de modo que toda a camada de dados pode ficar no `commonMain` por trás de interfaces das quais a interface de usuário depende. Um erro comum é tentar compartilhar demais cedo demais. O caminho pragmático é começar com um único repositório, validar o build e o pipeline de CI nas duas plataformas e então mover as funcionalidades uma de cada vez conforme a confiança aumenta. ## Construir uma interface compartilhada com o Compose Multiplatform O Compose Multiplatform atingiu o status estável no iOS em maio de 2025 (versão 1.8.0) e chegou à 1.11.0 em meados de 2026, com entrada de texto nativa e renderização concorrente ativada por padrão. Um `@Composable` no `commonMain` é renderizado nas duas plataformas, e os view models compartilhados combinam naturalmente com uma [arquitetura MVVM ou MVI](/blog/android/mvvm-vs-mvi-architecture). ```kotlin // commonMain/kotlin/ui/QuestionList.kt import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Card import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.foundation.layout.padding // This list renders identically on Android and iOS @Composable fun QuestionList(questions: List) { LazyColumn { items(questions) { question -> Card(modifier = Modifier.padding(8.dp)) { Text(text = question.prompt, modifier = Modifier.padding(16.dp)) } } } } ``` Compartilhar a interface é opcional e feito tela por tela. Uma equipe pode compartilhar toda a interface com o [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform), manter o SwiftUI para o aplicativo inteiro e compartilhar apenas a lógica, ou combinar as duas abordagens. As telas que dependem de uma UX específica da plataforma, como widgets ou App Clips, costumam permanecer nativas. ## Consumir o código compartilhado a partir do Swift no iOS O módulo compartilhado é compilado em um framework que o Swift importa como qualquer biblioteca. Historicamente, o atrito vinha das funções `suspend` do Kotlin e do `Flow`, que apareciam como APIs de callback pouco práticas. O [SKIE](https://skie.touchlab.co/), da Touchlab, resolve isso gerando Swift idiomático: `suspend` vira um `async`/`await` nativo e `Flow` vira um `AsyncSequence`. ```swift // iosApp/ContentView.swift import SwiftUI import Shared // the KMP framework, baseName = "Shared" struct ContentView: View { @State private var questions: [Question] = [] private let repository = InterviewRepository() var body: some View { List(questions, id: \.id) { question in Text(question.prompt) } .task { // With SKIE, the Kotlin suspend fun is a Swift async fun questions = (try? await repository.fetchQuestions(tech: "android")) ?? [] } } } ``` A equipe de iOS escreve Swift e SwiftUI comuns. Ela consome os modelos e repositórios compartilhados exatamente como faria com um pacote Swift nativo, o que mantém o KMP invisível para a maior parte do código de iOS. Duas arestas ainda valem menção em uma entrevista. Primeiro, os tempos de build: a compilação do Kotlin/Native é mais lenta que um build Swift puro, embora o cache de build do Gradle e a distribuição de um XCFramework pré-compilado suavizem o custo diário. Segundo, a depuração na fronteira Swift-Kotlin está melhorando, mas ainda não é tão fluida quanto permanecer em uma só linguagem, mais um motivo para as equipes manterem a superfície compartilhada deliberada em vez de espalhada. ## Perguntas de entrevista sobre Kotlin Multiplatform que se pode esperar Como as perguntas de entrevista sobre KMP aparecem cada vez mais em vagas de Android e mobile, vale a pena revisar algumas recorrentes junto com uma [preparação para entrevistas de Android](/technologies/android) mais ampla: - **Em que expect/actual difere de uma interface?** O expect/actual é resolvido em tempo de compilação para cada target, sem dispatch em tempo de execução, e pode dar suporte a uma classe, função, propriedade ou typealias. Uma interface é resolvida dinamicamente em tempo de execução. Usa-se expect/actual para as APIs de plataforma e interfaces para o polimorfismo dentro do código compartilhado. - **Como o Kotlin/Native lida com memória e threads?** Desde o Kotlin 1.7.20, o novo gerenciador de memória removeu o antigo modelo de congelamento de objetos, então o estado mutável compartilhado e as corrotinas funcionam entre threads quase como na JVM. - **Um aplicativo existente pode adotar o KMP de forma incremental?** Sim. O módulo compartilhado é entregue como um AAR para o Android e um XCFramework para o iOS, então um repositório ou funcionalidade pode migrar um de cada vez, sem reescrita. - **Quando a interface deve permanecer nativa em vez de usar o Compose Multiplatform?** Quando uma tela se apoia em uma UX específica da plataforma ou quando a equipe de iOS detém e prefere controlar a camada de apresentação. > **Cadeia de ferramentas em 2026** > > Mirar no Kotlin 2.3 com o compilador K2, no Ktor 3.x para a rede, no SQLDelight para um banco de dados compartilhado e no Koin para a injeção de dependências. Para a interoperabilidade com iOS, adicionar o SKIE cedo: incorporá-lo depois, com a camada Swift já escrita, é bem mais penoso. ## Conclusão Em 2026, o Kotlin Multiplatform é uma forma pragmática de cortar a lógica duplicada entre Android e iOS sem abrir mão da interface nem do desempenho nativos: - Compartilhar a lógica que tem uma única fonte de verdade (modelos, rede, validação) e escolher interface nativa ou Compose tela por tela. - Usar `expect`/`actual` para as APIs de plataforma: a resolução ocorre em tempo de compilação, sem sobrecarga em tempo de execução. - Escrever a rede uma única vez com o Ktor e o `kotlinx.serialization` para que as correções cheguem às duas plataformas ao mesmo tempo. - Adotar de forma incremental por meio de um AAR e um XCFramework em vez de assumir uma reescrita. - Adicionar o SKIE desde o início para que o Swift consuma `suspend` e `Flow` como `async`/`await` e `AsyncSequence` nativos. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/android/kotlin-multiplatform-2026