Migrar una app Android a Kotlin Multiplatform con AGP 9: siete trampas
Por Nesim Razon, desarrollador Android independiente · 2026-11-14
Pasé un pequeño juego en Compose a Kotlin Multiplatform para que también funcione en iPhone. La parte de Kotlin fue fácil, la configuración de la compilación no. Estas son las siete trampas que encontré con Android Gradle Plugin 9 y Compose Multiplatform, en el orden en que las encontré, y las comprobaciones que me dijeron que nada más había cambiado.
1. El plugin de aplicación y el multiplataforma ya no comparten módulo
Con Android Gradle Plugin 9, el plugin de Kotlin Multiplatform no se puede aplicar a un módulo que también usa el plugin de aplicación Android. El código compartido necesita su propio módulo de biblioteca con el nuevo plugin de biblioteca Android para multiplataforma. El módulo de la app sigue siendo una aplicación Android normal y depende de él. La guía de migración de Kotlin pide además un Gradle reciente, 9.1 o superior.
2. Pruebas unitarias que dejan de ejecutarse en silencio
Pasé las reglas del juego y sus diez pruebas unitarias al módulo compartido, ejecuté la compilación y obtuve un resultado verde. Después miré el registro: la tarea de pruebas Android del módulo compartido decía que no había nada que ejecutar. Con el plugin nuevo, la prueba de host de Android está desactivada hasta que la activas.
Declarar una prueba de host en la parte Android del módulo lo arregló, y el archivo de resultados mostró diez pruebas ejecutadas y ninguna fallida. La lección: tras una migración, cuenta las pruebas, no te fíes solo del verde.
3. Compose Resources necesita los recursos de Android activados
Los textos y las fuentes pasaron al módulo compartido como Compose Resources. Mis pruebas de capturas fallaron entonces con un error de recurso ausente que apuntaba a un archivo de textos compilado. Añadir una llamada de configuración de vista previa en las pruebas no ayudó. Lo que lo arregló fue activar los recursos de Android en el bloque Android del módulo compartido, junto con incluir los recursos de Android en la prueba de host.
4. Una barra invertida que sobrevivió a la migración
Los archivos de textos de Android escapan el apóstrofo con una barra invertida. Compose Resources no la interpreta, así que el diálogo de estadísticas en turco mostraba 2048\'e en lugar de 2048'e. La solución es usar un apóstrofo normal en los textos copiados.
Solo lo encontré gracias a la siguiente comprobación. Nada se cerró y ninguna prueba falló; el texto simplemente estaba un poco mal.
5. Nombres de prueba que Kotlin/Native no acepta
Una prueba tenía una coma en su nombre entre acentos graves, algo inofensivo en Android. Al compilar el destino de pruebas de iOS, se detuvo con un mensaje de que el nombre contiene caracteres no permitidos. Reescribir el nombre sin la coma lo arregló.
6. Un destino de simulador que ya no existe
Había listado los destinos de simulador de iOS para Macs Apple silicon e Intel. La compilación informó de un fallo de resolución de dependencias: las bibliotecas de Compose Multiplatform no estaban publicadas para el destino de simulador Intel. Quité ese destino, así que la compilación cubre el simulador arm64 y los dispositivos reales.
7. Un DataStore por archivo
El código Android antiguo usaba un delegado que creaba un DataStore por proceso. En el código compartido creo yo el almacén y lo paso; dos almacenes abiertos sobre el mismo archivo hacen que la app se cierre. Por eso mantengo una única instancia detrás de un pequeño objeto contenedor en Android, apuntando al mismo archivo que usaba el delegado antiguo, de modo que las partidas guardadas existentes siguen siendo legibles.
Cómo comprobé que nada más había cambiado
Las pruebas de capturas que generan las imágenes de la tienda se convirtieron en mi batería de regresión. Tras la migración regeneré las dieciséis imágenes de la tienda y miré qué marcaba git como modificado. Quince eran idénticas a los archivos confirmados, y la que difería era el fallo del apóstrofo de arriba.
Para los datos guardados instalé la compilación del código antiguo, jugué unos movimientos y luego instalé la nueva encima sin desinstalar. Tras reiniciar la app por completo, el tablero, la puntuación y el récord eran los mismos. Como la ruta del archivo de datos y las claves no cambian, esa comprobación es barata y vale la pena antes de cualquier versión.
Preguntas frecuentes
¿Puedo usar el plugin de aplicación Android y Kotlin Multiplatform en un módulo con AGP 9?
No. Pon el código compartido en un módulo de biblioteca con el plugin de biblioteca Android para multiplataforma y deja el módulo de aplicación aparte.
¿Por qué no se ejecutaron mis pruebas unitarias compartidas tras la migración?
La prueba de host de Android no está activada por defecto con el plugin nuevo. Actívala en el bloque Android del módulo y comprueba que el número de pruebas es el esperado.
¿Compose Resources interpreta la barra invertida antes de un apóstrofo?
No. Usa un apóstrofo normal en los archivos de textos compartidos en lugar del escape al estilo Android.
¿Sigue funcionando el simulador de iOS para Intel con Compose Multiplatform?
En mi compilación las bibliotecas no se resolvieron para ese destino, así que lo quité y dejé el simulador arm64 y los dispositivos reales.
Más del blog
- Por qué mi enlace de la App Store dio 404 y la página mostraba capturas de 2018
- Guía 2.1 de App Store «Information Needed»: lo que envié
- Capturas de App Store sin teléfono: Robolectric, un cargador de imágenes falso y un navegador sin interfaz
- Un código QR para dos tiendas de apps: una pequeña página de redirección
- Reescribir para Kotlin Multiplatform sin cambiar el comportamiento: el código antiguo como oráculo de pruebas
- Una lista remota sin servidor para «Más juegos»: un archivo JSON en GitHub Pages