Saltar al contenido principal
Guía de tutoría

Crear una aplicación móvil de Nuxt desde cero con Capacitor 8

Paso a paso para crear un nuevo proyecto de Nuxt 4 y convertirlo en aplicaciones móviles nativas de iOS y Android utilizando Capacitor 8. Ideal para empezar de cero con el desarrollo de Vue móvil.

Martin Donadieu

Martin Donadieu

Redactor de contenido

Crear una aplicación móvil de Nuxt desde cero con Capacitor 8

Introducción

¿Quieres crear una aplicación móvil con Nuxt desde cero? Esta guía te guía a través de la creación de un proyecto de Nuxt 4 configurado para móviles desde el principio, luego empaquetarlo como aplicaciones móviles nativas de iOS y Android utilizando Capacitor 8.

Al final de esta guía, tendrás una aplicación móvil en funcionamiento en simuladores que puedes seguir desarrollando y eventualmente publicar en la Tienda de Aplicaciones y Google Play.

Tiempo requerido: ~30 minutos

¿Qué construirás:

  • Un nuevo proyecto de Nuxt 4 con la estructura de directorios más reciente
  • Configuración de generación estática para móviles
  • Capacitor 8 con plugins esenciales
  • Aplicaciones nativas de iOS y Android
  • Configuración de desarrollo con recarga en vivo

Ya tienes una aplicación de Nuxt? Consulta en lugar de Convertir tu aplicación de Nuxt a móvil en su lugar.

Requisitos previos

Asegúrate de tener instalados los siguientes:

  • Node.js 18+ (verifica con node --version)
  • Bun gestor de paquetes (curl -fsSL https://bun.sh/install | bash)
  • Xcode (solo para macOS, para desarrollo de iOS)
  • Android Studio (para desarrollo de Android)

Paso 1: Crea un Nuevo Proyecto de Nuxt 4

Comienza creando un proyecto de Nuxt 4 fresco:

bunx nuxi@latest init my-mobile-app
cd my-mobile-app
bun install

Estructura de Directorio de Nuxt 4

Nuxt 4 utiliza una nueva estructura de directorio con la aplicación code en el app/ directorios:

my-mobile-app/
  app/
    assets/
    components/
    composables/
    layouts/
    middleware/
    pages/
    plugins/
    utils/
    app.vue
  public/
  server/
  nuxt.config.ts
  package.json

Esta estructura proporciona una mejor separación entre la aplicación y el servidor code.

Paso 2: Configurar Nuxt para la Generación Estática

Capacitor requiere archivos HTML/JS/CSS estáticos. Configurar Nuxt para la generación estática en nuxt.config.ts:

export default defineNuxtConfig({
  compatibilityDate: '2025-01-15',
  devtools: { enabled: true },

  // Enable static generation
  ssr: true,
  nitro: {
    preset: 'static',
  },
});

Paso 3: Agregar Scripts Móviles

Actualice su package.json con scripts de desarrollo móvil:

{
  "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"
  }
}

Pruebe la generación estática:

bun run generate

Debería ver un .output/public directorios con sus archivos estáticos.

Paso 4: Instale Capacitor 8

Instale los paquetes de núcleo Capacitor:

bun add @capacitor/core
bun add -D @capacitor/cli

Instale los plugins esenciales que la mayoría de las aplicaciones móviles necesitan:

bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences

¿Qué hacen estos plugins:

  • @capacitor/app — Eventos de ciclo de vida de la aplicación (anterior/plano, enlaces profundos)
  • — @capacitor/teclado — Controlar el comportamiento del teclado
  • — @capacitor/pantalla-de-pulso — Control de pantalla de pulso nativa
  • — @capacitor/barra-de-estado — Estilizar la barra de estado del dispositivo
  • — @capacitor/preferencias — Almacenamiento de valor clave (como localStorage pero nativo)

Step 5: Inicializa Capacitor

Inicializa Capacitor con detalles de tu proyecto:

bunx cap init "My Mobile App" com.example.mymobileapp --web-dir .output/public

Sustituye:

  • "My Mobile App" por el nombre de pantalla de tu aplicación
  • com.example.mymobileapp por el ID de tu aplicación (notación de dominio inverso)

