Saltar al contenido principal
Tutorial

Convierte tu app de Nuxt a iOS y Android con Capacitor 8

Convierte tu aplicación web actual de Nuxt 4 en apps móviles nativas para iOS y Android con Capacitor 8. Una guía completa para configurar la generación estática, añadir plugins nativos y desplegar en las tiendas de apps.

Convierte tu app de Nuxt a iOS y Android con Capacitor 8

Introducción

¿Ya tienes una web app con Nuxt? En esta guía, aprenderás cómo transformarla en apps nativas para iOS y Android usando Capacitor 8 — la última versión con mejor rendimiento y nuevas funciones.

Capacitor envuelve tu web app en un contenedor nativo, dándote acceso a APIs del dispositivo como cámara, filesystem y push notifications sin cambiar tu codebase de Vue. A diferencia de Flutter o React Native, no tienes que reescribir nada: tu code de Nuxt funciona tal cual.

Lo que aprenderás:

  • Configurar tu app Nuxt actual para generación estática
  • Añadir Capacitor 8 con plugins nativos esenciales
  • Build y testing en simuladores de iOS y Android
  • Activar live reload para un desarrollo más rápido
  • Solucionar problemas comunes de layout en iOS (viewport, safe area, overflow horizontal)
  • Añadir una UI con feeling nativo con Capgo Native Navigation and Transitions

¿Quieres empezar un proyecto desde cero? Mira nuestra guía sobre Cómo crear una Nuxt Mobile App desde cero.

Beneficios de usar Nuxt y Capacitor

  • Reutilización con Code: Comparte tus componentes y lógica de Vue entre web y móvil.
  • Rendimiento: La generación estática de Nuxt crea bundles optimizados para móvil.
  • Capacidades Nativas: Accede a funciones del dispositivo como cámara, geolocalización y sistema de archivos mediante plugins de Capacitor.
  • Desarrollo Simplificado: Usa patrones familiares de Vue/Nuxt sin aprender desarrollo nativo.

Requisitos

Antes de empezar, asegúrate de tener:

  • Node.js 18+ instalado
  • Un Nuxt 4 aplicación
  • Xcode (para desarrollo iOS, solo macOS)
  • Android Studio (para desarrollo Android)

Configura tu app de Nuxt para móvil

El primer paso es configurar tu app de Nuxt para generación estática. Capacitor necesita archivos HTML/JS/CSS estáticos para empaquetarlos en la app nativa.

Asegúrate de que tu package.json tenga el script generate:

{
  "scripts": {
    "dev": "nuxt dev",
    "build": "nuxt build",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "mobile": "bun run generate && bunx cap sync",
    "mobile:ios": "bun run mobile && bunx cap open ios",
    "mobile:android": "bun run mobile && bunx cap open android"
  }
}

Importante: Si usas funciones de servidor (API routes, middleware de servidor, etc.), deberás refactorizarlas para usar alternativas de cliente o APIs externas.

Prueba la generación estática ejecutando:

bun run generate

Deberías ver una .output/public carpeta con tus archivos estáticos. Esto es lo que Capacitor incluirá en tu app nativa.

Añadir Capacitor 8 a tu proyecto

Para empaquetar tu app de Nuxt en un contenedor móvil nativo, sigue estos pasos:

  1. Instala el core de Capacitor y CLI:
bun add @capacitor/core
bun add -D @capacitor/cli
  1. Instala los plugins comunes de Capacitor que probablemente necesites:
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences

Estos plugins ofrecen funciones esenciales:

  • @capacitor/app: Gestiona eventos del ciclo de vida de la app (foreground/background, deep links)
  • @capacitor/keyboard: Controlar el comportamiento del teclado en móviles
  • @capacitor/splash-screen: Gestionar la splash screen nativa
  • @capacitor/status-bar: Dale estilo a la status bar del dispositivo
  • @capacitor/preferences: Almacenamiento key-value (como localStorage pero nativo)
  1. Inicializa Capacitor con los detalles de tu proyecto:
bunx cap init my-app com.example.myapp --web-dir .output/public

Reemplaza my-app con el nombre de tu app y com.example.myapp con el ID de tu app (notación de dominio inverso).

  1. Crea o actualiza el capacitor.config.ts archivo con la configuración adecuada:
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'my-app',
  webDir: '.output/public',
  plugins: {
    SplashScreen: {
      launchShowDuration: 2000,
      launchAutoHide: true,
      androidScaleType: 'CENTER_CROP',
      splashFullScreen: true,
      splashImmersive: true,
    },
    Keyboard: {
      resize: 'body',
      resizeOnFullScreen: true,
    },
    StatusBar: {
      style: 'dark',
    },
  },
};

