Saltar al contenido principal
Tutorial

Cómo crear apps móviles con Vue y Capacitor

Aprende a crear una app móvil con Vue, Capacitor y, opcionalmente, mejora Capgo con navegación nativa, transiciones y mejores prácticas de diseño para iOS.

Creación de aplicaciones móviles con Vue y Capacitor Capgo ilustración del blog

En este tutorial, te guiaremos a través del proceso de convertir una aplicación web de Vue en una aplicación móvil nativa usando Capacitor. También puedes agregar Capgo Native Navigation and Transitions para una sensación móvil nativa, y usar tailwind-capacitor para áreas seguras.

Acerca de Capacitor

Capacitor es una herramienta que cambia las reglas del juego y te permite integrarla fácilmente en cualquier proyecto web y convertir tu aplicación en una aplicación móvil nativa. Genera proyectos nativos de Xcode y Android Studio para ti y proporciona acceso a funciones nativas del dispositivo, como la cámara, a través de un puente de JavaScript.

Prepara tu app de Vue

Primero, crea una nueva app de Vue ejecutando el siguiente comando:

vue create my-app
cd my-app
npm install

Para preparar tu app de Vue para el despliegue móvil nativo, deberás exportar tu proyecto. Añade un script en tu package.json para hacer el build y copiar el proyecto de Vue:

{
  "scripts": {
    // ...
    "build": "vue-cli-service build"
  }
}

Después de ejecutar el build comando, deberías ver una nueva dist carpeta en el directorio raíz de tu proyecto. Esta carpeta será usada por Capacitor más adelante.

Añade Capacitor a tu app de Vue

Para convertir tu web app de Vue en un contenedor móvil nativo, sigue estos pasos:

  1. Instala Capacitor CLI como una dependencia de desarrollo y configúralo en tu proyecto. Acepta los valores por defecto para el nombre y el bundle ID durante el setup.

  2. Instala el paquete core y los paquetes relevantes para las plataformas iOS y Android.

  3. Añade las plataformas, y Capacitor creará carpetas para cada una en la raíz de tu proyecto:

# Install the Capacitor CLI locally
npm install -D @capacitor/cli

# Initialize Capacitor in your Vue project
npx cap init

# Install the required packages
npm install @capacitor/core @capacitor/ios @capacitor/android

# Add the native platforms
npx cap add ios
npx cap add android

Ahora deberías ver nuevas iOS y Android carpetas en tu proyecto Vue.

Actualiza el archivo capacitor.config.json archivo para que el webDir apunte al resultado de tu comando de build:

{
  "appId": "com.example.app",
  "appName": "my-app",
  "webDir": "dist"
}

Ahora puedes hacer el build de tu proyecto Vue y sincronizarlo con Capacitor:

npm run build
npx cap sync

Build y deploy de apps nativas

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

Usa Capacitor CLI para abrir ambos proyectos nativos:

npx cap open ios
npx cap open android

Despliega tu app en un dispositivo conectado usando Android Studio o Xcode.

Live Reload con Capacitor

Activa el live reload en tu dispositivo móvil haciendo que la app Capacitor cargue el contenido desde una URL específica de tu red.

Busca tu dirección IP local y actualiza el capacitor.config.ts archivo con la IP y el puerto correctos:

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

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: 'dist',
  bundledWebRuntime: false,
  server: {
    url: 'http://192.168.x.xx:8080',
    cleartext: true
  }
};

export default config;

Aplica estos cambios copiándolos en tu proyecto nativo:

npx cap copy

Ahora, tu app se recargará automáticamente y mostrará los cambios cuando actualices tu app de Vue.

Uso de Capacitor Plugins

Instala un plugin de Capacitor, como el plugin Share, y úsalo en tu app de Vue:

npm i @capacitor/share

Importa el paquete y llama al share() función en tu app:

<template>
  <div>
    <h1>Welcome to Vue and Capacitor!</h1>
    <button @click="share">Share now!</button>
  </div>
</template>

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

async function share() {
  await Share.share({
    title: 'Open Youtube',
    text: 'Check new video on youtube',
    url: 'https://www.youtube.com',
    dialogTitle: 'Share with friends'
  });
}
</script>

Tras instalar nuevos plugins, ejecuta el sync comando y vuelve a desplegar la app en tu dispositivo:

npx cap sync

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

UI con sensación nativa, navegación y transiciones nativas de Capgo

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

Para una sensación nativa en una app de Vue + Capacitor, usa plugins de Capgo en lugar de UI kits web como Konsta UI:

  • @capgo/capacitor-native-navigation — navbar nativa, Liquid Glass tab bar en iOS y un estilo de tab bar con desenfoque en Android. Tu Vue Router mantiene el estado de las rutas; el plugin se encarga del chrome nativo.
  • @capgo/capacitor-transitions — transiciones de página estilo Ionic y swipe-back desde el borde en iOS en la capa WebView, sin adoptar 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 con desenfoque):

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 a setDirection('forward') o setDirection('back') antes de navegar. No dupliques headers o footers web si la navegación nativa ya gestiona esas áreas.

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

Safe areas con Tailwind

Para las safe areas del dispositivo 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 src/assets/main.css:

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

Usa utilidades como pt-safe, pb-safe, y px-safe en lugar de añadir env(safe-area-inset-*) manualmente. El proyecto se desarrolla activamente: si falta algo para tu configuración de Vue, abre un PR en GitHub.

Cómo solucionar problemas de layout en iOS (viewport, safe area y overflow 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 meta tag viewport esté bien aplicada

Añade la etiqueta meta viewport en index.html dentro del <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 único app shell y aplica el padding de safe area ahí, no en múltiples componentes anidados:

html,
body,
#app {
  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 usando 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 encargue del safe area:

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

Combinar el content inset automático de Capacitor con CSS env(safe-area-inset-*) es una causa común de espaciado doble.

Encuentra el elemento que realmente 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 sea posible. 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

Capacitor es una excelente opción para crear aplicaciones nativas a partir de un proyecto web existente. Con la incorporación de Capgo, es aún más fácil añadir Live Updates a tu app, asegurando que tus usuarios siempre tengan acceso a las últimas funciones y correcciones de errores.

Descubre cómo Capgo puede ayudarte a crear mejores apps más rápido: crea una cuenta gratis hoy.

Sigue con Building Mobile Apps with Vue and Capacitor

Si estás usando Cómo crear apps móviles con Vue y Capacitor para planificar el comportamiento de los medios nativos y la interfaz, conéctalo con Uso de @capgo/capacitor-live-activities para la capacidad nativa en Uso de @capgo/capacitor-live-activities, @capgo/capacitor-live-activities para los detalles de implementación en @capgo/capacitor-live-activities, Uso de @capgo/capacitor-video-player para la capacidad nativa en Uso de @capgo/capacitor-video-player, @capgo/capacitor-video-player por el detalle de implementación en @capgo/capacitor-video-player, y Uso de @capgo/capacitor-native-navigation para la capacidad nativa al usar @capgo/capacitor-native-navigation.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de 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 flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.