Noticia Creación de una aplicación SaaS multiplataforma usando KMP, Ktor y SQLDelight

Creación de una aplicación SaaS multiplataforma usando KMP, Ktor y SQLDelight


Si te dedicas al desarrollo de aplicaciones móviles, sabrás que consumir APIs REST es el pan de cada día. La gran pregunta siempre es cómo hacerlo sin tener que escribir la misma lógica dos veces, una para cada sistema operativo. Aquí es donde entra en juego Kotlin Multiplatform (KMP), una tecnología que nos permite compartir la lógica de negocio mientras mantenemos la experiencia de usuario nativa en cada dispositivo.

En este artículo vamos a profundizar en cómo montar una estructura SaaS profesional. No nos quedaremos solo en la superficie; vamos a ver cómo integrar Ktor para las comunicaciones, SQLDelight para que la app funcione sin internet y Koin para que todo el sistema de dependencias esté bien organizado y sea escalable, evitando que el código se convierta en un espagueti imposible de mantener.

El ecosistema de herramientas: KMP, Ktor y SQLDelight​


Para empezar, es fundamental entender que KMP no es un framework de UI como Flutter, sino que se centra en compartir el código lógico. Esto significa que puedes escribir tus modelos de datos, la gestión de red y la base de datos una sola vez en un módulo común. Para la red, la herramienta estrella es Ktor Client, que es básicamente la alternativa moderna y multiplataforma a Retrofit. Al estar creado por JetBrains y basarse en corrutinas, la integración es sencillísima y no bloquea la interfaz de usuario.

Por otro lado, para que nuestra aplicación sea realmente robusta, necesitamos persistencia local. SQLDelight es la opción preferida porque no solo guarda datos, sino que genera código Kotlin basado en tus consultas SQL, lo que nos da un entorno tipado y seguro. Así evitamos errores en tiempo de ejecución que suelen ocurrir con las bases de datos tradicionales.

Configuración del proyecto y dependencias​


Para poner esto en marcha, lo ideal es usar IntelliJ IDEA o Android Studio. Al crear el proyecto, debemos seleccionar el asistente de Kotlin Multiplatform y marcar los targets de Android e iOS. Un punto clave aquí es decidir si queremos compartir la UI o no; para un acabado profesional, es recomendable implementar UIs nativas (Jetpack Compose en Android y SwiftUI en iOS) mientras el núcleo sigue siendo compartido.

En el archivo build.gradle.kts, debemos añadir las librerías necesarias. Para la red, necesitamos ktor-client-core y el plugin de ContentNegotiation para manejar JSON. Para la base de datos, instalamos el runtime de SQLDelight y los drivers específicos: el AndroidSqliteDriver para el entorno de Google y el NativeSqliteDriver para el ecosistema de Apple. No podemos olvidar kotlinx.serialization, que es la pieza que permite transformar el texto de la API en objetos de Kotlin de forma automática.

Modelado de datos y serialización​


Creación de una aplicación SaaS multiplataforma


Antes de lanzar peticiones, necesitamos definir qué datos vamos a manejar. Utilizando la anotación @Serializable, podemos crear data classes que representen la respuesta de la API. Es muy útil usar @SerialName para renombrar campos que vienen con nombres extraños desde la API y convertirlos en propiedades legibles y siguiendo las convenciones de Kotlin. Por ejemplo, si la API devuelve flight_number, nosotros podemos manejarlo internamente como flightNumber.

Implementando la capa de persistencia con SQLDelight​


La magia de SQLDelight empieza en los archivos .sq. En lugar de escribir código Kotlin para crear tablas, escribimos SQL puro. Definimos la tabla, las inserciones y las consultas de selección. Una vez hecho esto, ejecutamos la tarea de Gradle para que la herramienta genere la interfaz de Kotlin correspondiente. Esto nos permite llamar a selectAllLaunchesInfo() en nuestro código sin preocuparnos por errores de sintaxis en la consulta.

Para gestionar los drivers de la base de datos, que varían según la plataforma, lo más limpio es crear una interfaz DatabaseDriverFactory. Implementamos esta interfaz en los módulos androidMain e iosMain. Así, la lógica compartida solo sabe que necesita un driver, pero no le importa si es el de Android o el de iOS, delegando esa responsabilidad a la inyección de dependencias con Koin.

Consumo de APIs con Ktor y creación del SDK​


El cliente de Ktor se configura instalando el plugin de ContentNegotiation y configurando el formato JSON para que ignore claves desconocidas, evitando que la app pete si la API añade campos nuevos. Creamos una clase de servicio que realice peticiones asíncronas usando la palabra clave suspend, asegurando que la red se gestione en hilos secundarios.

Para orquestar todo, lo mejor es construir un SDK compartido (una fachada). Esta clase se encarga de la lógica de caché: primero revisa si hay datos en la base de datos local y, si están vacíos o el usuario solicita una actualización forzada, hace la llamada a la API y actualiza el caché local. Para que el código Swift en iOS pueda manejar los errores de Kotlin, es vital marcar estas funciones con @Throws, permitiendo que las excepciones se traduzcan correctamente a NSError.

Desarrollo de la interfaz de usuario nativa​


En Android, utilizamos Jetpack Compose y un ViewModel. El ViewModel se comunica con el SDK compartido y expone un estado (como una clase de estado de pantalla) que la UI observa. Implementar funciones como Pull-to-Refresh es muy sencillo gracias a los componentes de Material 3, permitiendo que el usuario refresque los datos llamando a la función de carga del SDK.

Para iOS, la ruta es SwiftUI. Creamos un ViewModel en Swift que implemente ObservableObject y utilice un KoinHelper en Kotlin para obtener el SDK. Una parte técnica importante en iOS es añadir el flag de enlace dinámico -lsqlite3 en Xcode, ya que el driver de SQLDelight necesita acceder a la librería de SQLite del sistema para funcionar correctamente.

Tener un sistema donde la lógica de red, la base de datos y la gestión de dependencias residen en un solo lugar permite que el desarrollo sea mucho más fluido. Al combinar KMP con Ktor y SQLDelight, logramos que la aplicación sea eficiente, rápida y extremadamente fácil de actualizar, ya que cualquier cambio en el modelo de datos o en la API solo requiere una modificación en el módulo compartido para impactar a ambas plataformas simultáneamente.

Continúar leyendo...