Introdução ao Kotlin Multiplatform

1. Antes de começar

Pré-requisitos

  • Saber como criar apps do Jetpack Compose.
  • Experiência com Kotlin.
  • Conhecimentos básicos sobre a sintaxe do Swift.

O que você precisa

O que você aprenderá

  • Os conceitos básicos do Kotlin Multiplatform.
  • Como compartilhar código entre plataformas.
  • Como conectar o código compartilhado no Android e no iOS.

2. Começar a configuração

Para começar, siga estas etapas:

  1. Clone o repositório do GitHub (link em inglês):
$ git clone https://github.com/android/codelab-android-kmp.git

Se preferir, faça o download do repositório como um arquivo ZIP:

  1. No Android Studio, abra o projeto get-started, que contém as ramificações abaixo:
  • main: contém o código inicial do projeto, em que você vai fazer mudanças para concluir o codelab.
  • end: contém o código da solução do codelab.

Este codelab começa com a ramificação main. Você pode seguir o codelab no seu próprio ritmo.

  1. Para conferir o código da solução, execute este comando:
$ git clone -b end https://github.com/android/codelab-android-kmp.git

Você também pode baixar o código da solução:

Instalar o XCode

Para criar e executar a parte do iOS deste codelab, você precisa do Xcode e de um simulador do iOS:

  1. Instale o Xcode na Mac App Store. Para isso, você precisa de uma conta da Apple.
  2. Após a instalação, inicie o Xcode.
  3. Uma caixa de diálogo vai indicar quais componentes são integrados e quais precisam ser baixados. c4aba94d795dabee.png
  4. Marque o iOS 18.4 (ou mais recente).
  5. Clique em "Baixar e instalar".
  6. Aguarde até que os componentes sejam instalados.

Este codelab foi testado com o Xcode 16.3. Se você usar qualquer outra versão do Xcode e tiver problemas, recomendamos baixar a versão exata mencionada neste codelab.

App de exemplo

Essa base de código contém um app Android criado com o Jetpack Compose e um app iOS criado com a SwiftUI. O projeto do Android está localizado na pasta androidApp/, enquanto o projeto do iOS está localizado na pasta iosApp/, que também contém o KMPGetStartedCodelab.xcodeproj para ser executado com o Xcode.

3. Introdução ao Kotlin Multiplatform

O Kotlin Multiplatform (KMP) permite escrever o código uma vez e compartilhá-lo em várias plataformas de destino, como Android, iOS, Web e computadores. Ao usar o KMP, você pode minimizar a duplicação de código, manter a consistência e reduzir significativamente o tempo e o esforço de desenvolvimento.

O KMP não determina quanto ou quais partes da base de código você precisa compartilhar. Cabe a você decidir quais partes do código valem a pena compartilhar.

Como decidir o que compartilhar

Esse código compartilhado permite manter a consistência e reduzir a duplicação entre as plataformas. Muitas equipes de dispositivos móveis começam compartilhando um conjunto discreto de lógica de negócios (por exemplo, acesso a banco de dados, acesso à rede etc.) e os testes associados, e depois compartilham mais código ao longo do tempo.

Muitas bibliotecas do Android Jetpack têm suporte ao KMP. As bibliotecas do Jetpack que foram criadas para várias plataformas oferecem vários níveis de suporte, dependendo da plataforma de destino. Para conferir a lista completa de bibliotecas e os níveis de suporte delas, consulte a documentação.

Por exemplo, uma das bibliotecas compatíveis, a biblioteca de banco de dados Room, é compatível com Android, iOS e computador. Isso permite que você transfira a criação do banco de dados e a lógica relacionada a um módulo compartilhado comum do KMP, preservando o outro código nativo em ambas as plataformas.

Uma possível próxima etapa após a migração do banco de dados seria compartilhar outra lógica de domínio. Em seguida, considere usar a biblioteca ViewModel multiplataforma do Android Jetpack.

Como escrever código específico para a plataforma

O Kotlin Multiplatform apresenta novas técnicas para implementar funcionalidades específicas da plataforma.

Declarações esperadas e reais

O recurso da linguagem Kotlin expect actual foi criado para ser compatível com a base de código multiplataforma do Kotlin com suporte total ao ambiente de desenvolvimento integrado.

Essa abordagem é ideal quando o comportamento específico da plataforma pode ser encapsulado em uma única função ou classe. É um mecanismo flexível e poderoso. Por exemplo, uma classe expect comum pode ter equivalentes actual específicos da plataforma com modificadores de visibilidade mais abertos, supertipos adicionais ou diferentes tipos ou modificadores de parâmetro. Esses tipos de variações não seriam possíveis com uma API de interface rígida. Além disso, expect actual é resolvido de forma estática, ou seja, a implementação específica da plataforma é aplicada durante a compilação.

Interface e implementações em Kotlin

Se ambas as plataformas precisarem seguir APIs semelhantes, mas com implementações diferentes, defina uma interface no código compartilhado como uma alternativa às declarações esperadas e reais. Essa abordagem permite usar diferentes implementações de teste ou alternar para uma implementação diferente no momento da execução.

