Saltar al contenido principal
Guía de tutoría

Build a Next.js Mobile App from Scratch with Capacitor 8

Step-by-step guide to creating a new Next.js 15 project and turning it into native iOS and Android mobile apps using Capacitor 8. Perfect for starting fresh with mobile-first development.

Martin Donadieu

Martin Donadieu

Gerente de contenido

Build a Next.js Mobile App from Scratch with Capacitor 8

Introducción

¿Quieres crear una aplicación móvil con Next.js desde cero? Esta guía te guía a través de la creación de un proyecto de Next.js 15 configurado para móviles desde el principio, luego empaquetarlo como aplicaciones móviles nativas de iOS y Android utilizando Capgo 8. 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 Next.js 15 con App Router
  • Configuración de exportación estática para móviles
  • Capacitor 8 con plugins esenciales
  • Aplicaciones nativas de iOS y Android
  • Configuración de desarrollo de reloj en vivo

Ya tienes una aplicación de Next.js? Consulta en lugar de Convertir tu aplicación de Next.js 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 Next.js

Comienza creando un proyecto de Next.js 15 fresco:

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

Cuando se te pregunte, selecciona estas opciones:

  • TypeScript: Sí (recomendado)
  • ESLint:
  • Tailwind CSS: Sí (recomendado para estilos móviles)
  • src/ directorio:
  • App Router: Sí (recomendado)
  • Alias de importación: Predeterminado (@/*)

Dirígete a tu proyecto:

cd my-mobile-app

Step 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;

Preguntas sobre 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 WebView nativa

Step 3: Agrega scripts móviles

Actualiza tu 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"
  }
}

Prueba la compilación:

bun run build

Deberías ver un out directorio con tus archivos estáticos.

Paso 4: Instala Capacitor 8

Instala los paquetes de core de Capacitor:

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

Instala 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 — Controla el comportamiento del teclado
  • @capacitor/pantalla-de-splash — Control de pantalla de arranque nativa
  • @capacitor/barra-de-estado — Estiliza la barra de estado del dispositivo
  • @capacitor/preferencias — Almacenamiento de valores clave (como localStorage pero nativo)

Paso 5: Inicializa Capacitor

Inicializa Capacitor con detalles de tu proyecto:

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

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: '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: 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 y android directorio que contiene los proyectos nativos.

Paso 7: Compilar y Ejecutar

Compila tu proyecto y sincroniza con las plataformas nativas:

bun run mobile

Abrir en iOS Simulator:

bun run mobile:ios

O Android Emulator:

bun run mobile:android

En Xcode (iOS):

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

En Android Studio:

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

Step 8: Configura Live Reload

Para un desarrollo más rápido, habilita la reactivación en vivo para que los cambios aparezcan 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. Agrega 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. 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 pantalla de inicio de Next.js code se recargarán automáticamente en el dispositivo.

Step 9: Crea tu primera pantalla móvil

Vamos a crear una pantalla de inicio simple y móvil. Actualiza 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>
  );
}

Step 10: Agregar Manejo de Área Segura

Los dispositivos móviles tienen notches, indicadores de inicio y barras de estado. Agregue el 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

Su 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

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

Configuración Esencial

  • Íconos de la Aplicación: Sustituir íconos 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 config
  • 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
  • Sistema de Archivos: bun add @capacitor/filesystem

Interfaz de usuario nativa y transiciones

Utiliza 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, agrega @capgo/tailwind-capacitor:

bun add -D tailwind-capacitor

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

Solucionando problemas de diseño de iOS (Vista previa, área segura y desbordamiento horizontal)

If el contenido parece recortado, desplazado o desplazable horizontalmente en iOS, agregar más overflow-x: hidden o ajustar la etiqueta de viewport sola usualmente no lo resuelve. Trabaja a través de estas comprobaciones en orden.

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

App Router (app/exportar viewport desde app/layout.tsx:

import type { Viewport } from 'next';

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

Pages Router (pages/pon la etiqueta meta de viewport en pages/_app.tsx, no _document.tsx.

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

Crear un solo contenedor de aplicación y aplicar allí el relleno de á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);
}

Envuelve todo el contenido de la página dentro .app-shell. El relleno de área segura duplicado en encabezados, modales y wrappers de diseño a menudo hace que la interfaz de usuario parezca recortada o demasiado grande.

Con @capgo/tailwind-capacitor, puedes expresar el mismo relleno con utilidades como pt-safe pb-safe px-safe en esa sola capa.

Establece Capacitor iOS contentInset a never primero

En capacitor.config.ts, prefiere el área de inserción nativa deshabilitada 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 Capacitor’s contenido automático con CSS env(safe-area-inset-*) el relleno es una causa común de doble espaciado.

Encuentra el elemento que está desbordando en realidad

El culpable habitual es un elemento que utiliza 100vw, Tailwind w-screen, un ancho de píxel fijo, o un contenedor muy ancho 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 cuando sea posible. Muchos problemas de desbordamiento horizontal provienen de 100vw / w-screen, duplicado relleno de área segura, o un contenedor de ancho fijo — no del etiqueta de meta de viewport en sí misma.

Actualizaciones por Vía Aérea

Configura Capgo para enviar actualizaciones sin la reenvío de la tienda de aplicaciones:

bunx @capgo/cli init

Resolución de Problemas

La compilación falla con “No se puede encontrar el módulo” Ejecutar bun install y vuelve a intentarlo.

iOS: “No se encontró la identidad de firma” Abra Xcode, vaya a Firmas y Capabilities, y seleccione su equipo de desarrollo.

Android: “SDK” no se encontró en la ubicación Crear android/local.properties con sdk.dir=/path/to/android/sdk

No se muestran los cambios en el dispositivo Asegúrate de haber ejecutado bun run mobile después de realizar cambios. Para el recarga en vivo, verifica que la dirección IP es correcta y 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 — inscríbete en una cuenta gratuita hoy.

Continúa desde Crea una aplicación móvil de Next.js desde cero con Capacitor 8

Si estás utilizando Crea una aplicación móvil de Next.js desde cero con Capacitor 8 para planificar la automatización de CI/CD, conecta con Capgo Automatización de CI/CD para el flujo de trabajo del producto en Capgo Automatización de 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, Integraciones Integración de CI/CD GitHub Acciones de Integración para el detalle de implementación en GitHub Acciones de Integración.

Actualizaciones en vivo para aplicaciones Capacitor

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

Apoyo humano de Martin

Inicia Ahora

Últimas noticias de nuestro Blog

Capgo te brinda las mejores herramientas para crear una aplicación móvil profesional de verdad.