export default config;
  1. Instala las plataformas nativas:
bun add @capacitor/ios @capacitor/android
  1. Añade las carpetas de las plataformas nativas:
bunx cap add ios
bunx cap add android

Capacitor creará ios y android carpetas en la raíz de tu proyecto con los proyectos nativos.

Para buildear el proyecto de Android, necesitas Android Studio. Para iOS, necesitas un Mac con Xcode.

  1. Haz el build y sincroniza tu proyecto:
bun run mobile

Esto ejecuta tu script personalizado que genera el build estático de Nuxt y sincroniza los archivos con las plataformas nativas.

Build y despliegue de apps nativas

Para construir y desplegar tu app móvil nativa, sigue estos pasos:

Para desarrollar apps para iOS, necesitas tener Xcode instalado, y para apps de Android, necesitas tener Android Studio instalado. Además, si planeas distribuir tu app en la tienda de apps, debes inscribirte en el Apple Developer Program para iOS y en Google Play Console para Android.

  1. Abre los proyectos nativos:

Para iOS:

bun run mobile:ios

Para Android:

bun run mobile:android

O directamente con Capacitor CLI:

bunx cap open ios
bunx cap open android
  1. Compila y ejecuta la app:

android-studio-run

  • En Android Studio, espera a que el proyecto esté listo y haz clic en el botón “Run” para desplegar la app en un dispositivo conectado o emulador.

xcode-run

  • En Xcode, configura tu cuenta de firma para desplegar la app en un dispositivo real. Si no lo has hecho antes, Xcode te guiará en el proceso (ten en cuenta que debes estar inscrito en el Apple Developer Program). Una vez configurado, haz clic en el botón “Play” para ejecutar la app en tu dispositivo conectado.

¡Felicidades! Has desplegado con éxito tu web app de Nuxt en un dispositivo móvil.

nuxtjs-mobile-app

Pero espera, también hay una forma más rápida de hacer esto durante el desarrollo…

Live Reload con Capacitor

Durante el desarrollo, puedes aprovechar el live reloading para ver los cambios al instante en tu móvil. Para activar esta función, sigue estos pasos:

  1. Busca tu dirección IP local:
  • En macOS, ejecuta el siguiente comando en la terminal:

    ipconfig getifaddr en0
  • En Windows, ejecuta:

    ipconfig

    Busca la dirección IPv4 en la salida.

  1. Actualiza tu capacitor.config.ts para apuntar a tu servidor de desarrollo:
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: '.output/public',
  server: {
    url: 'http://YOUR_IP_ADDRESS:3000',
    cleartext: true,
  },
  plugins: {
    // ... your plugin config
  },
};

export default config;

Reemplaza YOUR_IP_ADDRESS con tu dirección IP local (ej., 192.168.1.100).

  1. Aplica los cambios a tu proyecto nativo:
bunx cap copy

El copy el comando copia la carpeta web y los cambios de configuración al proyecto nativo sin actualizar todo el proyecto.

  1. Inicia tu servidor de dev de Nuxt y reconstruye en Xcode/Android Studio:
bun run dev

Ahora, cada vez que hagas cambios en tu app de Nuxt, la app móvil se recargará automáticamente para reflejarlos.

Nota: Si instalas nuevos plugins o modificas archivos nativos, tendrás que reconstruir el proyecto nativo, ya que el live reloading solo aplica a cambios en el code web.

Uso de plugins de Capacitor

Los plugins de Capacitor te permiten acceder a funciones nativas del dispositivo desde tu app de Nuxt. Veamos cómo usar Plugin de compartir como ejemplo:

  1. Instala el plugin Share:
bun add @capacitor/share
  1. Crea o actualiza una página para usar el plugin Share. En Nuxt 4, las páginas van en app/pages/:
<template>
  <div class="p-6">
    <h1 class="text-2xl font-bold mb-4">Welcome to Nuxt + Capacitor!</h1>
    <button
      @click="shareContent"
      class="px-6 py-3 bg-blue-600 text-white rounded-lg font-semibold"
    >
      Share now!
    </button>
  </div>
</template>

<script setup lang="ts">
import { Share } from '@capacitor/share';

