Jetpack Compose Desktop y Multiplatform

Jetpack Compose Desktop y Multiplatform

Hola amigos 馃憢 Bienvenidos a un nuevo tutorial de Universo Android. Hoy aprenderemos a crear aplicaciones multiplataforma con Jetpack Compose, permiti茅ndote escribir c贸digo una sola vez y ejecutarlo en Android, Desktop (Windows, macOS, Linux) y Web.

Al finalizar este tutorial tendr谩s:

  • Proyecto Compose Multiplatform
  • Aplicaci贸n para Android y Desktop
  • C贸digo compartido entre plataformas
  • UI adaptable
  • Recursos espec铆ficos por plataforma
  • Configuraci贸n completa

馃煩 1. ¿Qu茅 es Compose Multiplatform?

Compose Multiplatform es la evoluci贸n de Jetpack Compose que permite crear aplicaciones para m煤ltiples plataformas (Android, iOS, Desktop, Web) compartiendo c贸digo UI y l贸gica de negocio.

馃煩 2. Plataformas Soportadas

  • Android: Apps m贸viles nativas
  • Desktop: Windows, macOS, Linux
  • iOS: Aplicaciones iOS (experimental)
  • Web: Aplicaciones web (experimental)

馃煩 3. Crear Proyecto Multiplatform

Opci贸n 1: Usar Wizard de IntelliJ IDEA

  1. Descarga IntelliJ IDEA Community (gratis)
  2. New Project → Kotlin Multiplatform
  3. Selecciona: Android + Desktop
  4. Finaliza creaci贸n

Opci贸n 2: Crear Manualmente

馃煩 4. Estructura del Proyecto

MyComposeApp/
├── androidApp/           # C贸digo Android
│   └── src/
├── desktopApp/          # C贸digo Desktop
│   └── src/
├── common/              # C贸digo compartido
│   └── src/
│       ├── commonMain/  # C贸digo com煤n
│       ├── androidMain/ # Espec铆fico Android
│       └── desktopMain/ # Espec铆fico Desktop
└── build.gradle.kts

馃煩 5. Configuraci贸n Gradle (Proyecto)

馃搫 build.gradle.kts (root)

plugins {
    kotlin("multiplatform") version "1.9.20" apply false
    id("com.android.application") version "8.1.4" apply false
    id("org.jetbrains.compose") version "1.5.10" apply false
}

馃煩 6. Configuraci贸n Gradle (Common)

馃搫 common/build.gradle.kts

plugins {
    kotlin("multiplatform")
    id("org.jetbrains.compose")
    id("com.android.library")
}

kotlin {
    android()
    jvm("desktop")

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(compose.runtime)
                implementation(compose.foundation)
                implementation(compose.material3)
                implementation(compose.ui)
            }
        }

        val androidMain by getting {
            dependencies {
                implementation("androidx.activity:activity-compose:1.8.2")
            }
        }

        val desktopMain by getting {
            dependencies {
                implementation(compose.desktop.currentOs)
            }
        }
    }
}

android {
    namespace = "com.example.myapp.common"
    compileSdk = 34

    defaultConfig {
        minSdk = 24
    }
}

馃煩 7. C贸digo Compartido

馃搫 common/src/commonMain/App.kt

package com.example.myapp

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

