Introducción
¿Quieres construir 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 primer día, y luego empaquetarlo como aplicaciones nativas de iOS y Android utilizando Capacitor 8.
Por el final de esta tutoría, tendrás una aplicación móvil funcionando en simuladores que puedes seguir desarrollando y eventualmente publicar en la Tienda de App 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 con recarga en vivo
Ya tienes una aplicación de Next.js? Consulta Convertir tu aplicación de Next.js a móvil en su lugar.
Requisitos previos
Asegúrate de tener instalados:
- Node.js 18+ (verificar 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 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 pregunte, seleccione estas opciones:
- TypeScript: Sí (recomendado)
- ESLint: Sí
- Tailwind CSS: Sí (recomendado para estilos móviles)
src/carpeta: Sí- App Router: Sí (recomendado)
- Alias de importación: Por defecto (
@/*)
Navega a tu proyecto:
cd my-mobile-app
Step 2: Configure Next.js para Exportación Estática
Capacitor requiere archivos HTML/JS/CSS estáticos. Configure 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.jsimages: { 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: Agregar 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.
Step 4: Instale Capacitor 8
Instale los paquetes de núcleo de Capacitor:
bun add @capacitor/core
bun add -D @capacitor/cli
Install essential plugins that most mobile apps need:
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences
¿Qué hacen estos plugins:
- @capacitor/app — Eventos de ciclo de aplicación (anterior/plano, enlaces profundos)
- @capacitor/teclado — Controlar el comportamiento del teclado
- @capacitor/pantalla-de-inicio — Controlar la pantalla de inicio nativa
- @capacitor/barra-de-estado — Estilizar la barra de estado del dispositivo
- @capacitor/preferencias — Almacenamiento de valores clave (como localStorage pero nativo)
Paso 5: Inicializa Capacitor
Inicializa Capacitor con los 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óncom.example.mymobileapppor el ID de tu aplicación (notación de dominio inverso)
Esto crea capacitor.config.tsActualízalo 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
Construye tu proyecto y sincroniza con 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):
- Selecciona un simulador desde el menú de dispositivos
- Haz clic en el botón de reproducción o presiona
Cmd + R
En Android Studio:
- Espera a que Gradle termine de sincronizar
- Seleccione un emulador desde el menú de dispositivos
- Haga clic en el botón Ejecutar o presione
Shift + F10
Step 8: Configuración de Live Reload
Para un desarrollo más rápido, habilite la recarga en vivo para que los cambios se reflejen de inmediato en su dispositivo.
- Encuentre su dirección IP local:
# macOS
ipconfig getifaddr en0
# Windows
ipconfig
- Cree un archivo de 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;
- Inicie el servidor de desarrollo y copie la configuración a nativo:
bun run dev &
NODE_ENV=development bunx cap copy
- Reconstruya en Xcode/Android Studio
Ahora las ediciones de tu Next.js code se recargarán automáticamente en el dispositivo.
Step 9: Crea la primera pantalla móvil
Vamos a crear una pantalla de inicio simple y móvil. Actualice 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: Agregue manejo de área segura
Dispositivos móviles tienen notches, indicadores de inicio y barras de estado. Agregue manejo de área segura con Tailwind.
Actualización 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
Ahora tienes una aplicación móvil de Next.js funcionando. Aquí tienes lo siguiente que hacer.
Íconos de la aplicación:
- App Icons: Sustituye los iconos predeterminados en
ios/App/App/Assets.xcassetsandandroid/app/src/main/res - Pantalla de bienvenida: Personaliza en proyectos nativos o utiliza
@capacitor/splash-screenconfig - Enlaces Profundos: Configura los 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 de Capgo en lugar de Konsta UI para un sentir móvil nativo:
- @capgo/capacitor-navegación-nativa — Liquid Glass tab bar and native navbar
- @capgo/capacitor-transiciones — transiciones de página que se sienten nativas
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
Ver 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)
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 solucionar el problema. Trabaja a través de estas comprobaciones en orden.
Asegúrate de que la etiqueta meta de viewport esté aplicada correctamente
Ruta de Aplicación (app/): export viewport desde app/layout.tsx:
import type { Viewport } from 'next';
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
viewportFit: 'cover',
};
Rutas de Páginas (pages/): coloca la etiqueta meta de viewport en pages/_app.tsx, no _document.tsx.
Gestiona el área segura de iOS desde un solo contenedor raíz
Crea una caja de aplicación única y aplica 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);
}
Wrap all page content inside .app-shellEl relleno de área segura duplicado en encabezados, modales y contenedores de diseño a menudo hace que la interfaz de usuario se vea recortada o demasiado grande.
With @capgo/tailwind-capacitor, puedes expresar el mismo relleno con utilidades como pt-safe pb-safe px-safe en esa sola caja.
Establece Capacitor iOS contentInset a never primero
En capacitor.config.ts, prefiera el deshabilitado nativo y deja CSS (o la navegación nativa) contentInsetMode: 'css') se encargue del área segura:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'out',
ios: {
contentInset: 'never',
},
};
Mezclar el relleno de área automático de Capacitor con CSS env(safe-area-inset-*) rellena comúnmente con espacios dobles.
Encuentre el elemento que sobresale realmente
El culpable habitual es un elemento que utiliza 100vw, Tailwind w-screenuna anchura de píxel fija, o una gran 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 desbordamiento horizontal provienen de 100vw / w-screenNo se debe obtener el ancho de la vista desde la etiqueta meta de viewport en sí misma.
Actualizaciones en Línea
Configura Capgo Empujar actualizaciones sin reenvío de la tienda de aplicaciones.
bunx @capgo/cli init
Troubleshooting
Build falla con “No se puede encontrar el módulo”
Ejecutar bun install y vuelve a intentarlo.
iOS: "No se encontró identidad de firma" Abra Xcode, vaya a Signing & Capabilities y seleccione su equipo de desarrollo.
Android: “ubicación de SDK no encontrada”
Create android/local.properties Crear sdk.dir=/path/to/android/sdk
Cambios no se muestran en el dispositivo
Asegúrate de que ejecutaste bun run mobile después de realizar cambios. Verifique que la dirección IP es correcta y el servidor de desarrollo está en ejecución.
Recursos
- Capacitor 8 Documentación
- Documentación de Next.js 15
- Capgo - Actualizaciones en vivo
- @capgo/capacitor-navegación nativa
- @capgo/capacitor-transiciones
- @capgo/tailwind-capacitor
¿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 Next.js desde cero con Capacitor 8
If 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 de CI/CD para el detalle de implementación en Integración de CI/CD, y GitHub Acciones de Integración para los detalles de implementación en GitHub Acciones de Integración.