Migrar um app Android para Kotlin Multiplatform com AGP 9: sete armadilhas
Por Nesim Razon, desenvolvedor Android independente · 2026-11-14
Levei um pequeno jogo em Compose para Kotlin Multiplatform para que ele também rode no iPhone. A parte de Kotlin foi fácil, a configuração da compilação não. Estas são as sete armadilhas que encontrei com o Android Gradle Plugin 9 e o Compose Multiplatform, na ordem em que as encontrei, e as verificações que me mostraram que nada mais tinha mudado.
1. O plugin de aplicativo e o multiplataforma não dividem mais o módulo
Com o Android Gradle Plugin 9, o plugin de Kotlin Multiplatform não pode ser aplicado a um módulo que também usa o plugin de aplicativo Android. O código compartilhado precisa de um módulo de biblioteca próprio com o novo plugin de biblioteca Android para multiplataforma. O módulo do app continua sendo um aplicativo Android normal e depende dele. O guia de migração do Kotlin também pede um Gradle recente, 9.1 ou superior.
2. Testes unitários que param de rodar em silêncio
Movi as regras do jogo e seus dez testes unitários para o módulo compartilhado, rodei a compilação e recebi um resultado verde. Depois olhei o registro: a tarefa de testes Android do módulo compartilhado dizia que não havia nada para executar. Com o plugin novo, o teste de host do Android fica desligado até você ligá-lo.
Declarar um teste de host na parte Android do módulo resolveu, e o arquivo de resultados mostrou dez testes executados e nenhum falho. A lição: depois de uma migração, conte os testes, não confie só no verde.
3. O Compose Resources precisa dos recursos do Android ativados
Os textos e as fontes foram para o módulo compartilhado como Compose Resources. Meus testes de captura de tela passaram a falhar com um erro de recurso ausente que apontava para um arquivo de textos compilado. Adicionar uma chamada de configuração de pré-visualização nos testes não ajudou. O que resolveu foi ativar os recursos do Android no bloco Android do módulo compartilhado, junto com incluir os recursos do Android no teste de host.
4. Uma barra invertida que sobreviveu à migração
Os arquivos de textos do Android escapam o apóstrofo com uma barra invertida. O Compose Resources não a interpreta, então o diálogo de estatísticas em turco mostrava 2048\'e em vez de 2048'e. A solução é usar um apóstrofo normal nos textos copiados.
Só encontrei isso graças à verificação seguinte. Nada travou e nenhum teste falhou, o texto estava apenas um pouco errado.
5. Nomes de teste que o Kotlin/Native não aceita
Um teste tinha uma vírgula no nome entre crases, algo inofensivo no Android. Ao compilar o destino de testes do iOS, ele parou com uma mensagem de que o nome contém caracteres ilegais. Reescrever o nome sem a vírgula resolveu.
6. Um destino de simulador que não existe mais
Eu tinha listado os destinos de simulador do iOS para Macs Apple silicon e Intel. A compilação acusou uma falha de resolução de dependências: as bibliotecas do Compose Multiplatform não estavam publicadas para o destino de simulador Intel. Tirei esse destino, então a compilação cobre o simulador arm64 e dispositivos reais.
7. Um DataStore por arquivo
O código Android antigo usava um delegado que criava um DataStore por processo. No código compartilhado eu mesmo crio o repositório e o passo adiante; dois repositórios abertos sobre o mesmo arquivo derrubam o app. Por isso mantenho uma única instância atrás de um pequeno objeto de apoio no Android, apontando para o mesmo arquivo que o delegado antigo usava, de modo que os jogos salvos existentes continuam legíveis.
Como verifiquei que nada mais mudou
Os testes de captura de tela que geram as imagens da loja viraram minha bateria de regressão. Depois da migração gerei de novo as dezesseis imagens da loja e olhei o que o git marcava como modificado. Quinze eram idênticas aos arquivos confirmados, e a que diferia era o erro do apóstrofo acima.
Para os dados salvos, instalei a compilação do código antigo, joguei algumas jogadas e instalei a nova por cima sem desinstalar. Depois de reiniciar o app por completo, o tabuleiro, a pontuação e o recorde eram os mesmos. Como o caminho do arquivo de dados e as chaves não mudam, essa verificação é barata e vale a pena antes de qualquer versão.
Perguntas frequentes
Posso usar o plugin de aplicativo Android e o Kotlin Multiplatform em um módulo com o AGP 9?
Não. Coloque o código compartilhado em um módulo de biblioteca com o plugin de biblioteca Android para multiplataforma e mantenha o módulo do aplicativo separado.
Por que meus testes unitários compartilhados não rodaram depois da migração?
O teste de host do Android não vem ativado por padrão com o plugin novo. Ative-o no bloco Android do módulo e confira se o número de testes é o esperado.
O Compose Resources interpreta a barra invertida antes de um apóstrofo?
Não. Use um apóstrofo normal nos arquivos de textos compartilhados em vez do escape no estilo Android.
O simulador de iOS para Intel ainda funciona com o Compose Multiplatform?
Na minha compilação as bibliotecas não foram resolvidas para esse destino, então o removi e mantive o simulador arm64 e dispositivos reais.
Mais do blog
- Por que meu link da App Store deu 404 e a página mostrava capturas de 2018
- Diretriz 2.1 da App Store "Information Needed": o que enviei
- Capturas de tela da App Store sem celular: Robolectric, um carregador de imagens falso e um navegador sem interface
- Um código QR para duas lojas de apps: uma pequena página de redirecionamento
- Reescrever para Kotlin Multiplatform sem mudar o comportamento: o código antigo como oráculo de testes
- Uma lista remota sem servidor para "Mais jogos": um arquivo JSON no GitHub Pages