Tu primer proyecto en Kotlin
Al terminar: Crear el proyecto Marcador y el módulo :torneo, recorrer la vista Android, entender módulo frente a carpeta y ejecutar tu primer main.
Al terminar esta lección tendrás Marcador, la app de fútbol amateur que vas a construir en todo el curso. Será un proyecto de Android Studio con dos módulos: :app, la app Android que genera la plantilla y que por ahora se queda como está, y :torneo, un programa de consola donde escribirás toda la lógica del torneo. Ejecutarás tu primer main() y verás salir por pantalla el nombre del torneo. La consola es la ventana de texto donde un programa escribe lo que muestra (la Terminal de Android Studio o la caja de abajo del Playground); un programa de consola es el que no tiene pantallas ni botones, solo escribe texto ahí. Y conocerás el Kotlin Playground, la página donde harás los ejercicios de práctica de todo el curso.
Esta lección toca de Gradle solo lo imprescindible para que el programa corra. Gradle es la herramienta que compila todo. Compilar es traducir el texto que escribes a instrucciones que el ordenador sabe ejecutar: como traducir un libro antes de que lo lea alguien que no sabe español. El compilador es el traductor, y si una frase está mal escrita se niega a traducirla: eso es un error de compilación. Cómo funcionan los ficheros de Gradle, el catálogo de versiones (el fichero donde se apuntan, una sola vez, las versiones de todo lo que usa el proyecto) y cómo se instala una librería lo verás dentro de dos lecciones, en Los ficheros de Gradle de tu proyecto.
Temas: el proyecto de Android Studio y la vista Android; el módulo :torneo; tu primer main() y el Kotlin Playground; módulo frente a carpeta. Las variables y los tipos vienen en Variables, tipos y operaciones, la lección siguiente.
Paso · Crea el proyecto
Objetivo: un proyecto llamado Marcador, creado con la plantilla de Android Studio, que sincroniza sin errores.
- Abre Android Studio. En la pantalla de bienvenida, pulsa New Project; si ya tienes otro proyecto abierto, usa File → New → New Project…
- Elige la plantilla Empty Activity (la del icono con una pantalla vacía: una Activity es una pantalla de una app Android, y más abajo se explica) y pulsa Next.
- Rellena el formulario:
| Campo | Qué escribes | Qué significa |
|---|---|---|
| Name | Marcador | El nombre de la app y de la carpeta del proyecto |
| Package name | com.sebastiannarvaez.marcador | El nombre único del código de la app (se explica abajo) |
| Save location | La que propone Android Studio | La carpeta donde se guarda el proyecto. No la cambies |
| Minimum SDK | API 24 | La versión de Android más antigua donde se podrá instalar |
| Build configuration language | Kotlin DSL | En qué lenguaje se escriben los ficheros de Gradle |
- Pulsa Finish.
Usas el nombre de la guía (com.sebastiannarvaez.marcador) a propósito: Marcador solo se ejecuta en tu ordenador, así que no choca con ninguna otra app. Ese Package name es también el identificador de aplicación: el nombre único con el que Android reconoce una app. Es un solo dato con dos nombres.
Los nombres exactos de los campos cambian unas palabras entre versiones de Android Studio. Si usas otro Package name, tu código llevará otro package en la primera línea y tendrás que cambiarlo en cada fichero que copies de la guía.
Cuatro palabras del formulario, porque saldrán en todo el curso:
- Activity: una pantalla de una app Android. La plantilla Empty Activity crea un proyecto con una sola pantalla vacía.
- Compose (Jetpack Compose): la forma actual de dibujar la interfaz en Android. Describes la pantalla con funciones de Kotlin y Compose la pinta. La plantilla ya trae lo necesario; lo usarás a fondo en lecciones posteriores.
- API level (nivel de API): el número que identifica cada versión de Android. API 24 es Android 7.0. Con Minimum SDK en API 24, un móvil con Android 6 (API 23) no puede instalar la app. SDK (Software Development Kit, kit de desarrollo) es el conjunto de herramientas y librerías de Android que instalaste con Android Studio.
- DSL (Domain-Specific Language, lenguaje de dominio específico): un lenguaje pensado para una sola tarea. Kotlin DSL quiere decir que los ficheros de configuración de Gradle se escriben en Kotlin.
La primera sincronización. Al pulsar Finish, Android Studio abre el proyecto y lanza Gradle por primera vez. En la parte inferior de la ventana verás una barra de progreso: está descargando lo que el proyecto necesita: la versión de Gradle que pide, los plugins (complementos que le enseñan a Gradle a hacer algo nuevo, como construir una app Android) y las librerías (código que otros ya escribieron y empaquetaron para que lo uses sin escribirlo de nuevo). La primera vez tarda varios minutos y necesita internet; las siguientes, segundos. Espera a que termine sin errores antes de seguir.
La vista Android, nodo a nodo
El panel de la izquierda enseña los ficheros del proyecto. Arriba hay un selector que pone Android: es la vista que usa toda la guía.