Esto crea capacitor.config.ts. Actualiza con la configuración del plugin:

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile 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;

Step 6: Agrega Plataformas Nativas

Instala los paquetes de plataforma:

bun add @capacitor/ios @capacitor/android

Genera los proyectos nativos:

bunx cap add ios
bunx cap add android

Esto crea ios And android carpetas que contienen proyectos nativos.

Step 7: Construye y Ejecuta

Construye tu proyecto y sincroniza con plataformas nativas:

bun run mobile

Abre en Simulador de iOS:

bun run mobile:ios

O Emulador de Android:

bun run mobile:android

En Xcode (iOS):

  1. Selecciona un simulador desde el menú de dispositivos
  2. Pulsa el botón de reproducción o presiona Cmd + R

En Android Studio:

  1. Espera a que Gradle termine de sincronizar
  2. Selecciona un emulador desde el menú de dispositivos
  3. Haz clic en el botón Ejecutar o presiona Shift + F10

Paso 8: Configura Live Reload

Para un desarrollo más rápido, habilita la recarga en vivo para que los cambios se reflejen instantáneamente en tu dispositivo.

  1. Encuentra tu dirección IP local:
# macOS
ipconfig getifaddr en0

# Windows
ipconfig
  1. Crea un archivo de configuración de desarrollo Capacitor. Actualiza capacitor.config.ts:
import type { CapacitorConfig } from '@capacitor/cli';

const devConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: '.output/public',
  server: {
    url: 'http://YOUR_IP_ADDRESS:3000',
    cleartext: true,
  },
  plugins: {
    // ... same plugin config
  },
};

const prodConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: '.output/public',
  plugins: {
    // ... same plugin config
  },
};

const config = process.env.NODE_ENV === 'development' ? devConfig : prodConfig;

export default config;
  1. Inicia el servidor de desarrollo y copia la configuración a nativo:
bun run dev &
NODE_ENV=development bunx cap copy
  1. Reconstruye en Xcode/Android Studio

Ahora los cambios en tu Nuxt code se recargarán automáticamente en el dispositivo.

Paso 9: Crea tu primera pantalla móvil

Vamos a crear una pantalla de inicio amigable con dispositivos móviles. Actualiza app/app.vue:

<template>
  <NuxtPage />
</template>

Crea app/pages/index.vue:

<template>
  <main
    class="min-h-screen bg-linear-to-b from-green-500 to-green-700 flex flex-col items-center justify-center p-6 text-white"
  >
    <h1 class="text-4xl font-bold mb-4">My Mobile App</h1>
    <p class="text-xl mb-8 text-center opacity-90">
      Built with Nuxt 4 + Capacitor 8
    </p>

    <div v-if="appInfo" class="bg-white/20 rounded-lg p-4 backdrop-blur-sm mb-8">
      <p class="text-sm">
        {{ appInfo.name }} v{{ appInfo.version }}
      </p>
    </div>

    <div class="space-y-4 w-full max-w-sm">
      <button
        class="w-full py-4 px-6 bg-white text-green-600 rounded-xl font-semibold text-lg shadow-lg active:scale-95 transition-transform"
        @click="handleGetStarted"
      >
        Get Started
      </button>
      <button
        class="w-full py-4 px-6 bg-white/20 text-white rounded-xl font-semibold text-lg backdrop-blur-sm active:scale-95 transition-transform"
        @click="handleShare"
      >
        Share App
      </button>
    </div>
  </main>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { App } from '@capacitor/app';

const appInfo = ref<{ name: string; version: string } | null>(null);

let backButtonListener: { remove: () => void } | null = null;

onMounted(async () => {
  // Get app info
  try {
    appInfo.value = await App.getInfo();
  } catch (e) {
    // Web fallback
    appInfo.value = { name: 'My Mobile App', version: '1.0.0' };
  }

  // Handle Android back button
  backButtonListener = await App.addListener('backButton', ({ canGoBack }) => {
    if (!canGoBack) {
      App.exitApp();
    } else {
      window.history.back();
    }
  });
});

onUnmounted(() => {
  backButtonListener?.remove();
});

function handleGetStarted() {
  // Navigate to onboarding or main app
  console.log('Get started clicked');
}

