Allez directement au contenu principal
Tutoriel

Construire une application mobile Next.js à partir de zéro avec Capacitor 8

Guide étape par étape pour créer un nouveau projet Next.js 15 et le transformer en applications mobiles natives iOS et Android à l'aide de Capacitor 8. Parfait pour démarrer avec un développement mobile centré sur l'utilisateur.

Créez une application mobile Next.js à partir de zéro avec Capacitor 8

Introduction

Voulez-vous créer une application mobile avec Next.js à partir de zéro ? Cette guide vous accompagne dans la création d'une nouvelle application Next.js 15 configurée pour les appareils mobiles dès le début, puis la mise en boîte sous forme d'applications natives iOS et Android à l'aide de Capacitor 8.

À la fin de ce tutoriel, vous disposerez d'une application mobile fonctionnelle exécutée sur des simulateurs que vous pourrez continuer à développer et publier ultérieurement sur l'App Store et Google Play.

Temps requis : ~30 minutes

Ce que vous allez construire :

  • Un nouveau projet Next.js 15 avec App Router
  • Configuration d'exportation statique pour mobile
  • Capacitor 8 avec plugins essentiels
  • Applications natives iOS et Android
  • Configuration de développement avec rechargement en direct

Déjà une application Next.js ? Consultez Convertir votre application Next.js en mobile au lieu de cela.

Prerequisites

