Glosario y fuentes
Al terminar: Tener a mano cada término, cada versión y cada URL oficial.
Todo el vocabulario de la guía en un sitio, la tabla maestra de versiones y el índice de fuentes oficiales. Esta lección es para volver, no para leer de corrido.
Las versiones de abajo no están escritas de memoria: son las que el curso instala en el catálogo de tu proyecto (Gradle Scripts → libs.versions.toml (Version Catalog "libs"), en la vista Android). Eso también significa que caducan, y al final tienes los comandos para comprobarlas por tu cuenta.
El vocabulario que se confunde
Estos cinco nombres se usan como sinónimos por ahí fuera y no lo son. Distinguirlos es lo que te permite entender de qué habla cada artículo.
| Término | Qué es exactamente |
|---|---|
| KMP — Kotlin Multiplatform | La tecnología de compartir código Kotlin entre plataformas. No incluye la interfaz |
| CMP — Compose Multiplatform | El kit de interfaz de JetBrains que corre sobre KMP. Opcional |
| Jetpack Compose | El kit de interfaz de Google. Solo Android |
| Kotlin/Native | El compilador de Kotlin a binario nativo. Es lo que hace posible iOS |
| KMM | Nombre retirado. Si lo ves, el texto es viejo |
Construcción y estructura
| Término | Definición |
|---|---|
| Target | Una plataforma de salida: androidTarget, iosArm64, jvm… |
| Source set | Una carpeta de código que compila para uno o varios targets: commonMain, iosMain. Ver Qué es KMP y qué no |
| Jerarquía de source sets | El árbol que hace que iosMain vea lo de appleMain y lo de commonMain |
| klib | El artefacto intermedio de Kotlin/Native, por target |
| Framework | El paquete que Xcode sabe enlazar. Se genera desde los klibs |
| XCFramework | Un framework que contiene varias arquitecturas. Para distribuir |
| Version catalog | El libs.versions.toml con las versiones en un solo sitio, en tres secciones: [versions], [libraries] y [plugins] |
| Receta «Instala X» | Los pasos con que esta guía añade una librería o un plugin: versión, librería o plugin en el catálogo, dependencia en el módulo, Sync Now y comprobación. Ver Los ficheros de Gradle de tu proyecto |
| Sync Now | El botón de Android Studio que vuelve a leer los ficheros de Gradle tras un cambio |
| Vista Android | La forma de ver el proyecto en Android Studio (app → kotlin+java, Gradle Scripts…); la guía nombra siempre los nodos de esta vista |
| Plugin de compilador | Plugin que se mete en el compilador de Kotlin y genera código al compilar (serialización, KMP-NativeCoroutines) |
api / implementation / export | Si una dependencia asoma en la cara pública del módulo, si queda dentro, y si además se mete en el framework de iOS. Ver La primera dependencia |
| Paquete de Swift | Una dependencia de la app de iOS que se añade en Xcode (File → Add Package Dependencies…); Package.resolved apunta la versión exacta que se descargó |
| Esquema compartido (Xcode) | Un esquema marcado como Shared: se guarda en el proyecto y no en tu configuración personal, así lo ven Xcode y xcodebuild. Ver Pruebas de interfaz en iOS |
| Metadatos Gradle | El fichero .module que dice qué targets publica una librería |
| KSP | Kotlin Symbol Processing: la generación de código que usa Room |
| ABI | La cara binaria de tu API. Lo que compara checkKotlinAbi |
Lenguaje
| Término | Definición |
|---|---|
expect / actual | Declaración común con implementación por plataforma |
| Interfaz + inyección | La alternativa preferida a expect/actual cuando basta |
sealed | Jerarquía cerrada: todas las subclases se conocen al compilar. Ver Sealed y enum |
value class | Clase que se borra a su tipo interno. No la exportes |
| Función de extensión | Función que se escribe como método pero se resuelve estáticamente |
| Concurrencia estructurada | Las corrutinas forman un árbol; el padre espera a los hijos y cancelarlo los cancela |
| Flujo frío | Cada colector arranca su propia ejecución. Ver Flow frío |
| Flujo caliente | Emite haya o no colectores, y todos comparten la misma emisión |
StateFlow | Flujo caliente con valor actual siempre disponible. Para estado. Ver StateFlow y SharedFlow |
SharedFlow | Flujo caliente sin valor inicial. Para eventos |
Mutex | Cerrojo que suspende en vez de bloquear. La opción estable en común |
La frontera con Swift
| Término | Definición |
|---|---|
| Interop de Objective-C | El puente por el que pasa hoy todo lo que va de Kotlin a Swift |
| Boxing | Meter un primitivo en una clase (Int? → KotlinInt?) |
| Mangling | Renombrado automático ante colisiones (description → description_) |
| Lightweight generics | Los genéricos de Objective-C: solo admiten tipos-clase |
XxxKt | La clase donde acaban las funciones de nivel superior de Xxx.kt |
| Completion handler | El bloque en que se convierte una función suspend |
@NativeCoroutines | Anotación de KMP-NativeCoroutines que hace recorrible un Flow o una suspend desde Swift (asyncSequence(for:), asyncFunction(for:)). Ver Un Flow hasta Swift y Cancelar desde Swift |
Sufijo Flow | Con @NativeCoroutinesState, uiStateForIos es el valor y uiStateForIosFlow la secuencia de cambios |
| Argumentos por defecto | No cruzan a Swift: la firma lleva todos los parámetros. Ver Corrutinas en commonMain |
| Swift export | La exportación directa a Swift, sin Objective-C. En Alpha |
| ARC | El conteo de referencias de Objective-C y Swift, que convive con el GC de Kotlin. Ver ARC |
Arquitectura
| Término | Definición |
|---|---|
| UDF | Flujo unidireccional: el estado baja, los eventos suben |
UiState | El estado completo de una pantalla, en un solo objeto |
| Repositorio | La capa que decide de dónde salen los datos (red, disco o las dos). Ver Red en Marcador: la lista de árbitros y en iOS |
| DTO | El objeto que refleja el JSON. No es tu modelo de dominio. Ver Red: HTTP y JSON y Red: HTTP, JSON y URLSession |
| Código de estado HTTP | El número con que el servidor resume su respuesta: 2xx fue bien, 4xx la petición no puede cumplirse (repetirla da lo mismo) y 5xx falla el servidor (puede valer la pena reintentar). Ver Red: HTTP y JSON y en iOS |
| Error de dominio | Un fallo traducido a los términos de la app (SinConexion, Servidor(código)) en vez de la excepción cruda de la librería de red; la pantalla solo ve este. Ver POST y errores de red y en iOS, y AppError en Errores que se pueden contar |
| Local primero | La copia local (Room en Android, un fichero JSON en iOS) es la fuente de verdad; la red solo la actualiza. Ver Dos fuentes: el almacén y el repositorio y su gemela de iOS |
| Fuente de verdad (SSOT) | Un solo dueño por tipo de dato: cuando dos fuentes (local y remota) discrepan, manda él y el resto se actualiza desde él. Ver Dos fuentes: el almacén y el repositorio y su gemela de iOS y, en la Pokédex, La base como fuente de verdad |
| Caché | Una copia guardada de datos que vienen de otro sitio, para no tener que pedirlos otra vez. En la Pokédex, la base de datos guarda la copia de la lista que se pidió a PokeAPI. Ver La base como fuente de verdad |
RemoteMediator | La pieza de Paging que pide páginas a la red y las escribe en la base, mientras la pantalla lee solo de la base. Ver El RemoteMediator: la red llena la base |
| Clave de página | El dato con que se sabe qué página pedir a continuación (aquí, el desplazamiento desde el que sigue la lista), guardado en la base para no perderlo al cerrar la app. Ver El RemoteMediator: la red llena la base |
| Caducidad de la copia | El tiempo a partir del cual lo guardado se considera viejo y se vuelve a pedir a la red al abrir la lista (12 horas en la Pokédex). Ver El repositorio con dos fuentes |
| Caso de uso | Una clase con una sola acción de negocio: encierra una regla (RegistrarGol) o junta varios repositorios; sobra si solo reenvía una llamada. Ver Casos de uso: cuándo sí y cuándo sobran y su gemela de iOS |
| Retrofit y OkHttp | Las librerías de Android para hablar con un servidor: Retrofit convierte una interfaz anotada en peticiones y OkHttp las envía. Ver Retrofit y la primera llamada |
| URLSession y ATS | El cliente de red que trae iOS, y la regla del sistema (App Transport Security) que exige HTTPS salvo excepción. Ver Red: HTTP, JSON y URLSession |
| Fake | Implementación real y simple de una interfaz, para tests. Ver Tests de un ViewModel: fakes, setMain y Turbine y, en iOS, Tests en iOS: falsos y espías |
| Inyección de dependencias | Que una clase reciba lo que necesita en vez de construirlo; alguien las monta en un grafo (Hilt en Android, Koin en la Pokédex, un contenedor escrito a mano en iOS). Ver Hilt: instalarlo y el primer módulo, Inyección en todas las capas, en iOS y Koin: un solo grafo en commonMain |
| Alcance de una dependencia | Cuánto vive una pieza que se inyecta: toda la app (proceso), una pantalla o una sola llamada. No es el CoroutineScope. Ver Inyección en todas las capas y en iOS |
| Estado de toda la app | Un dato que varias pantallas leen a la vez, como el partido en juego de Marcador. Vive en una sola instancia de la capa de datos o de dominio (en Android, un @Singleton; en iOS, un objeto del contenedor que se reparte con .environment) y cada pantalla lo observa en vez de guardar su copia. Solo se sube hasta ahí cuando lo leen varias pantallas a la vez y tiene que seguir vivo cuando la suya se cierra; con una sola de las dos condiciones, basta un peldaño más abajo (el remember o el ViewModel de la pantalla). Ver Estado de toda la app: el partido en juego y Estado de toda la app en SwiftUI |
| Alcance de app frente a pantalla | Quién es el dueño de un dato o de un trabajo. Si es la pantalla (remember, el ViewModel con su viewModelScope, el .task de una vista), muere con ella. Si es la app (una pieza @Singleton y el alcance @AlcanceDeApp en Android, un objeto del contenedor en iOS), vive mientras viva el proceso. Lo que debe seguir tras cerrar la pantalla, como el partido en juego, va en el de la app. No es lo mismo que el alcance de una dependencia (arriba), que habla de cuánto vive la pieza inyectada, no de quién lanza el trabajo. Ver El partido sigue aunque salgas y en iOS |
| Anotación | Una marca con @ delante de una clase o función (@Inject, @Module) que no cambia lo que hace el código, sino que lo lee una herramienta al compilar. Ver Hilt: instalarlo y el primer módulo |
| Hilt (Dagger Hilt) | La librería de Google que monta por ti las piezas de una app Android: lee las anotaciones al compilar y genera el código que las crea y las conecta. Está construida sobre Dagger. Solo funciona en Android. Ver Hilt: instalarlo y el primer módulo |
| Módulo (Hilt) | Una clase marcada con @Module e @InstallIn que explica a Hilt cómo conseguir piezas que no puede construir solo (la base de datos, el cliente de red). No es un módulo de Gradle. Ver Hilt: instalarlo y el primer módulo e Inyección en todas las capas |
@Provides / @Binds | Las dos maneras de dar una pieza en un módulo de Hilt: @Provides es una función que la construye; @Binds dice «cuando pidan esta interfaz, entrega esta implementación». Ver Hilt: instalarlo y el primer módulo e Inyección en todas las capas |
| Inyección asistida | Hilt construye casi todo el ViewModel, pero un dato (como el id del partido) llega desde fuera, en el momento de crearlo. Ver El id del partido: inyección asistida |
| Cualificador | Una etiqueta propia (como @AlcanceDeApp) que distingue dos piezas del mismo tipo para que Hilt sepa cuál entregar. Ver El repositorio con Room |
| Entidad, DAO y migración (Room) | La tabla, las consultas que se le hacen y el paso de una versión de la base de datos a la siguiente. Ver Room: entidades y DAO, Room: migrar la base de datos y Persistencia con Room 3 |
| Deep link | Un enlace que abre una pantalla concreta de la app (pokedex://pokemon/6). Ver Deep links en Android |
| Universal Link | Un enlace https que iOS abre en tu app sin diálogo porque el dueño del dominio la respalda. Ver Deep links en iOS |
| Token de acceso y de refresco | El de acceso caduca pronto y se manda en cada petición; el de refresco sirve para pedir otro. Ver Autenticación en el núcleo |
| Llavero (Keychain) | El almacén cifrado de iOS donde se guardan los tokens. Ver Guardar los tokens |
Fundamentos de Kotlin y corrutinas
Los términos que se usan en toda la guía y que se enseñan desde cero en los fundamentos.
| Término | Definición |
|---|---|
| Nulabilidad | Que el tipo diga si un valor puede faltar: String nunca es null, String? sí. El compilador te obliga a decidir qué hacer en ese caso. Ver Nulabilidad |
| Smart cast | Tras comprobar un tipo o un null, el compilador ya trata el valor como el tipo más concreto sin conversión explícita. Ver Nulabilidad |
data class | Clase para guardar datos: el compilador genera equals, copy y toString. Ver Data class |
| Lambda | Función sin nombre que se pasa como valor: { x -> x + 1 }. Ver Lambdas |
| Función de orden superior | Función que recibe otra función o la devuelve. Es lo que hace posible map, filter y los bloques como launch { }. Ver Lambdas |
suspend | Marca una función que puede pausarse sin bloquear el hilo y reanudarse después. Solo se llama desde otra suspend o desde una corrutina. Ver Corrutinas y suspend |
| Corrutina | Un trabajo ligero que se puede pausar y reanudar; muchas caben en un solo hilo. Ver Corrutinas y suspend |
Scope (CoroutineScope) | El ámbito que es dueño de un grupo de corrutinas: si se cancela, se cancelan todas las que lanzó. Ver Scope y cancelación |
| Dispatcher | Decide en qué hilo o grupo de hilos corre una corrutina (Main, IO, Default). Ver Dispatchers |
| Flow | Una secuencia de valores que llegan con el tiempo, producida y consumida con corrutinas. Ver Flow frío |
Fundamentos de Android y Compose
| Término | Definición |
|---|---|
| Activity | La pieza de Android que muestra una pantalla y tiene un ciclo de vida que el sistema controla. Ver La Activity y El ciclo de vida de la Activity |
| Context | El acceso de un componente al sistema Android: recursos, servicios, nombre del paquete. Hay uno de Application y otro por Activity. Ver Context |
| Intent | El mensaje con el que una app pide algo al sistema o a otra app: abrir una pantalla, compartir un texto. Ver Intents |
| WorkManager | La API de Android para trabajo en segundo plano que debe cumplirse aunque la app se cierre, sin exigir hora exacta. Ver Trabajo en segundo plano |
| ViewModel | La clase que guarda el estado de una pantalla y sobrevive a la rotación; en Android muere con la pantalla. Ver ViewModel: qué sobrevive |
| Composable | Una función marcada con @Composable que describe un trozo de interfaz. Ver Compose: composables y modifiers |
| Recomposición | Volver a ejecutar solo los composables cuyo estado ha cambiado. Vocabulario de Compose, no de SwiftUI. Ver Recomposición |
| State hoisting | Subir el estado al padre y bajar solo el valor y los eventos, para que el composable no guarde estado propio. Ver State hoisting |
Campo de texto (TextField) | El cuadro donde el usuario escribe. No guarda lo escrito: recibe el texto (value) y avisa de cada cambio (onValueChange), y quien lo usa es el dueño del texto. Ver Campos de texto: TextField |
IME / ImeAction | El IME (Input Method Editor) es el teclado en pantalla. ImeAction es la tecla de acción de su esquina (por ejemplo «Siguiente» o «Hecho») y qué hace al pulsarla. Ver Formularios: la pantalla, el teclado y las pruebas |
| Campo tocado y error calculado | En un formulario, un campo está «tocado» cuando el usuario ya ha escrito en él, y solo entonces se enseña su error. El error no se guarda: se calcula cada vez a partir del texto y de las reglas, y por eso no puede quedarse viejo. Ver Formularios: el estado y las reglas |
TextFieldState | La forma más nueva de guardar el texto de un campo en Compose: un objeto que se le pasa al campo en vez de value y onValueChange. Ver La forma más nueva: TextFieldState y SecureTextField |
| Siembra tras una migración | Una migración de Room crea una tabla nueva, pero la crea vacía, también en un móvil que ya tenía datos. Rellenarla (sembrarla) con los datos iniciales es trabajo aparte. Ver La plantilla, guardada en Room |
Chuleta de adb
adb (Android Debug Bridge, «puente de depuración de Android») es el programa de la terminal que habla con el emulador o con un móvil conectado. Las lecciones de Android lo usan con estas órdenes; aquí están todas juntas y cada lección te trae a esta tabla la primera vez que las necesita. Se escriben en la Terminal de Android Studio (View → Tool Windows → Terminal) o en cualquier terminal. Si responde command not found, falta el paso del PATH de Instalar Android Studio y el SDK.
adb shell abre una terminal dentro del dispositivo: lo que escribes después se ejecuta allí, no en tu ordenador. Dentro hay herramientas del sistema que verás en las tablas: am (activity manager, el gestor de actividades) arranca, para o mata cosas de las apps; pm (package manager, el gestor de paquetes) sabe qué apps hay instaladas y qué permisos tienen; dumpsys imprime el estado interno de un servicio del sistema; settings cambia un ajuste del móvil; input simula toques y teclas; pidof dice el número de proceso de una app. En los ejemplos, com.sebastiannarvaez.marcador es el identificador de la app (applicationId); las variantes de Gradle: flavors y variantes añaden .debug o .pro.
Logcat, el registro
| Orden | Qué hace |
|---|---|
adb logcat -c | Vacía el registro, para que lo siguiente sea solo lo nuevo |
adb logcat -d -s Ciclo | -d imprime lo que hay y termina; -s deja solo las líneas con ese tag (la etiqueta del mensaje). Admite varios: -s Ciclo Trabajo |
adb logcat -s LeakCanary | Sin -d no termina: va imprimiendo las líneas según llegan, hasta que pulses Ctrl+C. Sirve para esperar a que aparezca algo |
Instalar y arrancar
| Orden | Qué hace |
|---|---|
adb devices | Lista los dispositivos conectados; un emulador sale como emulator-5554 |
adb install -r app/build/outputs/apk/debug/app-debug.apk | Instala un APK; -r reinstala encima si ya estaba, conservando sus datos |
adb uninstall com.sebastiannarvaez.marcador | Desinstala la app |
adb shell am start -n com.sebastiannarvaez.marcador/.MainActivity | Arranca una pantalla por su nombre: paquete, barra y clase (el punto inicial quiere decir «dentro del paquete de la app») |
adb shell am start -a android.intent.action.VIEW -d "marcador://partido/2" | Arranca lo que sepa abrir ese enlace: -a es la acción del Intent y -d su dirección |
adb shell am force-stop com.sebastiannarvaez.marcador | Para la app y borra de la memoria todo lo suyo |
Estado de una app
| Orden | Qué hace |
|---|---|
adb shell pidof com.sebastiannarvaez.marcador | Imprime el número de proceso (pid) de la app; no imprime nada si no está en marcha |
adb shell am kill com.sebastiannarvaez.marcador | Mata el proceso solo si la app está en segundo plano, como haría el sistema al faltarle memoria. Justo después de pulsar Home puede no hacer nada: si pidof sigue dando un número, espera unos segundos y repite |
adb shell pm list packages marcador | Lista las apps instaladas cuyo nombre contiene esa palabra |
adb shell pm revoke com.sebastiannarvaez.marcador android.permission.POST_NOTIFICATIONS | Quita un permiso a la app (pm grant en lugar de pm revoke lo concede) |
El dispositivo
| Orden | Qué hace |
|---|---|
adb shell getprop ro.build.version.sdk | El nivel de API del dispositivo (Android 15 es el 35) |
adb shell settings put system accelerometer_rotation 0 | Bloquea el giro automático |
adb shell settings put system user_rotation 1 | Fuerza la orientación (con el giro bloqueado): 1 es horizontal y 0 vertical |
adb shell input tap 500 700 | Toca la pantalla en esas coordenadas, en píxeles |
adb shell input keyevent KEYCODE_HOME | Pulsa el botón Home |
adb shell cmd connectivity airplane-mode enable | Enciende el modo avión del emulador o del móvil (disable lo apaga). Tarda unos segundos en cortar la red. Probado en Android 15 (API 35); en versiones muy antiguas la orden puede no existir y habrá que usar los ajustes rápidos |
Para mirar las notificaciones publicadas, dumpsys se combina con un filtro:
adb shell "dumpsys notification | grep -A3 goles"Imprime las líneas que mencionan goles y las tres siguientes. Las comillas hacen que grep corra dentro del móvil, no en tu ordenador. Un | grep fuera de las comillas correría en tu ordenador.
Fundamentos de Swift y SwiftUI
| Término | Definición |
|---|---|
| Opcional | El equivalente Swift de un tipo con null: Int? puede ser un valor o nil. Se desenvuelve con if let, guard let o ??. Ver Opcionales |
| Protocolo | Una lista de métodos y propiedades que un tipo promete tener; es la interfaz de Swift. Ver Protocolos y extensiones |
| Closure | La lambda de Swift: un bloque de código que se pasa como valor y captura lo que usa de su entorno. Ver Closures |
| Actor | Un tipo de Swift que protege su estado: solo una tarea a la vez accede a él. Ver Actores |
| Retain cycle | Dos objetos que se referencian con referencias fuertes y por eso ARC nunca los libera. Se rompe con weak o unowned. Ver Retain cycles |
@MainActor | Marca código que solo se ejecuta en el hilo principal, el único que puede tocar la interfaz. Ver @MainActor |
@State | El estado propio de una vista de SwiftUI, guardado por SwiftUI y no por la vista. Ver @State |
@Binding | Una referencia de lectura y escritura a un @State que vive en otra vista. Ver @Binding |
@StateObject | El dueño de un objeto observable: lo crea una vez y lo conserva mientras la vista exista. Ver ObservableObject y @StateObject |
@Observable | La macro de iOS 17 que hace observable una clase sin @Published. Ver @Observable |
@Entry | La macro de SwiftUI que añade tu propio valor al entorno, como los que ya trae (\.dismiss): @Entry var abrirPartido: (Int) -> Void = { _ in } se lee en cualquier vista con @Environment(\.abrirPartido). Lleva un valor por defecto, así que si nadie lo pone no ocurre nada; con un objeto leído con @Environment(Tipo.self) es distinto: si falta, la app se detiene. Ver La barra del partido en juego, en iOS |
Binding(get:set:) | Un enlace (Binding) construido a mano con dos funciones, una que lee y otra que escribe, para cuando lo que enseña la vista no es lo mismo que lo que guarda. En Marcador, el selector de duración lee la de este partido y escribe la preferencia. Ver Solo un partido a la vez, en iOS |
.contentShape(.rect) | Dice a SwiftUI qué parte de una vista responde al toque. Con .buttonStyle(.plain), un botón de solo un dibujo (como la X de la barra del partido) solo responde en el dibujo, aunque su .frame sea mayor; .contentShape(.rect) hace tocable todo el rectángulo. Lo marca la auditoría de accesibilidad de Xcode como «Hit area is too small» cuando falta. Ver La barra del partido en juego, en iOS |
TextField | El campo de texto de SwiftUI. Se crea con un título y un enlace (text: $dato) al String donde escribe cada cambio. Ver Campos de texto en SwiftUI |
@FocusState | Guarda qué campo tiene el foco (el que recibe lo que tecleas). Se enlaza a cada campo con .focused(…), y cambiar su valor mueve el foco de un campo a otro. Ver Formularios en SwiftUI: Form, foco y guardar |
Form | El contenedor de SwiftUI para pantallas con campos: los agrupa en secciones (Section) con el aspecto de un formulario de iOS. Ver Formularios en SwiftUI: Form, foco y guardar |
LabeledContent | Una fila con un rótulo a un lado y un valor al otro, como «Rayo FC — 3 jugadores». Ver Equipos y plantillas en iOS |
La tabla maestra de versiones
Esto es lo que compila hoy la app de esta guía. Cada número sale de leer el catálogo, no de recordarlo.
Cadena de herramientas
| Pieza | Versión | De dónde sale |
|---|---|---|
| Kotlin | 2.4.20 | libs.versions.toml |
| AGP | 9.4.0 | libs.versions.toml (en Marcador, 9.4.1) |
| KSP | 2.3.12 | libs.versions.toml |
compileSdk | 37 | libs.versions.toml |
targetSdk | 37 | libs.versions.toml |
minSdk | 24 | libs.versions.toml |
| Gradle | 9.7.1 | gradle/wrapper/gradle-wrapper.properties (en Marcador, 9.6.0) |
Librerías del núcleo
| Librería | Versión | Nota |
|---|---|---|
| kotlinx-coroutines | 1.11.0 | Dispatchers.IO no está en commonMain |
| kotlinx-serialization | 1.11.0 | |
| Ktor | 3.5.2 | Cliente + un motor por plataforma |
| Room 3 | 3.0.3 | androidx.room3, no androidx.room |
| room3-paging | 3.0.3 | El PagingSource de Room en commonMain (androidx.room3.paging); la lista sin conexión lo necesita |
| androidx.sqlite (bundled) | 2.7.1 | El driver recomendado: SQLite dentro del binario |
| DataStore Preferences | 1.2.1 | Solo la variante preferences-core en KMP; trae Okio por dentro, sin declararlo |
| kotlinx-datetime | 0.8.0 | Sigue en 0.x y su README avisa de que la API puede cambiar |
| Koin | 4.2.2 | Publica targets de iOS |
| Kermit | 2.2.0 | Registro multiplataforma |
| KMP-NativeCoroutines | 1.0.6 | El puente de Flow a AsyncSequence |
Librerías de la app de Android
| Librería | Versión | Nota |
|---|---|---|
| lifecycle (ViewModel) | 2.11.0 | Publica variantes de iOS: por eso el ViewModel es común |
| Navigation 3 | 1.1.7 | androidx.navigation3 |
| Paging | 3.5.1 | paging-common es multiplataforma; paging-compose, no |
| Coil | 3.6.2 | Con coil-network-ktor3 |
| WorkManager | 2.12.0 | Solo Android |
| Compose BOM | 2026.08.00 | Fija de golpe todas las versiones de Compose |
| activity-compose | 1.13.0 | |
| core-ktx | 1.19.0 | |
| core-splashscreen | 1.2.0 |
Pruebas
| Librería | Versión |
|---|---|
| Turbine | 1.2.1 |
| Robolectric | 4.17 |
| JUnit 4 | 4.13.2 |
Y la versión de la app, que también vive ahí
# La version de la app, en un solo sitio. Android la lee aqui y el .xcconfig de
# iOS tiene la misma: si se tocan por separado, las dos tiendas acaban
# publicando numeros distintos de la misma version.
appVersionName = "1.0.0"
appVersionCode = "1"Lo que no sale del catálogo
Tres cosas que se mencionan en la guía y no están en la Pokédex. Se citan por su documentación, no por haberlas compilado aquí:
| Pieza | Estado | Por qué no está |
|---|---|---|
| Compose Multiplatform | 1.12.0, iOS Stable | Esta app usa interfaz nativa en cada plataforma |
| SKIE | Alternativa a KMP-NativeCoroutines | No se usa: el puente elegido fue el otro |
| Hilt | Sin targets nativos | Por eso la inyección es Koin |
Índice de fuentes oficiales
Todas las páginas citadas en la guía, agrupadas.
Kotlin y Kotlin Multiplatform
- Releases de Kotlin
- Null safety
- Clases selladas
- Corrutinas: fundamentos
- Flujos: fríos y calientes
- Contexto y dispatchers
- Gestor de memoria de Kotlin/Native
- Migración del gestor de memoria
- Integración con ARC
- Interoperabilidad con Objective-C
- Simbolicación en iOS
- Swift export (Alpha)
- Binarios nativos
- Referencia del DSL multiplataforma
- Migrar desde Android
- Integración directa con Xcode
- Publicar una librería multiplataforma
- Exportar a Swift Package Manager
- Integración con CocoaPods
- Validación de compatibilidad binaria
- Componentes que solo existen en Android
JetBrains — Compose Multiplatform
- Plataformas soportadas y estabilidad
- Compose Multiplatform frente a Jetpack Compose
- Integración con SwiftUI
- Integración con UIKit
Google — Android
- Kotlin Multiplatform en Android
- Migrar a Kotlin Multiplatform
- Plugin de librería Android para KMP
- ViewModel para KMP
- Room para KMP
- DataStore para KMP
- Guía de arquitectura
- Offline-first: la capa de datos
- La capa de dominio (casos de uso)
- Inyección de dependencias con Hilt
- Hilt, en la documentación de Dagger
- Estado en Compose
- Notas de versión de Room 2.x
- Notas de versión de Room 3
Apple y Swift
- El libro de Swift: concurrencia
- El libro de Swift: clases y estructuras
- El libro de Swift: encadenamiento opcional
- Swift 6.2 publicado
- SwiftUI:
State - Observation:
@Observable URLSession.data(from:delegate:)- Traer datos de un sitio web a memoria
NSAppTransportSecurity- SwiftUI:
refreshable(action:)
Servicios y estándares web
Gradle y herramientas
Librerías
- Ktor: motores del cliente
- Ktor: probar el cliente
- Koin: Kotlin Multiplatform
- Retrofit
- OkHttp:
OkHttpClient - KMP-NativeCoroutines
- kotlinx.coroutines: código fuente
Reto · Comprueba una versión tú mismo
Sin fiarte de la tabla de arriba: averigua cuál es la última versión estable de Koin y si sirve para iOS.
Ver solución
Dos comandos.
La versión:
curl -s "https://repo1.maven.org/maven2/io/insert-koin/koin-core/maven-metadata.xml" \
| grep -o "<version>[^<]*</version>" | grep -viE "alpha|beta|rc" | tail -1Se filtran los preestables a propósito: la etiqueta <release> del propio fichero a veces apunta a un rc, así que fiarse de ella es justo el error que este comando evita.
Si sirve para iOS:
curl -s "https://repo1.maven.org/maven2/io/insert-koin/koin-core/4.2.2/koin-core-4.2.2.module" \
| grep -o '"org.jetbrains.kotlin.native.target": "[^"]*"' | sort -uSi salen líneas con ios_arm64 y ios_simulator_arm64, sirve. Si no sale ninguna —como pasa con hilt-android— la librería es solo de la JVM, diga lo que diga su web.
Este par de comandos responde en treinta segundos a la pregunta que más tiempo hace perder en KMP: «¿esta librería sirve para multiplataforma?»
Y un tercero, que es el que de verdad usas a diario: grep koin gradle/libs.versions.toml. Si tu proyecto tiene catálogo, la pregunta «¿qué versión estoy usando?» se responde leyendo un archivo, no recordando.
Comprueba lo que entendiste
5 preguntas · necesitas 4 para completar la lección
1.¿Cuál es la diferencia entre KMP y Compose Multiplatform?
2.Encuentras un artículo que habla de «KMM». ¿Qué te dice eso?
3.Quieres saber si una librería sirve para KMP con iOS. ¿Qué miras?
4.Quieres saber con qué versión de Ktor compila tu proyecto. ¿Cuál es la respuesta correcta?
5.¿Por qué la versión de Gradle no está en el catálogo de versiones?