Saltar al contenido
K
ReferenciaReferencia10 min Introductorio

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érminoQué es exactamente
KMP — Kotlin MultiplatformLa tecnología de compartir código Kotlin entre plataformas. No incluye la interfaz
CMP — Compose MultiplatformEl kit de interfaz de JetBrains que corre sobre KMP. Opcional
Jetpack ComposeEl kit de interfaz de Google. Solo Android
Kotlin/NativeEl compilador de Kotlin a binario nativo. Es lo que hace posible iOS
KMMNombre retirado. Si lo ves, el texto es viejo

Construcción y estructura

TérminoDefinición
TargetUna plataforma de salida: androidTarget, iosArm64, jvm…
Source setUna carpeta de código que compila para uno o varios targets: commonMain, iosMain. Ver Qué es KMP y qué no
Jerarquía de source setsEl árbol que hace que iosMain vea lo de appleMain y lo de commonMain
klibEl artefacto intermedio de Kotlin/Native, por target
FrameworkEl paquete que Xcode sabe enlazar. Se genera desde los klibs
XCFrameworkUn framework que contiene varias arquitecturas. Para distribuir
Version catalogEl 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 NowEl botón de Android Studio que vuelve a leer los ficheros de Gradle tras un cambio
Vista AndroidLa 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 compiladorPlugin que se mete en el compilador de Kotlin y genera código al compilar (serialización, KMP-NativeCoroutines)
api / implementation / exportSi 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 SwiftUna 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 GradleEl fichero .module que dice qué targets publica una librería
KSPKotlin Symbol Processing: la generación de código que usa Room
ABILa cara binaria de tu API. Lo que compara checkKotlinAbi

Lenguaje

TérminoDefinición
expect / actualDeclaración común con implementación por plataforma
Interfaz + inyecciónLa alternativa preferida a expect/actual cuando basta
sealedJerarquía cerrada: todas las subclases se conocen al compilar. Ver Sealed y enum
value classClase que se borra a su tipo interno. No la exportes
Función de extensiónFunción que se escribe como método pero se resuelve estáticamente
Concurrencia estructuradaLas corrutinas forman un árbol; el padre espera a los hijos y cancelarlo los cancela
Flujo fríoCada colector arranca su propia ejecución. Ver Flow frío
Flujo calienteEmite haya o no colectores, y todos comparten la misma emisión
StateFlowFlujo caliente con valor actual siempre disponible. Para estado. Ver StateFlow y SharedFlow
SharedFlowFlujo caliente sin valor inicial. Para eventos
MutexCerrojo que suspende en vez de bloquear. La opción estable en común

La frontera con Swift

TérminoDefinición
Interop de Objective-CEl puente por el que pasa hoy todo lo que va de Kotlin a Swift
BoxingMeter un primitivo en una clase (Int? → KotlinInt?)
ManglingRenombrado automático ante colisiones (description → description_)
Lightweight genericsLos genéricos de Objective-C: solo admiten tipos-clase
XxxKtLa clase donde acaban las funciones de nivel superior de Xxx.kt
Completion handlerEl bloque en que se convierte una función suspend
@NativeCoroutinesAnotació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 FlowCon @NativeCoroutinesState, uiStateForIos es el valor y uiStateForIosFlow la secuencia de cambios
Argumentos por defectoNo cruzan a Swift: la firma lleva todos los parámetros. Ver Corrutinas en commonMain
Swift exportLa exportación directa a Swift, sin Objective-C. En Alpha
ARCEl conteo de referencias de Objective-C y Swift, que convive con el GC de Kotlin. Ver ARC

Arquitectura

