Skip to main content

Mi primera aplicación

⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.


r8vnhill/echo-app-kt

Cuando desarrollamos software, no basta con escribir funciones en un archivo: necesitamos empaquetarlas, ejecutarlas, y eventualmente distribuirlas. Crear una aplicación ejecutable es uno de los primeros pasos para transformar código en una herramienta útil, accesible y reutilizable.

En esta lección aprenderás cómo crear tu primera aplicación ejecutable usando Kotlin y Gradle. Utilizaremos un ejemplo simple pero práctico: una pequeña herramienta de línea de comandos que imprime mensajes con una marca de tiempo.

Aunque su funcionalidad es modesta, esta aplicación te permitirá:

  • Configurar un proyecto Gradle desde cero.
  • Integrar bibliotecas externas de manera declarativa.
  • Empaquetar y ejecutar tu aplicación desde la terminal.
  • Comprender el papel del plugin application y su impacto en la distribución.

Este recorrido sentará las bases para crear herramientas más complejas en el futuro y te dará un primer vistazo a cómo se ve una biblioteca de software cuando se convierte en una aplicación lista para ejecutarse.

📢 Echo App

La aplicación que crearemos se llama Echo App. Su función es simple: recibir un mensaje como argumento y mostrarlo en la consola junto a la hora actual. Aunque la funcionalidad es básica, nos permitirá explorar cómo configurar un proyecto Gradle y ejecutar una aplicación Kotlin.

📦 Dependencias en detalle

Para expandir las funcionalidades de nuestro proyecto, vamos a añadir la biblioteca kotlinx-datetime, la cual nos permitirá trabajar con fechas y horas en Kotlin de manera eficiente. El primer paso será actualizar el archivo libs.versions.toml ubicado en la carpeta gradle con la nueva dependencia:

./gradle/libs.versions.toml
[versions]
# ...
kotlinx-datetime = "0.6.2"

[libraries]
# ...
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }

Ahora, para asegurarnos de que todo esté correctamente configurado y habilitar el autocompletado en el IDE, construye el proyecto ejecutando el siguiente comando en tu terminal:

./gradlew build

Lo siguiente es decirle a Gradle dónde debe buscar la nueva dependencia. Para ello, actualiza el archivo settings.gradle.kts en la raíz del proyecto para incluir el repositorio de MavenCentral:

settings.gradle.kts
// ...
dependencyResolutionManagement { // Gestión de resolución de dependencias
@Suppress("UnstableApiUsage") // Necesario para usar la API de resolución de dependencias
repositories {
mavenCentral() // Repositorio Maven Central
}
}

Aquí, hemos añadido mavenCentral() al bloque repositories para que Gradle pueda buscar la dependencia en Maven Central. Esto añadirá el repositorio a todos los módulos del proyecto.

A continuación, actualiza el archivo build.gradle.kts en el módulo app para incluir la nueva dependencia en el bloque dependencies. Este bloque es donde definimos las bibliotecas que se utilizarán en el proyecto. Veamos qué tipo de dependencias puedes declarar en Gradle y cómo afectan la compilación y ejecución del proyecto:

  • implementation: Dependencias que serán incluidas en la compilación y el empaquetado de la aplicación.
  • testImplementation: Dependencias utilizadas únicamente para las pruebas.
  • runtimeOnly: Dependencias necesarias solo en tiempo de ejecución, no durante la compilación.
  • testRuntimeOnly: Dependencias necesarias solo en tiempo de ejecución de las pruebas.
  • compileOnly: Dependencias utilizadas en tiempo de compilación, pero no incluidas en tiempo de ejecución.
  • testCompileOnly: Dependencias para la compilación de las pruebas, no necesarias en tiempo de ejecución.
  • api: Dependencias que se compilan y también se exponen a otros módulos.
  • testApi: Dependencias para pruebas que se exponen a otros módulos.

La sintaxis básica para añadir una dependencia es la siguiente:

dependencies {
implementation("group:artifact:version")
implementation(group = "group", name = "artifact", version = "version")
implementation(libs.artifact)
}

En nuestro caso, añadimos la dependencia de kotlinx-datetime a nuestro proyecto de la siguiente manera:

app/build.gradle.kts
dependencies {
implementation(libs.kotlinx.datetime)
}

🛠️ Creando la aplicación

Una vez que las dependencias están configuradas, es momento de empezar a escribir el código de nuestra aplicación. El primer paso es crear un nuevo paquete utilizando el nombre del grupo del proyecto seguido de .echo (por ejemplo, cl.ravenhill.echo). Dentro de este paquete, crearemos un archivo llamado EchoApp.kt que contendrá la lógica principal de la aplicación.

El siguiente código muestra cómo construir nuestra aplicación:

./app/src/main/kotlin/cl/ravenhill/echo/EchoApp.kt
package cl.ravenhill.echo

import kotlinx.datetime.Clock

fun echo(message: String) = "${Clock.System.now()} - $message"

fun main(args: Array<String>) {
for (arg in args) {
println(echo(arg))
}
}
¿Qué acabamos de hacer?
  • Usamos kotlinx.datetime.Clock para obtener la hora actual y así agregar una marca de tiempo a los mensajes que se envían como argumento.
  • La función echo() toma un mensaje como parámetro y devuelve una cadena con el mensaje acompañado de la hora actual.
  • En la función main(), se iteran los argumentos de la aplicación (args), y para cada uno de ellos, se llama a la función echo().

⚙️ Configuración del plugin application

