Aunque el API de KMP nos provea de muchas de las implementaciones más comunes, hay ciertas situaciones donde queremos añadir dependencias distintas por cada entorno. Para solucionarlo aprenderemos a utilizar las clases EXPECT y ACTUAL.

Entendiendo el problema

Imaginemos que queremos añadir mapas en nuestra app, pero no cualquier mapa, ya que para Android queremos utilizar Google Maps pero para iOS Apple Maps ¿Que hacemos?

Y es que este tipo de situaciones las vamos a ver muy a menudo en desarrollos multiplataforma ya que no siempre tendremos librerías que funcionen a la par en distintos entornos.

implementaciones distintas en kmp
Mismo código distintas implementaciones.

Fíjate en la imagen anterior. Aunque el core de la app sea igual estamos llamando a una clase que nos provee información distinta dependiendo del entorno y eso lo haremos gracias a las clases EXPECT y ACTUAL.

Implementaciones por entorno

Debemos entender que para que funcione esta implementación necesitamos trabajar con los distintos directorios del proyecto.

Directorios del proyecto KMP (iOS y Android).

La idea es muy sencilla, dentro del directorio commonMain debemos crear la clase expect y las «implementaciones» de esta clase serán actual e irán en cada entorno. Aunque técnicamente no es una implementación ya que no es una interfaz, es muy similar a nivel de implementación y te puede ayudar a entenderlo.

Vamos a crear una clase que nos provea de cierta información distinta de cada entorno, así que lo primero que habrá que hacer será crear una clase expect en la ruta commonMain/Kotlin.

@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
expect class GetDeviceInformation() {
    fun getDeviceInfo():String
}

Fíjate que aunque estamos creando una función no tiene un body, es decir, solo estamos definiendo la función. Y sí, ahora mismo te saldrán varios errores ya que las clases expect esperan una clase actual es cada uno de los entornos, al hacerlo desaparecerán los errores.

También hemos tenido que poner un Suppress para decirle al IDE que ya sabemos que está en beta, es lo que hay.

Ahora tenemos que hacer algo muy similar para todos los entornos, en este caso crearemos una clase en el directorio androidMain/Kotlin y iosMain/Kotlin.

@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
actual class GetDeviceInformation {
    actual fun getDeviceInfo(): String {
        return "Soy un Android molón"
    }
}
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
actual class GetDeviceInformation {
    actual fun getDeviceInfo(): String {
        return "Soy un iOS"
    }
}

Como habrás notado los dos ficheros son iguales menos el contenido que devuelven.

Esta es la idea de las clases expect y actual ya que ahora yo en cualquiera de mis ficheros genéricos puedo llamar a la clase GetDeviceInformation (fíjate que todas las clases y funciones se llaman igual) y el sistema dependiendo de tu entorno accederá a un fichero u otro.

Ahora ya podemos ir a nuestra app y acceder a la información de cada entorno.

val response = GetDeviceInformation().getDeviceInfo()
Button(onClick = { showContent = !showContent }) {
     Text("Click me! $response")
}

Recuerda que puedes descargar TODO el proyecto desde GitHub de manera gratuita (y me ayudas mucho dándole una estrella ⭐️).


Si te ha gustado puedes seguirme en mis redes sociales en Aristi.Dev. Y si tienes dudas con este o cualquier otro artículo del blog únete al Discord de la comunidad y te ayudaremos.