TérminoDefinición
UDFFlujo unidireccional: el estado baja, los eventos suben
UiStateEl estado completo de una pantalla, en un solo objeto
RepositorioLa 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
DTOEl 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 HTTPEl 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 dominioUn 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 primeroLa 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
RemoteMediatorLa 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áginaEl 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 copiaEl 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 usoUna 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 OkHttpLas 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 ATSEl 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
FakeImplementació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 dependenciasQue 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 dependenciaCuá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 appUn 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 pantallaQuié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ónUna 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 / @BindsLas 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 asistidaHilt 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
CualificadorUna 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 linkUn enlace que abre una pantalla concreta de la app (pokedex://pokemon/6). Ver Deep links en Android
Universal LinkUn 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 refrescoEl 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érminoDefinición
NulabilidadQue 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 castTras 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 classClase para guardar datos: el compilador genera equals, copy y toString. Ver Data class
LambdaFunción sin nombre que se pasa como valor: { x -> x + 1 }. Ver Lambdas
Función de orden superiorFunción que recibe otra función o la devuelve. Es lo que hace posible map, filter y los bloques como launch { }. Ver Lambdas
suspendMarca 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
CorrutinaUn 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
DispatcherDecide en qué hilo o grupo de hilos corre una corrutina (Main, IO, Default). Ver Dispatchers
FlowUna secuencia de valores que llegan con el tiempo, producida y consumida con corrutinas. Ver Flow frío

Fundamentos de Android y Compose

TérminoDefinición
ActivityLa 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
ContextEl acceso de un componente al sistema Android: recursos, servicios, nombre del paquete. Hay uno de Application y otro por Activity. Ver Context
IntentEl mensaje con el que una app pide algo al sistema o a otra app: abrir una pantalla, compartir un texto. Ver Intents
WorkManagerLa 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
ViewModelLa clase que guarda el estado de una pantalla y sobrevive a la rotación; en Android muere con la pantalla. Ver ViewModel: qué sobrevive
ComposableUna función marcada con @Composable que describe un trozo de interfaz. Ver Compose: composables y modifiers
RecomposiciónVolver a ejecutar solo los composables cuyo estado ha cambiado. Vocabulario de Compose, no de SwiftUI. Ver Recomposición
State hoistingSubir 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 / ImeActionEl 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 calculadoEn 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
TextFieldStateLa 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ónUna 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

OrdenQué hace
adb logcat -cVací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 LeakCanarySin -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

OrdenQué hace
adb devicesLista los dispositivos conectados; un emulador sale como emulator-5554
adb install -r app/build/outputs/apk/debug/app-debug.apkInstala un APK; -r reinstala encima si ya estaba, conservando sus datos
adb uninstall com.sebastiannarvaez.marcadorDesinstala la app
adb shell am start -n com.sebastiannarvaez.marcador/.MainActivityArranca 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.marcadorPara la app y borra de la memoria todo lo suyo

Estado de una app

OrdenQué hace
adb shell pidof com.sebastiannarvaez.marcadorImprime el número de proceso (pid) de la app; no imprime nada si no está en marcha
adb shell am kill com.sebastiannarvaez.marcadorMata 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 marcadorLista las apps instaladas cuyo nombre contiene esa palabra
adb shell pm revoke com.sebastiannarvaez.marcador android.permission.POST_NOTIFICATIONSQuita un permiso a la app (pm grant en lugar de pm revoke lo concede)

El dispositivo

OrdenQué hace
adb shell getprop ro.build.version.sdkEl nivel de API del dispositivo (Android 15 es el 35)
adb shell settings put system accelerometer_rotation 0Bloquea el giro automático
adb shell settings put system user_rotation 1Fuerza la orientación (con el giro bloqueado): 1 es horizontal y 0 vertical
adb shell input tap 500 700Toca la pantalla en esas coordenadas, en píxeles
adb shell input keyevent KEYCODE_HOMEPulsa el botón Home
adb shell cmd connectivity airplane-mode enableEnciende 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érminoDefinición
OpcionalEl equivalente Swift de un tipo con null: Int? puede ser un valor o nil. Se desenvuelve con if let, guard let o ??. Ver Opcionales
ProtocoloUna lista de métodos y propiedades que un tipo promete tener; es la interfaz de Swift. Ver Protocolos y extensiones
ClosureLa lambda de Swift: un bloque de código que se pasa como valor y captura lo que usa de su entorno. Ver Closures
ActorUn tipo de Swift que protege su estado: solo una tarea a la vez accede a él. Ver Actores
Retain cycleDos objetos que se referencian con referencias fuertes y por eso ARC nunca los libera. Se rompe con weak o unowned. Ver Retain cycles
@MainActorMarca código que solo se ejecuta en el hilo principal, el único que puede tocar la interfaz. Ver @MainActor
@StateEl estado propio de una vista de SwiftUI, guardado por SwiftUI y no por la vista. Ver @State
@BindingUna referencia de lectura y escritura a un @State que vive en otra vista. Ver @Binding
@StateObjectEl dueño de un objeto observable: lo crea una vez y lo conserva mientras la vista exista. Ver ObservableObject y @StateObject
@ObservableLa macro de iOS 17 que hace observable una clase sin @Published. Ver @Observable
@EntryLa 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
TextFieldEl 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
@FocusStateGuarda 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
FormEl 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
LabeledContentUna 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

PiezaVersiónDe dónde sale
Kotlin2.4.20libs.versions.toml
AGP9.4.0libs.versions.toml (en Marcador, 9.4.1)
KSP2.3.12libs.versions.toml
compileSdk37libs.versions.toml
targetSdk37libs.versions.toml
minSdk24libs.versions.toml
Gradle9.7.1gradle/wrapper/gradle-wrapper.properties (en Marcador, 9.6.0)

Librerías del núcleo

LibreríaVersiónNota
kotlinx-coroutines1.11.0Dispatchers.IO no está en commonMain
kotlinx-serialization1.11.0
Ktor3.5.2Cliente + un motor por plataforma
Room 33.0.3androidx.room3, no androidx.room
room3-paging3.0.3El PagingSource de Room en commonMain (androidx.room3.paging); la lista sin conexión lo necesita
androidx.sqlite (bundled)2.7.1El driver recomendado: SQLite dentro del binario
DataStore Preferences1.2.1Solo la variante preferences-core en KMP; trae Okio por dentro, sin declararlo
kotlinx-datetime0.8.0Sigue en 0.x y su README avisa de que la API puede cambiar
Koin4.2.2Publica targets de iOS
Kermit2.2.0Registro multiplataforma
KMP-NativeCoroutines1.0.6El puente de Flow a AsyncSequence

Librerías de la app de Android

LibreríaVersiónNota
lifecycle (ViewModel)2.11.0Publica variantes de iOS: por eso el ViewModel es común
Navigation 31.1.7androidx.navigation3
Paging3.5.1paging-common es multiplataforma; paging-compose, no
Coil3.6.2Con coil-network-ktor3
WorkManager2.12.0Solo Android
Compose BOM2026.08.00Fija de golpe todas las versiones de Compose
activity-compose1.13.0
core-ktx1.19.0
core-splashscreen1.2.0

Pruebas

LibreríaVersión
Turbine1.2.1
Robolectric4.17
JUnit 44.13.2

Y la versión de la app, que también vive ahí

libs.versions.toml: [versions] (versión de la app)
# 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"

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í:

PiezaEstadoPor qué no está
Compose Multiplatform1.12.0, iOS StableEsta app usa interfaz nativa en cada plataforma
SKIEAlternativa a KMP-NativeCoroutinesNo se usa: el puente elegido fue el otro
HiltSin targets nativosPor eso la inyección es Koin

Índice de fuentes oficiales

Todas las páginas citadas en la guía, agrupadas.

Kotlin y Kotlin Multiplatform

JetBrains — Compose Multiplatform

Google — Android

Apple y Swift

Servicios y estándares web

Gradle y herramientas

Librerías

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 -1

Se 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 -u

Si 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. 1.¿Cuál es la diferencia entre KMP y Compose Multiplatform?

  2. 2.Encuentras un artículo que habla de «KMM». ¿Qué te dice eso?

  3. 3.Quieres saber si una librería sirve para KMP con iOS. ¿Qué miras?

  4. 4.Quieres saber con qué versión de Ktor compila tu proyecto. ¿Cuál es la respuesta correcta?

  5. 5.¿Por qué la versión de Gradle no está en el catálogo de versiones?

Faltan 5 de 5