Além disso, as interfaces não exigem conhecimento específico do Kotlin, o que torna essa opção acessível para desenvolvedores que já conhecem interfaces em outras linguagens.

Interface em código compartilhado comum, implementação em código nativo (Android ou Swift).

Em alguns casos, é necessário escrever um código que não está disponível no código KMP. Nessa situação, você pode definir uma interface no código compartilhado, implementá-la para Android em Kotlin e fornecer uma contraparte do iOS em Swift. Normalmente, as implementações nativas são injetadas no código compartilhado, seja por injeção de dependências ou diretamente. Essa estratégia permite uma experiência personalizada em cada plataforma, mantendo uma interface comum para o código compartilhado.

4. Abrir o projeto do Xcode no Android Studio

Depois que o Xcode for instalado, confira se é possível executar o app iOS.

É possível abrir o projeto iOS diretamente no Android Studio.

  1. Mude para o painel "Project" para usar a visualização Project4f1a2c2ad988334c.png.
  2. Encontre o arquivo KmpGetStartedCodelab.xcodeproj na pasta [root]/iosApp/ 1357ffb58fe05180.png
  3. Clique com o botão direito do mouse no arquivo e selecione Open in e Open in Associated Application. Isso vai abrir o app iOS no Xcode. f93dee415dfd40e9.png
  4. Execute o projeto no Xcode clicando em ⌘+R ou navegando até o menu "Product" e selecionando "Run".

fff7f322c13ccdc0.png.

5. Adicionar um módulo KMP

Para adicionar compatibilidade com o KMP ao seu projeto, primeiro crie um módulo shared para o código que será reutilizado em várias plataformas (Android, iOS).

O Android Studio oferece uma maneira de adicionar um módulo Kotlin Multiplatform usando o modelo de módulo compartilhado do KMP.

Para criar o módulo KMP no Android Studio:

  1. Navegue até File > New > New Module > Kotlin Multiplatform Shared Module.
  2. Mude o pacote para com.example.kmp.shared.
  3. Clique em Finish4ef605dcc1fe6301.png
  4. Quando a criação do módulo for concluída e o Gradle terminar a sincronização, um novo módulo shared vai aparecer no projeto. Para conferir a visualização mostrada abaixo, talvez seja necessário mudar da visualização Android para a visualização Project.

eb58eea4e534dab2.png

O módulo compartilhado gerado pelo modelo de módulo compartilhado do KMP inclui algumas funções e testes de marcador de posição básicos. Esses marcadores de posição garantem que o módulo seja compilado e executado desde o início.

Importante: as pastas iosApp e iosMain são diferentes. A pasta iosApp contém o código do app iOS independente, enquanto iosMain faz parte do módulo compartilhado do KMP que você acabou de adicionar. A iosApp contém código Swift, enquanto a iosMain contém código KMP específico da plataforma iOS.

Primeiro, você precisa vincular o novo módulo compartilhado como uma dependência no módulo do Gradle :androidApp para permitir que o app use o código compartilhado:

  1. Abra o arquivo androidApp/build.gradle.kts.
  2. Adicione a dependência do módulo shared no bloco de dependências desta forma:
dependencies {
    ...
    implementation(projects.shared)
}
  1. Sincronize o projeto com arquivos do Gradle c4a6ca72cf444e6e.png

Verificar o acesso do código ao módulo shared

Para conferir se o app Android pode acessar o código do módulo shared, vamos fazer uma atualização simples no app.

  1. No projeto KMPGetStartedCodelab, abra o arquivo MainActivity em androidApp/src/main/java/com/example/kmp/getstarted/android/MainActivity.kt.
  2. Modifique o elemento combinável Text do conteúdo para incluir as informações platform() na string exibida.
Text(
  "Hello ${platform()}",
)
  1. Clique em ⌥(option)+return no teclado e selecione Import function 'platform'da301d17884eaef9.png.
  2. Crie e execute o app em um dispositivo ou emulador Android.

Essa atualização verifica se o app pode chamar a função platform() do módulo shared, que deve retornar "Android" quando executado na plataforma Android.

9828afe63d7cd9da.png

6. Configurar o módulo compartilhado no app iOS

O Swift não pode usar módulos Kotlin diretamente, como os apps Android, e exige a produção de um framework binário compilado (pacote XCFramework). Um pacote XCFramework é um pacote binário que inclui os frameworks e as bibliotecas necessárias para criar várias plataformas da Apple.

Como a biblioteca compartilhada é distribuída

O novo modelo de módulo no Android Studio já configurou o módulo compartilhado para produzir um framework para cada uma das arquiteturas do iOS. O código abaixo está no arquivo build.gradle.kts do módulo shared.

val xcfName = "sharedKit"

iosX64 {
  binaries.framework {
    baseName = xcfName
  }
}

iosArm64 {
  binaries.framework {
    baseName = xcfName
  }
}

iosSimulatorArm64 {
  binaries.framework {
    baseName = xcfName
  }
}

Esta etapa envolve configurar o Xcode para executar um script e gerar o framework Kotlin e chamar a função platform() no app iOS.