Para que nuestra aplicación sea ejecutable con Gradle, necesitamos agregar el plugin application al archivo build.gradle.kts en el módulo app. Este plugin nos permitirá ejecutar la aplicación mediante el comando ./gradlew :app:run y empaquetarla con ./gradlew :app:installDist.

Añade el siguiente bloque al archivo build.gradle.kts:

./app/build.gradle.kts
plugins {
// ...
application
}

// ...

application {
mainClass.set("cl.ravenhill.echo.EchoAppKt")
}
¿Qué acabamos de hacer?
  • Se aplica el plugin application.
  • Se define la clase principal que contiene la función main() de nuestra aplicación. En este caso, la clase generada por el compilador de Kotlin es cl.ravenhill.echo.EchoAppKt. El compilador agrega Kt al nombre de la clase, ya que es el nombre del archivo en el que está definida la función main().
tip

Si tienes dudas sobre el nombre completo del main class, puedes compilar el proyecto y buscar el archivo .class generado en build/classes. Recuerda que Kotlin agrega el sufijo Kt al nombre del archivo si no es una clase.

🚀 Ejecutando la aplicación

Para ejecutar la aplicación, usa el siguiente comando en la terminal:

./gradlew :app:run --args "Hello, world!"

El resultado debería ser similar al siguiente:

> Task :app:run
2024-09-08T18:35:20.469735500Z - Hello,
2024-09-08T18:35:20.479782500Z - world!

En este punto, has creado una aplicación funcional que recibe argumentos y los imprime junto con una marca de tiempo. Esto demuestra cómo integrar una biblioteca externa (kotlinx-datetime) y cómo configurar el proyecto para que sea ejecutable con Gradle.

⚠️ El problema con gradle run

Aunque gradle run es una forma rápida y conveniente de ejecutar una aplicación Kotlin durante el desarrollo, presenta algunas limitaciones importantes:

  • No permite pasar argumentos directamente desde la línea de comandos: Para pasar argumentos, debemos usar --args, lo cual puede ser menos intuitivo.
  • No soporta input interactivo: No se pueden recibir entradas directamente desde la consola mientras la aplicación está en ejecución.
  • Requiere que Gradle esté instalado: Cualquier persona que desee ejecutar la aplicación deberá tener Gradle instalado, lo cual no es ideal para distribución a usuarixs finales.

Por estas razones, gradle run es más útil para el desarrollo, pero no es la mejor opción cuando queremos distribuir nuestra aplicación a usuarixs finales. Para crear un archivo ejecutable independiente de Gradle, podemos utilizar el comando gradle installDist.

./gradlew :app:installDist

Este comando genera un directorio build/install/app, que contiene un script de inicio que permite ejecutar la aplicación sin necesidad de Gradle. Para ejecutar la aplicación empaquetada, solo debes ejecutar el siguiente comando:

./app/build/install/app/bin/app "Hello," "world!"

Esto producirá el mismo resultado que ejecutar gradle run, pero con la ventaja de que no depende de Gradle y puede distribuirse de manera más sencilla.

🎉 ¡Felicidades!

Has creado tu primera aplicación ejecutable en Kotlin, lista para distribuirse sin la necesidad de Gradle. Este es un paso importante para asegurar que tu aplicación sea más accesible para quienes la usen, ya que podrán ejecutarla de manera independiente.

🎯 Conclusiones

Crear una aplicación ejecutable puede parecer un desafío al principio, pero con las herramientas adecuadas y una estructura clara, se convierte en una tarea accesible y enriquecedora. En esta lección, diste tus primeros pasos para convertir código en una herramienta útil y compartible, utilizando Kotlin y Gradle como base tecnológica.

Este proceso no solo implica escribir funciones, sino también aprender a:

  • Configurar un entorno de construcción moderno y declarativo.
  • Aprovechar bibliotecas externas para extender capacidades sin reinventar la rueda.
  • Empaquetar la aplicación para facilitar su distribución.

Más allá del ejemplo concreto, el verdadero valor está en comprender los principios que permiten crear software robusto y reutilizable.

🔑 Puntos clave

  • Gradle es una herramienta poderosa para gestionar proyectos y dependencias en Kotlin.
  • El plugin application transforma un módulo en una aplicación ejecutable.
  • kotlinx-datetime es una opción moderna y multiplataforma para trabajar con fechas y horas.
  • El empaquetado con installDist permite crear versiones autoejecutables de la aplicación sin depender de Gradle.
  • Distribuir aplicaciones es un paso esencial para que otras personas puedan utilizar tu trabajo sin complicaciones técnicas.

🧰 ¿Qué nos llevamos?

Crear una aplicación ejecutable puede parecer una tarea sencilla, pero encierra muchas de las ideas fundamentales que aparecen en cualquier sistema de construcción: organización del código, gestión de dependencias, configuración del entorno de compilación y empaquetado, y preparación para su distribución. En este ejercicio, esas ideas aparecen de forma práctica y concreta, sirviendo como punto de entrada a un conjunto más amplio de herramientas y posibilidades.

A medida que avancemos en esta unidad, pasaremos de ejecutar una aplicación a construir bibliotecas, automatizar tareas, definir configuraciones reutilizables y extender el comportamiento de Gradle. Pero todo ese camino parte de aquí: de entender que, más allá de escribir código, construir software implica también saber cómo empaquetarlo y compartirlo.

📖 Referencias

🔥 Recomendadas

🌐 Get started with Gradle and Kotlin/JVM | Kotlin. (2024, septiembre 25). Kotlin Help. https://kotlinlang.org/docs/get-started-with-jvm-gradle-project.html