async function shareContent() {
  await Share.share({
    title: 'Check this out!',
    text: 'Built with Nuxt and Capacitor',
    url: 'https://capacitorjs.com',
    dialogTitle: 'Share with friends',
  });
}
</script>
  1. Sincroniza los cambios con el proyecto nativo:
bun run mobile

O simplemente sincroniza sin reconstruir:

bunx cap sync
  1. Reconstruye y ejecuta la app en tu dispositivo.

Ahora, al hacer clic en el botón “Share now!”, aparecerá el diálogo nativo para compartir.

Después, puedes hacer que la app se sienta más nativa en iOS y Android con la navegación y transiciones de Capgo, y solucionar problemas comunes de layout en iOS que causan desbordamiento horizontal o áreas seguras recortadas.

UI con sensación nativa gracias a Capgo Native Navigation and Transitions

He trabajado durante años con Ionic para crear aplicaciones multiplataforma, pero integrarlo con Nuxt es complicado y rara vez vale la pena si ya tienes Tailwind CSS.

Para una experiencia nativa en una app de Nuxt + Capacitor, usa plugins de Capgo en lugar de UI kits web como Konsta UI:

  • @capgo/capacitor-native-navigation — navbar nativa, tab bar tipo Liquid Glass en iOS y un estilo de tab bar con desenfoque en Android. El router de Nuxt gestiona el estado de las rutas; el plugin controla el chrome nativo.
  • @capgo/capacitor-transitions — Transiciones de página estilo Ionic y gesto de retroceso en iOS en la capa WebView, sin necesidad de usar Ionic UI.

Instala ambos:

bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync

Configura la navegación nativa con CSS inset mode para que el contenido web respete las barras nativas:

import { NativeNavigation } from '@capgo/capacitor-native-navigation';

await NativeNavigation.configure({
  contentInsetMode: 'css',
  animationDuration: 360,
  glass: {
    effect: 'liquidGlass',
  },
});

Renderiza una tab bar Liquid Glass (iOS usa renderizado del sistema; Android usa un fondo WebView desenfocado):

await NativeNavigation.setTabbar({
  selectedId: 'home',
  labelVisibilityMode: 'labeled',
  icons: true,
  colors: { dynamic: true },
  tabs: [
    { id: 'home', title: 'Home', icon: { svg: '...' } },
    { id: 'settings', title: 'Settings', icon: { svg: '...' } },
  ],
});

await NativeNavigation.addListener('tabSelect', ({ id }) => {
  router.push(`/${id}`);
});

Añade transiciones de página nativas en tu app shell:

<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/vue';

initTransitions({ platform: 'auto' });

const router = useRouter();
const outletRef = ref(null);

onMounted(() => {
  if (outletRef.value) {
    setupRouterOutlet(outletRef.value, { platform: 'auto', swipeGesture: 'auto' });
  }
});

const openSettings = () => {
  setDirection('forward');
  router.push('/settings');
};
</script>

<template>
  <cap-router-outlet ref="outletRef">
    <router-view />
  </cap-router-outlet>
</template>

Envuelve las páginas enrutadas en cap-router-outlet, cap-page, y cap-content, y llama setDirection('forward') o setDirection('back') antes de navegar. No dupliques los headers o footers web cuando la navegación nativa ya gestione esas superficies.

Consulta las guías completas: Usando @capgo/capacitor-native-navigation y Usando @capgo/capacitor-transitions.

Safe areas con Tailwind

Para las safe areas en Tailwind CSS, usa @capgo/tailwind-capacitor (publicado como tailwind-capacitor en npm). Proporciona safe-areas utilidades y otros plugins de Tailwind compatibles con Capacitor:

bun add -D tailwind-capacitor

En app/assets/css/main.css:

@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";

Para Nuxt 4 con Tailwind CSS 4, mantén esta importación en el archivo CSS referenciado por nuxt.config.ts.

Usa utilidades como pt-safe, pb-safe, y px-safe en lugar de añadir env(safe-area-inset-*) manualmente. El proyecto está en desarrollo activo; si falta algo para tu configuración de Nuxt, abre un PR en GitHub.

Cómo solucionar problemas de layout en iOS (Viewport, Safe Area y desbordamiento horizontal)

Si el contenido se ve recortado, desplazado o con scroll horizontal en iOS, añadir más overflow-x: hidden o ajustar solo la etiqueta viewport no suele solucionarlo. Revisa estas comprobaciones en orden.

Asegúrate de que la etiqueta meta viewport esté aplicada correctamente

