Saltar al contenido principal
Guía de tutoría

Crear una aplicación móvil de Next.js desde cero con Capacitor 8

Guía paso a paso para crear un nuevo proyecto de Next.js 15 y convertirlo en aplicaciones móviles nativas de iOS y Android utilizando Capacitor 8. Ideal para empezar de cero con el desarrollo móvil

Créditos del artículo

Martin Donadieu

Escritor

Valeria

Revisor

Jordan

Editor

Crear una aplicación móvil de Next.js desde cero con Capacitor 8

Introducción

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

Al finalizar esta tutorí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

Lo que construirás:

  • Un nuevo proyecto de Next.js 15 con App Router
  • Configuración de exportación estática para móviles
  • Capacitor 8 with essential plugins
  • Aplicaciones nativas iOS y Android
  • Configuración de desarrollo de live reload

Ya tienes una aplicación de Next.js? Convierte tu aplicación de Next.js a móvil en su lugar.

Requisitos previos

Asegúrate de tener instalados estos:

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

Paso 1: Crear un Nuevo Proyecto de Next.js

Comience creando un proyecto de Next.js 15 fresco:

bunx create-next-app@latest my-mobile-app

Cuando se le solicite, seleccione estas opciones:

  • TypeScript: Sí (recomendado)
  • ESLint:
  • Tailwind CSS: Sí (recomendado para estilos móviles)
  • src/ carpeta:
  • Ruta de la aplicación: Sí (recomendado)
  • Alias de importación: Predeterminado (@/*)

Dirígete a tu proyecto:

cd my-mobile-app

Paso 2: Configura Next.js para exportación estática

Capacitor requiere archivos HTML/JS/CSS estáticos. Configura Next.js para exportación estática actualizando next.config.ts:

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  output: 'export',
  images: {
    unoptimized: true,
  },
  // Ensure trailing slashes for proper routing in Capacitor
  trailingSlash: true,
};

export default nextConfig;

¿Por qué estos ajustes?

  • output: 'export' — Genera HTML estático en lugar de requerir un servidor Node.js
  • images: { unoptimized: true } — Desactiva la optimización de imágenes de Next.js (requiere un servidor)
  • trailingSlash: true — Asegura la ruta correcta en la vista previa nativa

Paso 3: Agrega scripts móviles

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

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "mobile": "bun run build && bunx cap sync",
    "mobile:ios": "bun run mobile && bunx cap open ios",
    "mobile:android": "bun run mobile && bunx cap open android"
  }
}

Pruebe la compilación:

bun run build

Debería ver un out con sus archivos estáticos.

Paso 4: Instale Capacitor 8

Instale los paquetes de Capacitor básicos:

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

Instale 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/keyboard --- Controlar el comportamiento del teclado
  • @capacitor/pantalla-de-bienvenida --- Control de pantalla de bienvenida nativa
  • @capacitor/barra-de-estado --- Estilizar la barra de estado del dispositivo
  • @capacitor/preferencias --- Almacenamiento de valores clave (como localStorage pero nativo)

Step 5: Inicializar Capacitor

Inicializar Capacitor con detalles de su proyecto:

bunx cap init "My Mobile App" com.example.mymobileapp --web-dir out

Sustituir:

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

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

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

const config: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: 'out',
  plugins: {
    SplashScreen: {
      launchShowDuration: 2000,
      launchAutoHide: true,
      androidScaleType: 'CENTER_CROP',
      splashFullScreen: true,
      splashImmersive: true,
    },
    Keyboard: {
      resize: 'body',
      resizeOnFullScreen: true,
    },
    StatusBar: {
      style: 'light',
    },
  },
};

export default config;

Paso 6: Agregar Plataformas Nativas

Instale los paquetes de plataforma:

bun add @capacitor/ios @capacitor/android

Genere los proyectos nativos:

bunx cap add ios
bunx cap add android

Esto crea ios y android directorios que contienen los proyectos nativos.

Paso 7: Compilar y Ejecutar

Compile su proyecto y sincronice con las plataformas nativas:

bun run mobile

Abrir en Simulador de iOS:

bun run mobile:ios

O Emulador de Android:

bun run mobile:android

En Xcode (iOS):

  1. Seleccione un simulador desde el menú de dispositivos
  2. Haga clic en el botón de reproducción o presione Cmd + R

En Android Studio:

  1. Espere a que Gradle termine de sincronizar
  2. Seleccione un emulador desde el menú de dispositivos
  3. Haga clic en el botón de ejecución o presione Shift + F10

Paso 8: Configuración de Live Reload

Para un desarrollo más rápido, habilite la reproducción en vivo para que los cambios aparezcan instantáneamente en su dispositivo.

  1. Encuentre su dirección IP local:
# macOS
ipconfig getifaddr en0

# Windows
ipconfig
  1. Cree una configuración de desarrollo Capacitor. Agregue a capacitor.config.ts:
import type { CapacitorConfig } from '@capacitor/cli';

const devConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: 'out',
  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: 'out',
  plugins: {
    // ... same plugin config
  },
};

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

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

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

Paso 9: Crea tu primera pantalla móvil

Vamos a crear una pantalla de inicio simple y móvil. Actualizar src/app/page.tsx:

'use client';

import { useEffect, useState } from 'react';
import { App } from '@capacitor/app';
import { Keyboard } from '@capacitor/keyboard';

export default function Home() {
  const [appInfo, setAppInfo] = useState<{ name: string; version: string } | null>(null);

  useEffect(() => {
    // Get app info on mount
    App.getInfo().then(setAppInfo).catch(console.error);

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

    // Hide keyboard when tapping outside inputs
    const keyboardHandler = Keyboard.addListener('keyboardWillShow', () => {
      document.body.classList.add('keyboard-open');
    });

    return () => {
      backHandler.then(h => h.remove());
      keyboardHandler.then(h => h.remove());
    };
  }, []);

  return (
    <main className="min-h-screen bg-linear-to-b from-blue-500 to-blue-700 flex flex-col items-center justify-center p-6 text-white">
      <h1 className="text-4xl font-bold mb-4">My Mobile App</h1>
      <p className="text-xl mb-8 text-center opacity-90">
        Built with Next.js 15 + Capacitor 8
      </p>

      {appInfo && (
        <div className="bg-white/20 rounded-lg p-4 backdrop-blur-sm">
          <p className="text-sm">
            {appInfo.name} v{appInfo.version}
          </p>
        </div>
      )}

      <div className="mt-12 space-y-4 w-full max-w-sm">
        <button className="w-full py-4 px-6 bg-white text-blue-600 rounded-xl font-semibold text-lg shadow-lg active:scale-95 transition-transform">
          Get Started
        </button>
        <button className="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">
          Learn More
        </button>
      </div>
    </main>
  );
}

Paso 10: Agregar manejo de área segura

Los dispositivos móviles tienen agujeros, indicadores de inicio y barras de estado. Agrega manejo de área segura con Tailwind.

Actualizar src/app/globals.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

: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;
}

/* Keyboard handling */
.keyboard-open {
  --sab: 0px;
}

Estructura del proyecto

Tu proyecto debería verse así:

my-mobile-app/
├── android/              # Android native project
├── ios/                  # iOS native project
├── out/                  # Static build output
├── src/
│   ├── app/
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   └── page.tsx
│   └── ...
├── capacitor.config.ts   # Capacitor configuration
├── next.config.ts        # Next.js configuration
├── package.json
└── ...

Pasos siguientes

Tienes ahora una aplicación móvil Next.js funcionando. Aquí está lo que debes hacer a continuación:

Configuración básica

  • Íconos de la Aplicación: Reemplazar íconos predeterminados en ios/App/App/Assets.xcassets y android/app/src/main/res
  • Pantalla de Inicio: Personalizar en proyectos nativos o utilizar @capacitor/splash-screen configuración
  • Enlaces Profundos: Configurar 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
  • Sistema de archivos: bun add @capacitor/filesystem

Interfaz de usuario nativa y transiciones

Utilice plugins Capgo en lugar de Konsta UI para un sentir móvil nativo:

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

Para áreas seguras de Tailwind, agregue @capgo/tailwind-capacitor:

bun add -D tailwind-capacitor

Consulte Usando @capgo/capacitor-navegación-nativa, Usando @capgo/capacitor-transiciones, y el repo de tailwind-capacitor para la configuración específica de Next.js.

Solucionar Problemas de Diseño en iOS (Viewport, Á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 viewport sola no suele solucionarlo. Pase por estos controles en orden.

Asegúrese de que la etiqueta meta de viewport se aplique correctamente

App Router (app/): export viewport de app/layout.tsx:

import type { Viewport } from 'next';

export const viewport: Viewport = {
  width: 'device-width',
  initialScale: 1,
  viewportFit: 'cover',
};

Pages Router (pages/): coloque la etiqueta meta de viewport en pages/_app.tsxno _document.tsx.

Administrar el área segura de iOS desde un wrapper raíz solo

Crear una caja de aplicación única y aplicar allí el relleno del área segura, no en múltiples componentes anidados:

html,
body,
#__next {
  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 duplicado del área segura en encabezados, modales y wrappers de diseño a menudo hace que la IU parezca 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 con actualizaciones en vivo. Rol: Etiqueta de IU corta o elemento de navegación. Clave de mensaje `live_update_dynamic_label_to` (Etiqueta dinámica de actualización en vivo a).

En capacitor.config.ts, prefiere el relleno de inset 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: 'out',
  ios: {
    contentInset: 'never',
  },
};

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

Encuentra el elemento que está desbordando realmente

El culpable habitual es un elemento que utiliza 100vw, Tailwind w-screen, un ancho de píxeles fijo, o un tamaño 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 When sea posible. Muchos problemas de rebosamiento horizontal provienen de 100vw / w-screenduplicados espacios de seguridad de área 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

Resolució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 Resolución de Problemas de la Política de Soporte). 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

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.

Recursos

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

Sigue adelante desde Construye una aplicación móvil de Next.js desde cero con Capacitor 8

Si estás utilizando Construye una aplicación móvil de Next.js desde cero con Capacitor 8 para planificar la automatización de CI/CD, conecta con Capgo CI/CD para el flujo de trabajo del producto en Capgo CI/CD, Capgo Builds Nativos para el flujo de trabajo del producto en Capgo Builds Nativos, 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 Línea para aplicaciones Capacitor

Cuando un error en la capa web está vivo, envía 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.

soporte humano de Martin

Inicia Ahora

Últimas noticias de nuestro Blog

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