Assurez-vous d'avoir ces éléments installés :

  • Node.js 18+ (vérifiez avec node --version)
  • Bun gestionnaire de packages (curl -fsSL https://bun.sh/install | bash)
  • Xcode (seulement sur macOS, pour le développement iOS)
  • Android Studio (pour le développement Android)

Étape 1 : Créez un nouveau projet Next.js

Commencez par créer un projet Next.js 15 frais :

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

Sélectionnez ces options lorsque vous y êtes invité.

  • TypeScript : Oui (recommandé)
  • ESLint : Oui
  • Développement natif Oui (recommandé pour la mise en forme mobile)
  • src/ directory: Oui
  • répertoire : Oui (recommandé)
  • App Router : Default (@/*)

Naviguez vers votre projet :

cd my-mobile-app

Étape 2 : Configurez Next.js pour l'exportation statique

Capacitor nécessite des fichiers HTML/JS/CSS statiques. Configurez Next.js pour l'exportation statique 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.js
  • images: { unoptimized: true } — Désactive l'optimisation des images Next.js (nécessite un serveur)
  • trailingSlash: true — Assure une navigation correcte dans la vue WebView native

Étape 3 : Ajoutez les scripts mobiles

Mettez à jour votre package.json avec des 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 la construction :

bun run build

Vous devriez voir un out répertoire avec vos fichiers statiques.

Étape 4 : Installez Capacitor 8

Installez les packages de noyau 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

Ce que font ces plugins :

  • @capacitor/app — Événements de cycle d'applications (avant-plan/arrière-plan, liens profonds)
  • @capacitor/keyboard — Gérer le comportement du clavier
  • @capacitor/splash-screen — Contrôle de l'écran de splash natif
  • @capacitor/status-bar — Personnalisez la barre d'état du dispositif
  • @capacitor/préférences — Stockage clé-valeur (comme localStorage mais natif)

Étape 5 : Initialiser Capacitor

Initialisez Capacitor avec vos détails de projet :

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

Replace:

  • "My Mobile App" avec le nom d'affichage de votre application
  • com.example.mymobileapp par le nom de votre application

Cela crée capacitor.config.tsMise à 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;

. Mettez à jour avec la configuration du plugin :

Étape 6 : Ajouter les plateformes natives

bun add @capacitor/ios @capacitor/android

Installez les packages de plateforme :

bunx cap add ios
bunx cap add android

Cela crée ios et android répertoires contenant les projets natifs.

Étape 7 : Construire et Exécuter

Construire votre projet et synchroniser avec les plateformes natives :

bun run mobile

Ouvrir dans l'émulateur iOS :

bun run mobile:ios

Ou l'émulateur Android :

bun run mobile:android

Dans Xcode (iOS) :

  1. Sélectionnez un simulateur dans le menu des appareils
  2. Cliquez sur le bouton Play ou appuyez sur Cmd + R

Dans Android Studio :

  1. Attendez que Gradle termine de synchroniser
  2. Choisissez un émulateur dans le menu déroulant du dispositif
  3. Cliquez sur le bouton Exécuter ou appuyez sur Shift + F10

Étape 8 : Activer le rechargement en direct

For faster development, enable live reload so changes appear instantly on your device.

  1. Trouvez votre adresse IP locale :
# macOS
ipconfig getifaddr en0

# Windows
ipconfig
  1. Créez une configuration de développement Capacitor. Ajoutez-y 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. Start the dev server and copy config to native:
bun run dev &
NODE_ENV=development bunx cap copy
  1. Rebâtissez dans Xcode/Android Studio

Now edits to your Next.js code will hot-reload on the device.

Étape 9 : Créez votre première écran mobile

Créons une simple page d'accueil mobile-friendly. Mettez à 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 : Ajoutez un traitement de zone de sécurité

Les appareils mobiles ont des rebords, des indicateurs d'accueil et des barres d'état. Ajoutez un traitement de zone de sécurité avec Tailwind.

Actualisation 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 de projet

Votre projet devrait 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 ce que faire ensuite.

Paramètres essentiels

  • App Icons: Remplacez les icônes par défaut dans ios/App/App/Assets.xcassets et android/app/src/main/res
  • Écran d'accueil : Personnalisez dans les projets natifs ou utilisez @capacitor/splash-screen config
  • Liens profonds : Configurez les schémas d'URL pour votre application

Ajoutez plus de fonctionnalités

  • Caméra : bun add @capacitor/camera
  • Geolocation: bun add @capacitor/geolocation
  • Notifications push : bun add @capacitor/push-notifications
  • Système de fichiers : bun add @capacitor/filesystem

Interface utilisateur native et transitions

Utilisez les plugins Capgo au lieu de Konsta UI pour un sentiment mobile natif :

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

Pour les zones de sécurité Tailwind, ajoutez @capgo/tailwind-capacitor:

bun add -D tailwind-capacitor

Voir Utilisation de @capgo/capacitor-navigation-native, Utilisation de @capgo/capacitor-transitions, et le repo tailwind-capacitor pour la configuration spécifique à Next.js.

Résoudre les problèmes de mise en page iOS (Vueport, Zone de sécurité, et débordement horizontal)

Si le contenu semble coupé, décalé ou scrollable horizontalement sur iOS, ajoutez plus overflow-x: hidden ou ajuster seul le tag de viewport ne résout généralement pas le problème. Travaillez ces vérifications dans l'ordre.

Assurez-vous que le tag de métadonnées de viewport est appliqué correctement

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

import type { Viewport } from 'next';

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

Routage de Pages (pages/): insérez le tag de métadonnées de viewport dans pages/_app.tsx, pas _document.tsx.

Gérer l'espace sûr d'iOS à partir d'un seul enveloppe racine

Créez un noyau d'application unique et appliquez-y un padding de zone de sécurité — 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 page à l'intérieur .app-shellLes marges de sécurité dupliquées dans les en-têtes, les modaux et les enveloppes de mise en page rendent souvent l'interface utilisateur coupée ou trop grande.

With @capgo/tailwind-capacitor, vous pouvez exprimer le même écartement avec des utilitaires comme pt-safe pb-safe px-safe on ce seul shell.

Configurez Capacitor iOS contentInset à never first

premier capacitor.config.tspréférez l'insérer nativement désactivé et laissez CSS (ou la navigation native) contentInsetMode: 'css'Propriétaire de la zone sécurisée :

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

Mélanger les Capacitor automatiques d'encart de contenu avec CSS env(safe-area-inset-*) l'espace de padding est une cause courante de double espace.

Trouvez l'élément qui déborde vraiment

Le coupable habituel est un élément utilisant 100vw, Tailwind w-screen, une largeur de pixels fixe, ou une large min-width.

Dans l'Inspecteur Web de Safari, exécutez :

[...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 lorsque possible. Beaucoup d'issues de débordement horizontal proviennent de 100vw / w-screenPas de padding de zone de sécurité dupliqué, ni un conteneur à largeur fixe — pas de la balise meta viewport elle-même.

Actualisations hors ligne

Configurez Capgo pour pousser des mises à jour sans résubmission de l'App Store :

bunx @capgo/cli init

Troubleshooting

Build fails with “Cannot find module” Run bun install Réessayez.

iOS : "Aucune identité de signature trouvée" Ouvrez Xcode, allez dans Signing &amp; Capabilités, et sélectionnez votre équipe de développement.

Android : “SDK n'a pas été trouvé” Create android/local.properties Créer sdk.dir=/path/to/android/sdk

Mises à jour non affichées sur le dispositif Assurez-vous d'avoir exécuté bun run mobile Après les modifications. Vérifiez l'adresse IP et assurez-vous que le serveur de développement est en cours d'exécution.

Ressources

Ready to ship your app? Learn how Capgo can help you deliver updates faster — s'inscrire à un compte gratuit aujourd'hui.

Continuez à partir de Construire une application mobile Next.js à partir de zéro avec Capacitor 8

Si vous utilisez Construirez une application mobile Next.js à partir de zéro avec Capacitor 8 pour planifier l'automatisation de CI/CD, connectez-l’avec Capgo CI/CD pour le flux de travail du produit dans Capgo CI/CD, Capgo Builds natifs pour le flux de travail du produit dans Capgo Builds natifs, Capgo Intégrations pour le flux de travail du produit dans Capgo Intégrations, Intégration CI/CD pour le détail d'implémentation dans Intégration CI/CD, et GitHub Actions d'intégration pour les détails d'implémentation dans GitHub Actions d'intégration.

Mises à jour instantanées pour les applications Capacitor

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

Dernières actualités de notre Blog

Capgo vous donne les meilleures pistes nécessaires pour créer une application mobile véritablement professionnelle.