Para consumir a biblioteca compartilhada, conecte o framework Kotlin ao projeto iOS seguindo estas etapas:

  1. Abra o projeto iOS (o diretório iosApp mencionado anteriormente) no Xcode e abra as configurações do projeto clicando duas vezes no nome do projeto no navegador de projeto 94047b06db4a3b6f.png
  2. Na guia Build Phases das configurações do projeto, clique em + e selecione New Run Script Phase. Isso adiciona uma nova fase "Run Script" (Executar script) após todas as outras fases. d4907a9cb0a5ac6e.png
  3. Clique duas vezes no título Run Script para renomeá-lo. Mude o nome padrão Run Script para Compile Kotlin Framework (Compilar Framework Kotlin) para que seja possível entender o que essa fase faz.
  4. Abra a fase de build e, no campo de texto abaixo de Shell, insira o código do script:
cd "$SRCROOT/.."
./gradlew :shared:embedAndSignAppleFrameworkForXcode

7b6a393e44ddbe60.png

  1. Arraste a fase Compile Kotlin Framework para que fique antes da fase Compile Sources. 27dbe2cf958c986f.png
  2. Crie o projeto no Xcode clicando em ⌘+B ou acessando o menu do produto e selecionando Build. O progresso do build é mostrado na parte de cima do Xcode. bb0f9cb0f96d1f89.png

Se tudo estiver configurado corretamente, o projeto será criado.

bb9b12d5f6ad0bac.png

Ao definir a fase de criação de script de execução dessa forma, você pode compilar seu projeto do iOS no Xcode sem precisar mudar para outra ferramenta para compilar o módulo compartilhado.

Verificar o acesso do código ao módulo shared

Para conferir se o app iOS pode acessar o código do módulo shared, faça a mesma atualização simples no app que você fez no app Android.

  1. No projeto iOS, no Xcode, abra o arquivo ContentView.swift em: Sources/View/ContentView.swift
  2. Adicione import sharedKit na parte de cima do arquivo.
  3. Modifique a visualização Text para incluir as informações Platform_iosKt.platform() na string exibida com \(Platform_iosKt.platform()).

Confira o resultado final do arquivo:

import SwiftUI
import sharedKit 

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            
            Text("Hello, \(Platform_iosKt.platform())!")
        }
        .padding()
    }
}
  1. Para executar o app, clique em ⌘+R ou navegue até o menu Produto e clique em Run.

Essa atualização verifica se o app iOS pode chamar a função platform() do módulo compartilhado, que deve retornar "iOS" quando executado na plataforma iOS.

8024b5cc4bcd3f84.png

7. Adicionar o Swift/Kotlin Interface Enhancer (SKIE)

Por padrão, a interface nativa que o Kotlin produz é um cabeçalho Objective-C. O Swift é compatível diretamente com o Objective-C, mas o Objective-C não inclui todos os recursos modernos do Swift ou do Kotlin.

Essa também é a razão pela qual, no exemplo anterior, você não pode usar a chamada platform() diretamente no código Swift. O KMP não pode gerar uma função global porque o Objective-C não é compatível com funções globais, apenas funções estáticas encapsuladas em uma classe. É por isso que você precisa adicionar Platform_iosKt.

Para tornar a interface mais compatível com o Swift, use a ferramenta Swift/Kotlin Interface Enhancer (SKIE) para melhorar a interface Swift do módulo :shared.

Os recursos comuns da SKIE são:

  • Melhor compatibilidade com argumentos padrão
  • Melhor compatibilidade para hierarquias seladas (sealed class, sealed interface)
  • Melhor compatibilidade com enum class com tratamento exaustivo em instruções switch
  • Interoperabilidade entre Flow e AsyncSequence
  • Interoperabilidade entre suspend fun e async func
  1. Adicione o plug-in do Gradle co.touchlab.skie ao arquivo libs.versions.toml:
[versions]
skie = "0.10.1"

[plugins]
skie = { id = "co.touchlab.skie", version.ref = "skie" }
  1. Adicione o plug-in ao arquivo raiz build.gradle.kts
plugins {
   ...
   alias(libs.plugins.skie) apply false
}
  1. Adicione o plug-in ao arquivo build.gradle.kts do módulo :shared:
plugins {
   ...
   alias(libs.plugins.skie)
}
  1. O Gradle sincroniza o projeto

Remover a chamada de função estática

Ao recriar o app iOS, talvez você não note nada imediatamente, mas pode remover o prefixo Platform_iosKt e deixar a função platform() atuar como uma função global.

Text("Hello, KMP! \(platform())")

Isso funciona porque a SKIE (entre outros recursos) aproveita as notas da API do Swift, que adicionam informações sobre APIs para melhor consumo no código Swift.

8. Parabéns

Parabéns! Você adicionou o primeiro código compartilhado do Kotlin Multiplatform a projetos Android e iOS. Embora esse seja apenas um pequeno ponto de partida, agora você pode começar a descobrir recursos mais avançados e casos de uso para compartilhar código com o KMP.

Qual é a próxima etapa?

Aprenda a usar o Jetpack Room para compartilhar uma camada de dados entre Android e iOS no próximo codelab.

Saiba mais