async function handleShare() {
  // We'll implement this with the Share plugin later
  console.log('Share clicked');
}
</script>

Paso 10: Agrega Tailwind CSS

For el estilo funcionar, agrega Tailwind CSS a tu proyecto:

bun add tailwindcss @tailwindcss/vite

Actualizar nuxt.config.ts:

import tailwindcss from '@tailwindcss/vite';

export default defineNuxtConfig({
  compatibilityDate: '2025-01-15',
  devtools: { enabled: true },

  ssr: true,
  nitro: {
    preset: 'static',
  },

  css: ['~/assets/css/main.css'],

  vite: {
    plugins: [tailwindcss()],
  },
});

Crear app/assets/css/main.css:

@import 'tailwindcss';

:root {
  --sat: env(safe-area-inset-top);
  --sar: env(safe-area-inset-right);
  --sab: env(safe-area-inset-bottom);
  --sal: env(safe-area-inset-left);
}

body {
  padding-top: var(--sat);
  padding-right: var(--sar);
  padding-bottom: var(--sab);
  padding-left: var(--sal);
}

/* Prevent text selection on mobile */
* {
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Allow text selection in inputs */
input,
textarea {
  -webkit-user-select: auto;
  user-select: auto;
}

Paso 11: Agrega el plugin de Compartir

Implementemos la funcionalidad del botón de compartir:

bun add @capacitor/share

Actualizar app/pages/index.vue para usar el plugin de Compartir:

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { App } from '@capacitor/app';
import { Share } from '@capacitor/share';

// ... existing code ...

async function handleShare() {
  try {
    await Share.share({
      title: 'Check out this app!',
      text: 'Built with Nuxt 4 and Capacitor 8',
      url: 'https://capacitorjs.com',
      dialogTitle: 'Share with friends',
    });
  } catch (e) {
    console.log('Share cancelled or failed:', e);
  }
}
</script>

Sincroniza y reconstruye:

bun run mobile

Estructura del Proyecto

Tu proyecto debería verse así:

my-mobile-app/
├── android/                  # Android native project
├── ios/                      # iOS native project
├── .output/
│   └── public/              # Static build output
├── app/
│   ├── assets/
│   │   └── css/
│   │       └── main.css
│   ├── pages/
│   │   └── index.vue
│   └── app.vue
├── capacitor.config.ts       # Capacitor configuration
├── nuxt.config.ts            # Nuxt configuration
├── package.json
└── ...

Pasos siguientes

Ahora tienes una aplicación móvil de Nuxt funcionando. Aquí está qué hacer a continuación:

Configuración Básica

  • Iconos de Aplicación: Sustituye los iconos predeterminados en ios/App/App/Assets.xcassets y android/app/src/main/res
  • Pantalla de Inicio: Personaliza en proyectos nativos o utiliza @capacitor/splash-screen configuración
  • Enlaces Profundos: Configura esquemas de URL para tu aplicación

Agregar Más Características

  • Cámara: bun add @capacitor/camera
  • Ubicación: bun add @capacitor/geolocation
  • Notificaciones Push: bun add @capacitor/push-notifications o @capgo/capacitor-firebase-messaging ¿Qué alternativas tenemos para Appflow?
  • ¿Qué alternativas tenemos para Capawesome? bun add @capacitor/filesystem

¿Qué alternativas tenemos para la actualización en vivo de Capacitor?

@Capgo/__CAPGO_KEEP_1__-firebase-messaging

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

@__CAPGO_KEEP_0__/__CAPGO_KEEP_1__-native-navigation @capgo/tailwind-capacitor :

bun add -D tailwind-capacitor

Ver Usando @capgo/capacitor-navegación-nativa , Usando @capgo/capacitor-transiciones , y el repositorio tailwind-capacitor para la configuración específica de Nuxt.

Corrigiendo problemas de diseño en iOS (Vista previa, Área segura y desbordamiento horizontal)

Si el contenido parece recortado, desplazado o desplazable horizontalmente en iOS, agregar más overflow-x: hidden o ajustar la etiqueta de vista previa sola no suele solucionar el problema. Pase por estos controles en orden.

Asegúrese de que la etiqueta meta de vista previa se aplique correctamente

En nuxt.config.tsEstablecer la vista a través de app.head:

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

Gestionar el área seguro de iOS desde un solo envoltorio raíz

Crear una caja de aplicación única y aplicar allí el relleno de área seguro, 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);
}