En nuxt.config.ts, configura el viewport mediante app.head:

export default defineNuxtConfig({
  app: {
    head: {
      meta: [
        {
          name: 'viewport',
          content: 'width=device-width, initial-scale=1, viewport-fit=cover',
        },
      ],
    },
  },
});

Gestiona el safe area de iOS desde un único wrapper raíz

Crea un app shell único y aplica el padding del safe area ahí, no en múltiples componentes anidados:

html,
body,
#__nuxt {
  width: 100%;
  min-height: 100%;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
}

* {
  box-sizing: border-box;
}

.app-shell {
  min-height: 100dvh;
  width: 100%;
  padding-top: env(safe-area-inset-top);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
}

Envuelve todo el contenido de la página dentro de .app-shell. El padding de safe-area duplicado en headers, modales y wrappers de layout suele hacer que la UI parezca recortada o demasiado grande.

Con @capgo/tailwind-capacitor, puedes aplicar el mismo padding con utilidades como pt-safe pb-safe px-safe en ese único shell.

Configura Capacitor iOS contentInset a never primero

En capacitor.config.ts, prefiere desactivar el inset nativo y dejar que CSS (o la navegación nativa) contentInsetMode: 'css') se encarga del safe area:

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'my-app',
  webDir: 'out',
  ios: {
    contentInset: 'never',
  },
};

Mezclar el content inset automático de Capacitor con CSS env(safe-area-inset-*) padding suele causar espacios dobles.

Encuentra el elemento real que desborda

El culpable habitual es un elemento que usa 100vw, Tailwind w-screen, un ancho fijo en píxeles, o un min-width.

En Safari Web Inspector, ejecuta:

[...document.querySelectorAll('*')]
  .filter(el => el.scrollWidth > document.documentElement.clientWidth)
  .map(el => ({
    el,
    tag: el.tagName,
    class: el.className,
    scrollWidth: el.scrollWidth,
    clientWidth: document.documentElement.clientWidth,
  }));

Con Tailwind, reemplaza w-screen con w-full siempre que puedas. Muchos problemas de desbordamiento horizontal vienen de 100vw / w-screen, padding de safe-area duplicado, o un contenedor de ancho fijo —no del propio meta tag del viewport.

Conclusión

Has convertido con éxito tu aplicación web de Nuxt en apps nativas para iOS y Android usando Capacitor 8. Tu codebase de Vue ahora se ejecuta de forma nativa en dispositivos móviles con acceso a las APIs del dispositivo.

Lo que lograste:

  • Configuración de Nuxt para generación estática
  • Añadido Capacitor 8 con plugins esenciales
  • Build y despliegue en simuladores iOS y Android
  • Live reload habilitado para desarrollo
  • Se corrigieron errores comunes de layout en iOS (viewport, safe area, overflow)
  • Interfaz con sensación nativa gracias a Capgo Native Navigation y Transitions

Próximos pasos:

  • Configurar Capgo para actualizaciones over-the-air sin reenviar a la app store
  • Añadir más plugins nativos como Camera, Geolocation o Push Notifications
  • Configurar los iconos y splash screens para producción
  • Preparar la app para enviarla a App Store y Google Play

¿Empiezas un proyecto desde cero? Mira Cómo crear una app móvil con Nuxt desde cero para un tutorial paso a paso.

Recursos

Descubre cómo Capgo te ayuda a crear mejores apps más rápido, regístrate para obtener una cuenta gratis hoy mismo.

Continúa desde Convierte tu app de Nuxt a iOS y Android con Capacitor 8

Si estás usando Convierte tu app de Nuxt a iOS y Android con Capacitor 8 para planificar el trabajo del plugin nativo, conéctalo con Directorio de plugins de Capgo para el flujo de trabajo de productos en el Capgo Plugin Directory, Plugins de Capacitor por Capgo para los detalles de implementación en Plugins de Capacitor por Capgo, Añadir o actualizar plugins para los detalles de implementación en Añadir o actualizar plugins, Alternativas a los plugins de Ionic Enterprise para el flujo de trabajo del producto en Alternativas a los plugins de Ionic Enterprise, y Native Builds de Capgo para el flujo de trabajo en Capgo Native Builds.

Live Updates para apps de Capacitor

Si hay un bug en la capa web, publica el fix con Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el proceso de revisión normal.

Lo último de nuestro blog

Capgo te da los mejores insights para crear una app móvil realmente profesional.