app: un módulo, una parte del proyecto que Gradle compila por separado. Gradle lo escribe con dos puntos delante,:app. En el paso siguiente crearás el segundo,:torneo.manifests → AndroidManifest.xml: el carné de identidad de la app (nombre, icono, qué pantallas existen). No lo tocas hoy; lo abrirás en La Activity.kotlin+java: el código, agrupado por paquete, un nombre con puntos (com.sebastiannarvaez.marcador) que funciona como una carpeta lógica y evita choques de nombres. Hay tres entradas con el mismo paquete, y la etiqueta entre paréntesis dice cuál es cuál:- sin etiqueta: el código de la app (
MainActivity.kt, la pantalla de la plantilla, y el paqueteui.theme, sus colores y tipos de letra). Se queda como está; (test): tests que corren en tu ordenador, en segundos (ExampleUnitTest). Un test es código que comprueba que otro código hace lo que debe; escribirás el primero en Bucles y tu primer test;(androidTest): tests que necesitan un móvil o un emulador encendido (ExampleInstrumentedTest).
- sin etiqueta: el código de la app (
res: lo que no es código (iconos, colores, textos, tema de la ventana), separado para cambiarlo sin tocar Kotlin. No lo tocas hoy.keepRules → rules.keep: reglas para R8, la herramienta que reduce el código al publicar. No lo tocas.Gradle Scripts: todos los ficheros de Gradle del proyecto, cada uno con una etiqueta gris entre paréntesis. Hoy solo tocas uno; los demás se explican en Los ficheros de Gradle de tu proyecto.
build/, .gradle/ y .idea/ existen en el disco, pero son resultados de compilar, cachés y ajustes del editor. Se regeneran solos, y la vista Android hace bien en esconderlos.
Paso · Crea el módulo :torneo
Objetivo: un segundo módulo, :torneo, de Kotlin puro, que aparece en la vista Android y sincroniza sin errores.
Un módulo es una parte del proyecto que Gradle compila por separado, con su propio fichero de configuración. :torneo será un módulo sin nada de Android, donde vivirá toda la lógica del torneo y que se ejecuta en tu ordenador, sin emulador. Por qué un módulo y no una carpeta se responde justo después de ejecutarlo.
- File → New → New Module…
- En la lista de la izquierda, elige Java or Kotlin Library.
- Rellena:
- Library name:
torneo - Package name:
com.sebastiannarvaez.marcador.torneo - Class name: deja la que propone (
MyClass); la borrarás enseguida. Una clase es una forma de agrupar código con nombre; la verás en Bucles y tu primer test y a fondo en Clases y objetos. Aquí solo sirve de relleno - Language: Kotlin
- Build configuration language: Kotlin DSL, si lo pregunta
- Library name:
- Pulsa Finish y espera a que termine la sincronización.
Los nombres de los campos pueden cambiar unas palabras entre versiones de Android Studio. Lo importante es elegir Java or Kotlin Library y escribir bien el nombre y el paquete.
Librería: código que alguien ya escribió y empaquetó para que otros lo usen sin escribirlo de nuevo. Con esta plantilla, :torneo será una librería tuya, de uso interno: la usará la app.
Qué ha hecho el asistente. No ha creado solo una carpeta: ha tocado tres ficheros de Gradle que ya existían, ha creado el build.gradle.kts del módulo y un fichero de Kotlin de ejemplo.
En la vista Android, Gradle Scripts tiene ahora una entrada más, build.gradle.kts (Module :torneo), y debajo de app aparece el módulo torneo. No tiene manifests ni res, porque no es de Android: solo kotlin+java, con el paquete com.sebastiannarvaez.marcador.torneo y dentro MyClass.
Los tres ficheros que ya existían no hace falta tocarlos: la línea include(":torneo") de settings.gradle.kts es lo que le dice a Gradle que el módulo existe, y las otras dos instalan el plugin de Kotlin para la JVM (la «máquina virtual de Java», el programa que ejecuta en tu ordenador el código ya compilado de Kotlin o Java), org.jetbrains.kotlin.jvm, que sabe compilar programas sin Android. Los verás línea a línea en Los ficheros de Gradle de tu proyecto. Lo que sí vas a abrir es el del módulo nuevo:
plugins {
id("java-library") // plugin de Gradle para construir una librería de la JVM
alias(libs.plugins.jetbrains.kotlin.jvm) // plugin de Kotlin para la JVM, sin Android (libs = el catálogo de versiones)
}
java { // el asistente pide Java 11 dos veces:
sourceCompatibility = JavaVersion.VERSION_11 // una para el compilador de Java
targetCompatibility = JavaVersion.VERSION_11
}
kotlin {
compilerOptions { // y otra para el de Kotlin
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
}
}Java es otro lenguaje de programación que corre en la misma JVM que Kotlin; el JDK es el kit que instalaste en JDK y verificación del entorno, y 11 y 17 son versiones. Java 11 vale por hoy; en Los ficheros de Gradle de tu proyecto lo sustituyes por el JDK 17.
Si no entiendes todavía esa sintaxis, no pasa nada: en estos ficheros, nombre { … } agrupa ajustes; id(...) y alias(...) dicen qué plugin se usa; y algo = x o algo.set(x) le da un valor a un ajuste. No necesitas más por ahora.
Borra MyClass. En torneo → kotlin+java → com.sebastiannarvaez.marcador.torneo, clic derecho sobre MyClass → Delete… y confirma. El paquete queda vacío: ahí escribirás Main.kt.
En el disco, el asistente ha puesto el código en una carpeta java y no kotlin. Da igual: el plugin de Kotlin compila los .kt de las dos, y en la vista Android las dos se ven juntas en kotlin+java. No muevas nada.
Paso · Configura :torneo como programa de consola
Objetivo: que :torneo tenga una tarea run que arranque tu main().
Abre Gradle Scripts → build.gradle.kts (Module :torneo) y haz dos cambios.
1 · Añade el plugin application como última línea del bloque plugins:
plugins {
id("java-library")
alias(libs.plugins.jetbrains.kotlin.jvm)
application // añade la tarea «run»
}application es otro plugin que viene dentro de Gradle, como java-library, así que no lleva versión ni pasa por el catálogo. application a secas es la forma corta de id("application"). Añade la tarea run, que compila el módulo y arranca el programa.
2 · Di dónde arranca el programa, con un bloque nuevo al final del fichero:
application {
// Clase donde está el main(): paquete + nombre del fichero + «Kt» (se explica abajo)
mainClass.set("com.sebastiannarvaez.marcador.torneo.MainKt")
}Es la configuración obligatoria de la cita de arriba. Kotlin guarda el main() de un fichero bajo el nombre del fichero más Kt: el que escribirás en Main.kt quedará como MainKt, dentro del paquete com.sebastiannarvaez.marcador.torneo. Por qué lo hace, lo verás más adelante; por ahora basta con copiar el nombre.
Al editar un fichero de Gradle, Android Studio enseña un aviso en la parte superior del editor con el enlace Sync Now. Púlsalo: Gradle relee la configuración y descarga lo nuevo. Debe terminar sin errores rojos, aunque Main.kt todavía no exista. Si sale rojo, mira el mensaje de error que aparece abajo y lee su primera línea: casi siempre dice el fichero y la línea. Lo más probable a estas alturas es la red (la primera vez Gradle descarga cosas) o un nombre mal escrito; corrige, o reconecta, y pulsa Sync Now otra vez. Los ficheros de Gradle de tu proyecto tiene una caja, «Si Sync sale en rojo», con los fallos más comunes ordenados por lo que ves.
Tu primer programa y dónde practicas
Un programa es una lista de instrucciones que el ordenador ejecuta en orden, de arriba abajo. En Kotlin cada programa tiene un punto de partida: una función llamada main. Una función es un bloque de instrucciones con nombre; en Funciones y parámetros aprenderás a escribir las tuyas, y hoy solo necesitas escribir main y llamar a otra que ya viene hecha, println. Llamar a una función es pedirle que se ejecute, escribiendo su nombre seguido de paréntesis. Lo que va dentro de los paréntesis es el dato que le das, el argumento: println("Hola") le pasa el texto Hola, y println lo muestra en pantalla y salta de línea.
Un texto va siempre entre comillas dobles: lo de dentro es un dato, no código. Por eso "Hola" lleva comillas y main no.
Dónde practicas: el Kotlin Playground
El Kotlin Playground es una página web de JetBrains que ejecuta Kotlin sin instalar nada. Lo usarás para el ejercicio de práctica de cada lección de Kotlin: un sitio donde probar código suelto, fuera de tu proyecto, sin riesgo de romper nada.
- Ábrela. Si sale un aviso de cookies, elige Accept All o Manage Settings.
- Borra el código que trae: la primera vez es un ejemplo; después, el último que escribiste, porque la página lo recuerda.
- Escribe o pega tu programa y pulsa Run.
- Lo que el programa muestra sale debajo del código.
Arriba se ven la versión de Kotlin (2.4.20 al escribir esto) y JVM, el modo en que se ejecuta: déjalos así.
Un comentario es texto que Kotlin ignora, escrito para las personas: empieza con // y llega hasta el final de la línea. Los ejemplos de esta guía llevan uno en cada línea para que sepas qué hace.
// main es el punto de partida: el programa empieza a ejecutarse aquí
fun main() {
// println muestra en la consola el texto que va entre comillas
println("Hola, soy Ana")
println("Empiezo a programar")
}Al pulsar Run sale:
Hola, soy Ana
Empiezo a programarReto · Ejercicio: el cartel de la biblioteca
En el Kotlin Playground, fuera de tu proyecto, escribe un programa que muestre en la consola el cartel de una biblioteca: tres líneas, una para el nombre, otra para la hora de apertura (las 9) y otra para la de cierre (las 20). Al pulsar Run debe verse:
Biblioteca del barrio
Abre a las 9
Cierra a las 20Ver solución
fun main() { // el punto de partida
println("Biblioteca del barrio") // cada println muestra una línea
println("Abre a las 9")
println("Cierra a las 20")
}Cada llamada a println escribe su texto y salta de línea, y se ejecutan en el orden en que están escritas.
Módulo frente a carpeta
Ya has creado y configurado :torneo. Antes de ejecutarlo, una pregunta que merece respuesta: ¿por qué un módulo y no una carpeta llamada torneo dentro de :app?
Una carpeta solo ordena ficheros; un módulo es una unidad que Gradle compila por separado, con su propio build.gradle.kts, sus propias dependencias y sus propias tareas. Para Marcador eso da tres ventajas:
:torneono sabe nada de Android. Es Kotlin puro: compila en segundos y se ejecuta en tu ordenador, sin móvil ni emulador. Toda la lógica del torneo (puntos, partidos, clasificación) se escribe y se prueba ahí.- La frontera la vigila el compilador. Si algún día escribes en
:torneoalgo de Android, no compila. Con una carpeta, nada te frena. - Más adelante,
:appusará:torneo. Un módulo funciona como una librería interna: otro módulo la «instala» declarándola como dependencia (una librería que ese módulo dice que necesita), igual que instalas una librería de internet.
La flecha va en un solo sentido:
:app ──depende de──▶ :torneo
(la app Android) (la lógica, Kotlin puro)
:app ve todo lo que :torneo ofrece.
:torneo no sabe que :app existe.:torneo puede usarse desde :app porque :app lo declarará como dependencia; al revés no, porque :torneo no declara a :app. Por eso un módulo de lógica no puede contener código de pantallas, pero las pantallas sí pueden usar la lógica. Esa conexión la harás en La Activity.
¿Cuándo, en un proyecto real, módulo y cuándo carpeta? Un módulo cuesta: un build.gradle.kts más que mantener y algo más de configuración para Gradle.
La regla práctica: carpeta (paquete) para ordenar código que va junto; módulo cuando quieres una frontera que el compilador vigile (lógica sin Android, una funcionalidad que otro equipo mantiene), compilar y probar una parte por separado, o reutilizarla en otra app. En una app pequeña con un solo equipo, lo normal es un módulo con buenos paquetes.
En Android Studio: New → Directory crea una carpeta vacía y nada más; Gradle ni se entera. New → Module crea un módulo: la carpeta, su build.gradle.kts, la línea include en settings.gradle.kts y lo que el módulo necesite en el catálogo.
Paso · Crea Main.kt y ejecútalo
Objetivo: un fichero Main.kt en :torneo con un main() mínimo, y ver su salida en la consola.
En la vista Android, despliega torneo → kotlin+java, haz clic derecho sobre el paquete com.sebastiannarvaez.marcador.torneo → New → Kotlin Class/File. En la ventanita, elige File, escribe Main y pulsa Intro. Android Studio crea Main.kt con la línea package ya escrita y lo abre.
En tu Main.kt la línea package ya está escrita, con tu paquete (com.sebastiannarvaez.marcador.torneo): no la cambies, porque mainClass la usa para encontrar el main(). Es la primera línea de cualquier fichero de Kotlin: dice a qué paquete pertenece.
Intenta escribirlo tú: el punto de entrada del programa, que muestre por consola el nombre del torneo. Al ejecutarlo debe verse:
Torneo: Copa BarrioIntenta primero. Cuando termines, compara con la solución.Mostrar el código
package com.sebastiannarvaez.marcador.torneo // a qué paquete pertenece este fichero
// Punto de entrada de consola
fun main() { // por aquí arranca el programa
println("Torneo: Copa Barrio") // imprime una línea
}Abre la Terminal de Android Studio: View → Tool Windows → Terminal. Se abre en la carpeta raíz del proyecto, la que tiene el fichero gradlew. Escribe:
./gradlew :torneo:rungradlew es un lanzador: descarga la versión exacta de Gradle que pide el proyecto y la arranca, así que todos compilan igual sin instalar nada. Por eso se escribe ./gradlew y no gradle; el ./ significa «el de esta carpeta». :torneo:run significa «la tarea run del módulo torneo» (una tarea es una acción con nombre que Gradle sabe hacer). Verás algo como esto (BUILD SUCCESSFUL quiere decir que el build, todo el proceso de compilar y ejecutar, terminó bien):
> Task :torneo:compileKotlin
> Task :torneo:run
Torneo: Copa Barrio
BUILD SUCCESSFUL in 3sLa primera vez tarda más, porque Gradle puede tener que descargar lo que le falte; las siguientes, unos segundos. Si la Terminal responde Permission denied, ejecuta una vez chmod +x gradlew (le da permiso al fichero para ejecutarse) y repite.
Sin Terminal. Android Studio muestra un triángulo verde en el margen, a la izquierda de fun main(). Al pulsarlo y elegir Run, ejecuta el programa y enseña la salida en la ventana Run de abajo. También puedes abrir la ventana Gradle de la derecha y buscar la tarea run dentro de torneo, en Tasks → application.
Punto de control
- En la vista Android ves dos módulos,
appytorneo, y enGradle Scriptsla entradabuild.gradle.kts (Module :torneo). build.gradle.kts (Module :torneo)tiene el pluginapplicationy el bloqueapplication { mainClass… }, yMyClassya no existe.- Sync Now termina sin errores rojos, y
MainActivity.ktse abre sin nada en rojo. ./gradlew :torneo:runimprimeTorneo: Copa Barrio.
Comprueba lo que entendiste
5 preguntas · necesitas 4 para completar la lección
1.¿Qué diferencia hay entre New → Directory y New → Module en Android Studio?
2.En la vista Android, bajo
kotlin+javaves tres entradas con el paquetecom.sebastiannarvaez.marcador. ¿Cuál es el código de la app y qué son las otras dos?3.
:torneotieneapplication { mainClass.set("com.sebastiannarvaez.marcador.torneo.MainKt") }. ¿Por quéMainKtsi el fichero se llamaMain.kt?4.¿Qué es compilar?
5.¿Para qué sirve el Kotlin Playground?