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
- Descarga IntelliJ IDEA Community (gratis)
- New Project → Kotlin Multiplatform
- Selecciona: Android + Desktop
- 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:installDebugDesktop
./gradlew :desktopApp:runCrear 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Ãstica | Compose MP | Flutter |
|---|---|---|
| Lenguaje | Kotlin | Dart |
| Madurez | Creciendo | Maduro |
| Rendimiento | Nativo | Cerca de nativo |
| Android | Excelente | Muy bueno |
| iOS | Experimental | Excelente |
| Desktop | Estable | Estable |
| Comunidad | Media | Grande |
▶️ Cómo Ejecutar
- Descarga IntelliJ IDEA
- Crea proyecto Kotlin Multiplatform
- Agrega dependencias Compose
- Copia el código
- 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