Envolver todo el contenido de la página dentro de .app-shellEl relleno de área seguro duplicado en encabezados, modales y envoltorios de diseño a menudo hace que la interfaz de usuario se vea recortada o demasiado grande.

Con @capgo/tailwind-capacitorpuedes expresar el mismo relleno con utilidades como pt-safe pb-safe px-safe en esa caja única.

Establecer Capacitor iOS contentInset a never context: Página/área: Página de productos de actualizaciones en vivo. Rol: Etiqueta de interfaz de usuario corta o elemento de navegación. Clave de mensaje `live_update_dynamic_label_to` (Etiqueta dinámica de actualización en vivo a).

Inicia capacitor.config.ts, prefiere el relleno de inseto nativo deshabilitado y deja que CSS (o la navegación nativa) contentInsetMode: 'css') tenga el área segura:

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

Mezclar el relleno de contenido de inseto automático de Capacitor con CSS env(safe-area-inset-*) relleno de padding es una causa común de doble espaciado.

Encuentra el elemento que se está desbordando realmente

El culpable usual es un elemento que utiliza 100vw, Tailwind w-screen, un ancho de píxeles fijo, o un ancho min-width.

In 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 cuando sea posible. Muchos problemas de rebosamiento horizontal provienen de 100vw / w-screenduplicado relleno de zona segura, o un contenedor de ancho fijo — no del meta etiqueta de viewport en sí.

Actualizaciones por Vía Aérea

Configuración Capgo para enviar actualizaciones sin la necesidad de volver a presentar la aplicación en la tienda:

bunx @capgo/cli init

Solución de Problemas

contexto: Página/área: Soporte / página de soporte premium o sección de soporte en el pie de página. Papel: Título de sección o página. Visto en: página support-policy.astro. Clave de mensaje `support_policy_troubleshooting_title` (Título de la política de soporte para solucionar problemas). El compilado falla con ‘No se puede encontrar el módulo’ bun install Ejecutar

y vuelve a intentarlo. iOS: ‘No se encontró identidad de firma’

Android: “ubicación de SDK no encontrada” Crear android/local.properties con sdk.dir=/path/to/android/sdk

Los cambios no aparecen en el dispositivo Asegúrate de haber ejecutado bun run mobile después de hacer cambios. Para el recarga en vivo, verifica que la dirección IP es correcta y que el servidor de desarrollo está en ejecución.

.output/public está vacío o faltante Asegúrate de haber configurado nitro: { preset: 'static' } en nuxt.config.ts y ejecutar bun run generate.

Recursos

¿Listo para enviar tu aplicación? Aprende cómo Capgo puede ayudarte a entregar actualizaciones más rápido — inscríbete en una cuenta gratuita hoy.

Sigue adelante desde Construye una aplicación móvil de Nuxt desde cero con Capacitor 8

Si estás utilizando Construye una aplicación móvil de Nuxt desde cero con Capacitor 8 a planificar la automatización de CI/CD, conecta con Capgo CI/CD para el flujo de trabajo del producto en Capgo CI/CD Capgo Compilaciones Nativas para el flujo de trabajo del producto en Capgo Compilaciones Nativas Capgo Integraciones para el flujo de trabajo del producto en Capgo Integraciones Integración CI/CD para el detalle de implementación en Integración CI/CD, y GitHub Integración de Acciones para el detalle de implementación en GitHub Integración de Acciones

Actualizaciones en vivo para aplicaciones Capacitor

Cuando un error de capa web está vivo, envíe la corrección a través de Capgo en lugar de esperar días para la aprobación de la tienda de aplicaciones. Los usuarios obtienen la actualización en segundo plano mientras los cambios nativos siguen en el camino de revisión normal.

Apoyo humano de Martin

Iniciar ahora

Últimas noticias de nuestro Blog

Capgo te brinda las mejores perspectivas que necesitas para crear una aplicación móvil verdaderamente profesional.