@Composable
fun App() {
    var showContent by remember { mutableStateOf(false) }
    var counter by remember { mutableStateOf(0) }

    MaterialTheme {
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .verticalScroll(rememberScrollState())
                    .padding(16.dp),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.spacedBy(16.dp)
            ) {
                // T铆tulo
                Text(
                    text = "Compose Multiplatform",
                    style = MaterialTheme.typography.headlineLarge,
                    color = Color(0xFF2196F3)
                )

                Text(
                    text = "Una app, m煤ltiples plataformas",
                    style = MaterialTheme.typography.bodyLarge,
                    color = Color.Gray
                )

                Spacer(modifier = Modifier.height(16.dp))

                // Informaci贸n de plataforma
                PlatformInfoCard()

                // Contador
                CounterCard(counter) { counter++ }

                // Bot贸n toggle
                Button(
                    onClick = { showContent = !showContent },
                    modifier = Modifier.fillMaxWidth()
                ) {
                    Text(if (showContent) "Ocultar" else "Mostrar Contenido")
                }

                // Contenido animado
                AnimatedVisibility(showContent) {
                    Card(
                        modifier = Modifier.fillMaxWidth(),
                        colors = CardDefaults.cardColors(
                            containerColor = Color(0xFF4CAF50)
                        ),
                        shape = RoundedCornerShape(16.dp)
                    ) {
                        Column(
                            modifier = Modifier.padding(24.dp)
                        ) {
                            Text(
                                "✓ C贸digo compartido",
                                color = Color.White
                            )
                            Text(
                                "✓ UI declarativa",
                                color = Color.White
                            )
                            Text(
                                "✓ Nativo en todas las plataformas",
                                color = Color.White
                            )
                        }
                    }
                }

                // Lista de caracter铆sticas
                FeaturesSection()
            }
        }
    }
}

@Composable
fun PlatformInfoCard() {
    Card(
        modifier = Modifier.fillMaxWidth(),
        colors = CardDefaults.cardColors(
            containerColor = Color(0xFF2196F3)
        ),
        shape = RoundedCornerShape(16.dp)
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(24.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                "Ejecutando en:",
                style = MaterialTheme.typography.titleMedium,
                color = Color.White
            )
            Text(
                getPlatformName(),
                style = MaterialTheme.typography.headlineMedium,
                color = Color.White
            )
        }
    }
}

@Composable
fun CounterCard(counter: Int, onIncrement: () -> Unit) {
    Card(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(16.dp)
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(24.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                "Contador",
                style = MaterialTheme.typography.titleLarge
            )
            Text(
                "$counter",
                style = MaterialTheme.typography.displayLarge,
                color = Color(0xFFFF5722)
            )
            Spacer(modifier = Modifier.height(16.dp))
            Button(onClick = onIncrement) {
                Text("Incrementar")
            }
        }
    }
}

@Composable
fun FeaturesSection() {
    Card(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(16.dp)
    ) {
        Column(
            modifier = Modifier.padding(24.dp),
            verticalArrangement = Arrangement.spacedBy(12.dp)
        ) {
            Text(
                "Caracter铆sticas",
                style = MaterialTheme.typography.titleLarge,
                color = Color(0xFF2196F3)
            )
            
            FeatureItem("馃摫", "Android nativo")
            FeatureItem("馃捇", "Windows, macOS, Linux")
            FeatureItem("馃帹", "UI moderna con Material 3")
            FeatureItem("⚡", "Rendimiento nativo")
            FeatureItem("馃攧", "Hot Reload")
        }
    }
}

@Composable
fun FeatureItem(icon: String, text: String) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(12.dp)
    ) {
        Text(icon, style = MaterialTheme.typography.headlineSmall)
        Text(text, style = MaterialTheme.typography.bodyLarge)
    }
}

// Funci贸n expect (declaraci贸n)
expect fun getPlatformName(): String

馃煩 8. Implementaci贸n Android

馃搫 common/src/androidMain/Platform.kt

package com.example.myapp

actual fun getPlatformName(): String {
    return "Android ${android.os.Build.VERSION.SDK_INT}"
}

馃煩 9. Implementaci贸n Desktop

馃搫 common/src/desktopMain/Platform.kt

package com.example.myapp

actual fun getPlatformName(): String {
    val os = System.getProperty("os.name")
    val arch = System.getProperty("os.arch")
    return "$os ($arch)"
}

馃煩 10. App Android

馃搫 androidApp/build.gradle.kts

plugins {
    id("com.android.application")
    kotlin("android")
    id("org.jetbrains.compose")
}

android {
    namespace = "com.example.myapp.android"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.myapp.android"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }
}

dependencies {
    implementation(project(":common"))
    implementation("androidx.activity:activity-compose:1.8.2")
}

馃搫 androidApp/src/main/MainActivity.kt

package com.example.myapp.android

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.myapp.App

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            App()
        }
    }
}

馃煩 11. App Desktop

