Introduction
Vous voulez créer une application mobile avec Next.js en partant de zéro ? Ce guide vous accompagne dans la création d'un tout nouveau projet Next.js 15 configuré pour le mobile dès le départ, puis dans son packaging en applications natives iOS et Android en utilisant Capacitor 8.
À la fin de ce tutoriel, vous aurez une application mobile fonctionnelle qui tourne sur les simulateurs, que vous pourrez continuer à développer et finir par publier sur l'App Store et Google Play.
Temps requis : ~30 minutes
Ce que vous allez créer :
- Un nouveau projet Next.js 15 avec App Router
- Configuration de l'export statique pour le mobile
- Capacitor 8 avec les plugins essentiels
- Des apps natives iOS et Android
- Configuration de développement avec live reload
Vous avez déjà une app Next.js ? Découvrez Convert Your Next.js App to Mobile plutôt.
Prerequisites
Assurez-vous d'avoir installé ceci :
- Node.js 18+ (vérifier avec
node --version) - Bun gestionnaire de paquets (
curl -fsSL https://bun.sh/install | bash) - Xcode (macOS uniquement, pour le développement iOS)
- Android Studio (pour le développement Android)
Étape 1 : créer un nouveau projet Next.js
Commencez par créer un nouveau projet Next.js 15 :
bunx create-next-app@latest my-mobile-app
Lorsqu'on vous le demande, sélectionnez ces options :
- TypeScript : Oui (recommandé)
- ESLint : Oui
- Tailwind CSS : Oui (recommandé pour le style mobile)
src/répertoire : Oui- App Router : Oui (recommandé)
- Alias d'importation : Par défaut (
@/*)
Accédez à votre projet :
cd my-mobile-app
Étape 2 : configurer Next.js pour l'export statique
Capacitor nécessite des fichiers HTML/JS/CSS statiques. Configurez l'export statique de Next.js en mettant à jour 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;
Pourquoi ces paramètres ?
output: 'export'— Génère du HTML statique au lieu de nécessiter un serveur Node.jsimages: { unoptimized: true }— Désactive l'optimisation des images de Next.js (nécessite un serveur)trailingSlash: true— Garantit un routage correct dans la WebView native
Étape 3 : Ajouter les scripts mobiles
Mettez à jour votre package.json avec les scripts de développement mobile :
{
"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"
}
}
Testez le build :
bun run build
Vous devriez voir un dossier out répertoire contenant vos fichiers statiques.
Étape 4 : Installer Capacitor 8
Installez les packages core Capacitor :
bun add @capacitor/core
bun add -D @capacitor/cli
Installez les plugins essentiels à la plupart des apps mobiles :
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences
Rôle de ces plugins :
- @capacitor/app — Événements du cycle de vie (premier plan/arrière-plan, deep links)
- @capacitor/keyboard — Contrôle du comportement du clavier
- @capacitor/splash-screen — Contrôle du splash screen natif
- @capacitor/status-bar — Personnaliser la barre d'état de l'appareil
- @capacitor/preferences — Stockage clé-valeur (comme localStorage mais natif)
Étape 5 : Initialiser Capacitor
Initialisez Capacitor avec les détails de votre projet :
bunx cap init "My Mobile App" com.example.mymobileapp --web-dir out
Remplacer :
"My Mobile App"par le nom d’affichage de votre applicationcom.example.mymobileapppar l’ID de votre application (notation de domaine inversée)
Cela crée capacitor.config.ts. Mettez-l’à jour avec la configuration du 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;
Étape 6 : Ajouter les plateformes natives
Installer les packages de plateforme :
bun add @capacitor/ios @capacitor/android
Générer les projets natifs :
bunx cap add ios
bunx cap add android
Cela crée ios et android répertoires contenant les projets natifs.
Étape 7 : build et exécution
Compilez votre projet et synchronisez-l’avec les plateformes natives :
bun run mobile
Ouvrir dans le simulateur iOS :
bun run mobile:ios
Ou l'émulateur Android :
bun run mobile:android
Dans Xcode (iOS) :
- Sélectionnez un simulateur dans le menu déroulant des appareils
- Cliquez sur le bouton Play ou appuyez sur
Cmd + R
Dans Android Studio :
- Attendez la fin de la synchronisation Gradle
- Sélectionnez un émulateur dans le menu des appareils
- Cliquez sur le bouton Run ou appuyez sur
Shift + F10
Étape 8 : Configurer le live reload
For faster development, enable live reload so changes appear instantly on your device.
- Trouvez votre adresse IP locale :
# macOS
ipconfig getifaddr en0
# Windows
ipconfig
- Créez une config de développement Capacitor. Ajoutez à
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;
- Lancez le serveur de dev et copiez la config vers le natif :
bun run dev &
NODE_ENV=development bunx cap copy
- Recompilez dans Xcode/Android Studio
Now edits to your Next.js code will hot-reload on the device.
Étape 9 : Créer votre premier écran mobile
Créons un écran d'accueil simple et mobile-friendly. Mise à jour 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>
);
}
Étape 10 : gérer les safe areas
Les appareils mobiles ont des encoches, un indicateur d'accueil et des barres d'état. Gérez les safe areas avec Tailwind.
Mise à jour 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;
}
Structure du projet
Votre projet devrait maintenant ressembler à ceci :
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
└── ...
Étapes suivantes
Vous avez maintenant une application mobile Next.js fonctionnelle. Voici la suite :
Configuration essentielle
- Icônes de l'app : Remplacez les icônes par défaut dans
ios/App/App/Assets.xcassetsetandroid/app/src/main/res - Écran de démarrage : Personnalisez dans vos projets natifs ou utilisez
@capacitor/splash-screenla config - Deep Links : Configurez les schémas d'URL de votre app
Ajoutez plus de fonctionnalités
- Caméra :
bun add @capacitor/camera - Géolocalisation :
bun add @capacitor/geolocation - Notifications push :
bun add @capacitor/push-notifications - Système de fichiers :
bun add @capacitor/filesystem
UI et transitions natives
Utilisez les plugins Capgo au lieu de Konsta UI pour un rendu mobile natif :
- @capgo/capacitor-native-navigation — Barre d'onglets Liquid Glass et navbar native
- @capgo/capacitor-transitions — transitions de page au rendu natif
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
Pour les safe areas Tailwind, ajoutez @capgo/tailwind-capacitor:
bun add -D tailwind-capacitor
Consultez Utilisation de @capgo/capacitor-native-navigation, Utiliser @capgo/capacitor-transitions, et le le repo tailwind-capacitor pour la configuration spécifique à Next.js.
Corriger les problèmes de mise en page iOS (viewport, zone sécurisée et débordement horizontal)
Si le contenu semble coupé, décalé ou défile horizontalement sur iOS, ajouter plus de overflow-x: hidden ou le simple ajustement de la balise viewport ne règle généralement pas le problème. Effectuez ces vérifications dans l'ordre.
Assurez-vous que la balise meta viewport est correctement appliquée
App Router (app/): export viewport depuis app/layout.tsx:
import type { Viewport } from 'next';
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
viewportFit: 'cover',
};
Pages Router (pages/): placez la balise meta viewport dans pages/_app.tsx, et non _document.tsx.
Gérez la safe area iOS depuis un seul wrapper racine
Créez un shell d'application unique et appliquez-y le padding de la safe area — pas dans plusieurs composants imbriqués :
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);
}
Enveloppez tout le contenu de la page dans .app-shell. Un padding de safe area dupliqué dans les headers, les modales et les wrappers de layout donne souvent l'impression que l'UI est rognée ou trop grande.
Avec @capgo/tailwind-capacitor, vous pouvez obtenir le même padding avec des utilitaires comme pt-safe pb-safe px-safe sur ce shell unique.
Configurez Capacitor iOS contentInset vers never d'abord
Dans capacitor.config.ts, préférez désactiver les insets natifs et laissez le CSS (ou la contentInsetMode: 'css') gèrent la safe area :
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'out',
ios: {
contentInset: 'never',
},
};
Combiner le content inset automatique de Capacitor avec le CSS env(safe-area-inset-*) le padding est une cause fréquente de double espacement.
Trouvez l'élément qui déborde réellement
Le coupable habituel est un élément utilisant 100vw, Tailwind w-screen, une largeur fixe en pixels, ou un grand min-width.
Dans le Web Inspector de Safari, lancez :
[...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,
}));
Avec Tailwind, remplacez w-screen par w-full dès que possible. De nombreux problèmes de débordement horizontal proviennent de 100vw / w-screen, d'un padding safe-area dupliqué, ou d'un conteneur à largeur fixe — et non de la balise meta viewport elle-même.
Mises à jour OTA
Configuration Capgo pour envoyer des mises à jour sans repasser par le store :
bunx @capgo/cli init
Troubleshooting
Le build échoue avec « Cannot find module »
Exécutez bun install et réessayez.
iOS : « No signing identity found » Ouvrez Xcode, allez dans Signing & Capabilities et sélectionnez votre équipe de développement.
Android : « SDK location not found »
Créer android/local.properties par sdk.dir=/path/to/android/sdk
Les changements n'apparaissent pas sur l'appareil
Assurez-vous d'avoir exécuté bun run mobile après avoir effectué les modifications. Pour le live reload, vérifiez que l'adresse IP est correcte et que le serveur de dev est lancé.
Ressources
- Documentation Capacitor
- Documentation Next.js 15
- Capgo - Live Updates
- @capgo/capacitor-native-navigation
- @capgo/capacitor-transitions
- @capgo/tailwind-capacitor
Prêt à déployer votre app ? Découvrez comment Capgo peut vous aider à livrer des mises à jour plus rapidement — créez un compte gratuit aujourd'hui.
Continuer à partir de « Créer une app mobile Next.js de zéro avec Capacitor 8 »
Si vous utilisez Créer une application mobile Next.js de zéro avec Capacitor 8 pour planifier l'automatisation CI/CD, et le connecter avec CI/CD Capgo pour le workflow produit dans le CI/CD de Capgo, Capgo Native Build pour le workflow produit dans les Native Builds de Capgo, Intégrations Capgo pour le workflow produit dans les intégrations de Capgo, Intégration CI/CD pour le détail d'implémentation dans l'intégration CI/CD, et Intégration GitHub Actions pour les détails d'implémentation de l'intégration GitHub Actions.