馃搫 desktopApp/build.gradle.kts

plugins {
    kotlin("multiplatform")
    id("org.jetbrains.compose")
}

kotlin {
    jvm {
        withJava()
    }
    
    sourceSets {
        val jvmMain by getting {
            dependencies {
                implementation(project(":common"))
                implementation(compose.desktop.currentOs)
            }
        }
    }
}

compose.desktop {
    application {
        mainClass = "MainKt"
        
        nativeDistributions {
            targetFormats(
                org.jetbrains.compose.desktop.application.dsl.TargetFormat.Dmg,
                org.jetbrains.compose.desktop.application.dsl.TargetFormat.Msi,
                org.jetbrains.compose.desktop.application.dsl.TargetFormat.Deb
            )
            packageName = "MyComposeApp"
            packageVersion = "1.0.0"
        }
    }
}

馃搫 desktopApp/src/jvmMain/Main.kt

import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import androidx.compose.ui.unit.dp
import com.example.myapp.App

fun main() = application {
    Window(
        onCloseRequest = ::exitApplication,
        title = "Compose Multiplatform App",
        state = rememberWindowState(width = 800.dp, height = 600.dp)
    ) {
        App()
    }
}

馃煩 12. Settings Gradle

馃搫 settings.gradle.kts

pluginManagement {
    repositories {
        google()
        gradlePluginPortal()
        mavenCentral()
    }
}

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "MyComposeApp"
include(":androidApp")
include(":desktopApp")
include(":common")

馃煩 13. Ejecutar las Aplicaciones

Android

./gradlew :androidApp:installDebug

Desktop

./gradlew :desktopApp:run

Crear Ejecutable Desktop

./gradlew :desktopApp:createDistributable

馃煩 14. Recursos por Plataforma

// En commonMain
expect fun loadImage(): ImageBitmap

// En androidMain
actual fun loadImage(): ImageBitmap {
    // Cargar desde recursos Android
}

// En desktopMain
actual fun loadImage(): ImageBitmap {
    // Cargar desde recursos Desktop
}

馃煩 15. Ventajas y Desventajas

Ventajas

✓ C贸digo compartido (50-90%)
✓ UI consistente
✓ Desarrollo m谩s r谩pido
✓ Mantenimiento simplificado
✓ Nativo en todas las plataformas

Desventajas

✗ Curva de aprendizaje
✗ iOS a煤n experimental
✗ Menos recursos que Flutter
✗ Requiere conocimiento de Kotlin

馃煩 16. Comparaci贸n con Flutter

Caracter铆sticaCompose MPFlutter
LenguajeKotlinDart
MadurezCreciendoMaduro
RendimientoNativoCerca de nativo
AndroidExcelenteMuy bueno
iOSExperimentalExcelente
DesktopEstableEstable
ComunidadMediaGrande

▶️ C贸mo Ejecutar

  1. Descarga IntelliJ IDEA
  2. Crea proyecto Kotlin Multiplatform
  3. Agrega dependencias Compose
  4. Copia el c贸digo
  5. Ejecuta para Android o Desktop

馃И Resultado Final

Aplicaci贸n funcionando en Android y Desktop con c贸digo compartido al 80-90%.

馃摜 Descargar Proyecto

馃憠 

馃檶 Gracias por Visitar mi Blog

✔️ Comp谩rtelo
✔️ D茅jame un comentario
✔️ S铆gueme para m谩s contenido

❓ Preguntas Frecuentes

1. ¿Qu茅 es Compose Multiplatform?
Framework que permite crear apps para m煤ltiples plataformas compartiendo c贸digo UI y l贸gica.

2. ¿Es mejor que Flutter?
Depende. Compose es mejor para devs Android/Kotlin. Flutter tiene m谩s madurez y comunidad.

3. ¿Funciona en iOS?
S铆, pero a煤n es experimental. Se recomienda para producci贸n solo Android y Desktop.

4. ¿Cu谩nto c贸digo puedo compartir?
Entre 70-90% del c贸digo puede ser compartido entre plataformas.

No hay comentarios:

Publicar un comentario