Capacitor + React — Créer des applications mobiles multiplateformes depuis votre app web (2026)

AI Bot
Par AI Bot ·

Chargement du lecteur de synthèse vocale...

Votre code React, exécuté nativement sur iOS et Android. Capacitor comble le fossé entre le web et le mobile — en vous donnant un accès complet aux API natives comme la caméra, la géolocalisation, les notifications push et la biométrie, tout en conservant votre codebase React existante.

Ce que vous apprendrez

À la fin de ce tutoriel, vous serez capable de :

  • Comprendre le fonctionnement de Capacitor et ses différences avec React Native ou Cordova
  • Ajouter Capacitor à un projet React existant (basé sur Vite)
  • Accéder aux fonctionnalités natives : caméra, système de fichiers, retour haptique et stockage local
  • Compiler et exécuter votre app sur les simulateurs iOS et Android
  • Gérer le code spécifique à chaque plateforme proprement
  • Configurer les icônes, les écrans de démarrage et les liens profonds
  • Préparer votre app pour la soumission sur l'App Store et Google Play

Prérequis

Avant de commencer, assurez-vous d'avoir :

  • Node.js 20+ installé (node --version)
  • De solides connaissances en React et TypeScript
  • Xcode 16+ (pour iOS — macOS uniquement)
  • Android Studio avec un émulateur configuré (pour Android)
  • CocoaPods installé (sudo gem install cocoapods) pour iOS
  • Un éditeur de code comme VS Code

Pourquoi Capacitor ?

Capacitor est le runtime d'Ionic qui permet de déployer des applications web comme des apps mobiles natives. Contrairement à React Native, vous conservez votre code React standard basé sur le DOM — HTML, CSS, et tout le reste. Contrairement à Cordova (que Capacitor remplace), il utilise une architecture de plugins moderne, un support TypeScript de premier ordre, et peut même fonctionner simultanément comme Progressive Web App.

CaractéristiqueCapacitorReact NativeCordova
Rendu UIWebView (votre HTML/CSS)Vues nativesWebView
Système de pluginsModerne, TypeScript-firstModules bridgeLegacy XML
Support PWAIntégréAucunLimité
ÉcosystèmeEn croissance, soutenu par IonicMassifEn déclin
Courbe d'apprentissageFaible (si vous connaissez le web)Moyenne-ÉlevéeFaible

Étape 1 : Créer un projet React + Vite

Nous allons commencer avec un projet Vite + React + TypeScript neuf. Si vous en avez déjà un, passez à l'étape 2.

npm create vite@latest my-mobile-app -- --template react-ts
cd my-mobile-app
npm install

Vérifiez que tout fonctionne :

npm run dev

Ouvrez http://localhost:5173 — vous devriez voir la page par défaut de Vite + React.


Étape 2 : Installer Capacitor

Ajoutez le core et le CLI de Capacitor à votre projet :

npm install @capacitor/core
npm install -D @capacitor/cli

Initialisez Capacitor :

npx cap init

On vous demandera :

  • Nom de l'app : My Mobile App
  • Package ID : com.example.mymobileapp (notation en domaine inversé)

Cela crée un fichier capacitor.config.ts à la racine de votre projet :

import type { CapacitorConfig } from "@capacitor/cli";
 
const config: CapacitorConfig = {
  appId: "com.example.mymobileapp",
  appName: "My Mobile App",
  webDir: "dist",
  server: {
    androidScheme: "https",
  },
};
 
export default config;

Le webDir: "dist" indique à Capacitor où se trouvent vos assets web compilés — pour Vite, c'est dist.


Étape 3 : Ajouter les plateformes natives

Ajoutez les plateformes iOS et Android :

npm install @capacitor/ios @capacitor/android
npx cap add ios
npx cap add android

Cela crée les répertoires ios/ et android/ avec des projets natifs Xcode et Android Studio complets.

Compilez votre app web et synchronisez-la avec les projets natifs :

npm run build
npx cap sync

Exécutez toujours npx cap sync après avoir modifié votre code web ou installé de nouveaux plugins Capacitor. Cela copie votre répertoire dist/ compilé dans les projets natifs et met à jour les dépendances natives.


Étape 4 : Exécuter sur les simulateurs

iOS (macOS uniquement)

npx cap open ios

Cela ouvre le projet dans Xcode. Sélectionnez un simulateur (par exemple iPhone 15 Pro) et cliquez sur le bouton Run, ou lancez depuis le terminal :

npx cap run ios

Android

npx cap open android

Cela ouvre le projet dans Android Studio. Sélectionnez un émulateur et cliquez sur Run, ou :

npx cap run android

Vous devriez voir votre app React fonctionner dans un shell natif sur les deux plateformes.


Étape 5 : Accéder à la caméra avec un plugin natif

Construisons quelque chose de concret — une fonctionnalité de capture photo utilisant le plugin Camera de Capacitor.

Installez le plugin :

npm install @capacitor/camera
npx cap sync

Créez un hook personnalisé src/hooks/useCamera.ts :

import { Camera, CameraResultType, CameraSource } from "@capacitor/camera";
 
export function useCamera() {
  const takePhoto = async () => {
    const photo = await Camera.getPhoto({
      quality: 90,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      source: CameraSource.Camera,
    });
 
    return photo.webPath;
  };
 
  const pickFromGallery = async () => {
    const photo = await Camera.getPhoto({
      quality: 90,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      source: CameraSource.Photos,
    });
 
    return photo.webPath;
  };
 
  return { takePhoto, pickFromGallery };
}

Utilisez-le maintenant dans un composant src/components/PhotoCapture.tsx :

import { useState } from "react";
import { useCamera } from "../hooks/useCamera";
 
export function PhotoCapture() {
  const { takePhoto, pickFromGallery } = useCamera();
  const [photoUrl, setPhotoUrl] = useState<string | null>(null);
 
  const handleTakePhoto = async () => {
    try {
      const url = await takePhoto();
      if (url) setPhotoUrl(url);
    } catch (error) {
      console.error("Erreur caméra :", error);
    }
  };
 
  const handlePickPhoto = async () => {
    try {
      const url = await pickFromGallery();
      if (url) setPhotoUrl(url);
    } catch (error) {
      console.error("Erreur galerie :", error);
    }
  };
 
  return (
    <div className="photo-capture">
      <h2>Capture Photo</h2>
      <div className="buttons">
        <button onClick={handleTakePhoto}>Prendre une photo</button>
        <button onClick={handlePickPhoto}>Choisir depuis la galerie</button>
      </div>
      {photoUrl && (
        <div className="preview">
          <img src={photoUrl} alt="Photo capturée" />
        </div>
      )}
    </div>
  );
}

Permissions iOS

Pour iOS, vous devez ajouter des descriptions de permissions. Ouvrez ios/App/App/Info.plist et ajoutez :

<key>NSCameraUsageDescription</key>
<string>Cette app a besoin d'accéder à la caméra pour prendre des photos</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Cette app a besoin d'accéder à la photothèque pour sélectionner des images</string>

Permissions Android

Pour Android, Capacitor gère les permissions automatiquement, mais vérifiez dans android/app/src/main/AndroidManifest.xml :

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Recompilez et synchronisez :

npm run build
npx cap sync
npx cap run ios

Étape 6 : Stockage local avec Preferences

Le plugin Preferences de Capacitor fournit un stockage clé-valeur qui persiste entre les lancements de l'app — l'équivalent mobile du localStorage mais plus fiable.

npm install @capacitor/preferences
npx cap sync

Créez un utilitaire de stockage src/lib/storage.ts :

import { Preferences } from "@capacitor/preferences";
 
export const storage = {
  async get<T>(key: string): Promise<T | null> {
    const { value } = await Preferences.get({ key });
    if (!value) return null;
    return JSON.parse(value) as T;
  },
 
  async set(key: string, value: unknown): Promise<void> {
    await Preferences.set({
      key,
      value: JSON.stringify(value),
    });
  },
 
  async remove(key: string): Promise<void> {
    await Preferences.remove({ key });
  },
 
  async clear(): Promise<void> {
    await Preferences.clear();
  },
};

Utilisez-le pour sauvegarder les photos :

import { storage } from "../lib/storage";
 
// Sauvegarder une URL de photo
await storage.set("lastPhoto", photoUrl);
 
// La récupérer plus tard
const lastPhoto = await storage.get<string>("lastPhoto");

Étape 7 : Retour haptique

Ajoutez un retour tactile aux appuis de boutons — une petite touche qui rend les apps plus natives :

npm install @capacitor/haptics
npx cap sync

Créez un utilitaire haptique src/lib/haptics.ts :

import { Haptics, ImpactStyle } from "@capacitor/haptics";
import { Capacitor } from "@capacitor/core";
 
export const haptics = {
  async impact(style: ImpactStyle = ImpactStyle.Medium) {
    if (Capacitor.isNativePlatform()) {
      await Haptics.impact({ style });
    }
  },
 
  async notification(type: "success" | "warning" | "error") {
    if (Capacitor.isNativePlatform()) {
      await Haptics.notification({ type: type as any });
    }
  },
 
  async vibrate() {
    if (Capacitor.isNativePlatform()) {
      await Haptics.vibrate();
    }
  },
};

Remarquez la vérification Capacitor.isNativePlatform() — elle assure que les vibrations ne se déclenchent que sur de vrais appareils, pas dans le navigateur. Utilisez-le dans votre bouton photo :

import { haptics } from "../lib/haptics";
import { ImpactStyle } from "@capacitor/haptics";
 
const handleTakePhoto = async () => {
  await haptics.impact(ImpactStyle.Light);
  const url = await takePhoto();
  if (url) setPhotoUrl(url);
};

Étape 8 : Détection de plateforme et UI adaptative

Votre app fonctionne sur le web, iOS et Android. Parfois vous avez besoin d'un comportement spécifique à la plateforme :

import { Capacitor } from "@capacitor/core";
 
export function getPlatformInfo() {
  return {
    platform: Capacitor.getPlatform(), // 'web' | 'ios' | 'android'
    isNative: Capacitor.isNativePlatform(),
    isIOS: Capacitor.getPlatform() === "ios",
    isAndroid: Capacitor.getPlatform() === "android",
    isWeb: Capacitor.getPlatform() === "web",
  };
}

Utilisez cela pour du styling adaptatif :

import { getPlatformInfo } from "../lib/platform";
 
function AppHeader() {
  const { isIOS } = getPlatformInfo();
 
  return (
    <header
      style={{
        paddingTop: isIOS ? "env(safe-area-inset-top)" : "0",
      }}
    >
      <h1>Mon App</h1>
    </header>
  );
}

Zones de sécurité (Safe Areas)

Les appareils iOS avec encoche nécessitent une gestion des zones de sécurité. Ajoutez ce CSS :

:root {
  --sat: env(safe-area-inset-top);
  --sab: env(safe-area-inset-bottom);
  --sal: env(safe-area-inset-left);
  --sar: env(safe-area-inset-right);
}
 
body {
  padding-top: var(--sat);
  padding-bottom: var(--sab);
  padding-left: var(--sal);
  padding-right: var(--sar);
}

Dans capacitor.config.ts, activez le recouvrement de la barre de statut :

const config: CapacitorConfig = {
  // ...
  ios: {
    contentInset: "automatic",
  },
};

Étape 9 : Notifications push

Ajoutez les notifications push avec le plugin Push Notifications de Capacitor :

npm install @capacitor/push-notifications
npx cap sync

Créez un service de notifications src/lib/notifications.ts :

import { PushNotifications } from "@capacitor/push-notifications";
import { Capacitor } from "@capacitor/core";
 
export async function initPushNotifications() {
  if (!Capacitor.isNativePlatform()) {
    console.log("Notifications push non disponibles sur le web");
    return;
  }
 
  // Demander la permission
  const permStatus = await PushNotifications.requestPermissions();
  if (permStatus.receive !== "granted") {
    console.warn("Permission push non accordée");
    return;
  }
 
  // S'enregistrer auprès d'Apple/Google
  await PushNotifications.register();
 
  // Écouter le token d'enregistrement
  PushNotifications.addListener("registration", (token) => {
    console.log("Token push :", token.value);
    // Envoyer ce token à votre backend
  });
 
  // Écouter les notifications entrantes
  PushNotifications.addListener(
    "pushNotificationReceived",
    (notification) => {
      console.log("Push reçue :", notification);
    }
  );
 
  // Écouter les taps sur les notifications
  PushNotifications.addListener(
    "pushNotificationActionPerformed",
    (action) => {
      console.log("Action push :", action);
      // Naviguer vers l'écran approprié
    }
  );
}

Appelez-le depuis votre App.tsx :

import { useEffect } from "react";
import { initPushNotifications } from "./lib/notifications";
 
function App() {
  useEffect(() => {
    initPushNotifications();
  }, []);
 
  return <>{/* votre app */}</>;
}

Étape 10 : Icônes et écran de démarrage

Générer les icônes

Utilisez le package @capacitor/assets pour générer toutes les tailles requises à partir d'une seule image source :

npm install -D @capacitor/assets

Placez vos images sources :

  • assets/icon-only.png — icône 1024x1024 (sans arrière-plan)
  • assets/icon-background.png — arrière-plan 1024x1024
  • assets/splash.png — écran de démarrage 2732x2732

Générez toutes les icônes pour les plateformes :

npx capacitor-assets generate

Cela crée toutes les tailles requises pour iOS et Android dans les projets natifs.

Configuration de l'écran de démarrage

Installez le plugin splash screen :

npm install @capacitor/splash-screen
npx cap sync

Configurez dans capacitor.config.ts :

const config: CapacitorConfig = {
  // ...
  plugins: {
    SplashScreen: {
      launchShowDuration: 2000,
      backgroundColor: "#1a1a2e",
      showSpinner: false,
      androidScaleType: "CENTER_CROP",
      splashFullScreen: true,
      splashImmersive: true,
    },
  },
};

Fermez-le programmatiquement dans votre app :

import { SplashScreen } from "@capacitor/splash-screen";
 
// Quand votre app est prête
await SplashScreen.hide();

Étape 11 : Rechargement à chaud pendant le développement

Taper npm run build && npx cap sync à chaque modification est lent. Activez le rechargement à chaud pour accélérer le développement :

Mettez à jour capacitor.config.ts pour le développement :

import type { CapacitorConfig } from "@capacitor/cli";
 
const config: CapacitorConfig = {
  appId: "com.example.mymobileapp",
  appName: "My Mobile App",
  webDir: "dist",
  server: {
    // Activer le rechargement à chaud en développement
    url: "http://VOTRE_IP_LOCALE:5173",
    cleartext: true,
  },
};
 
export default config;

Trouvez votre IP locale :

# macOS
ipconfig getifaddr en0

Maintenant lancez Vite et exécutez sur l'appareil :

npm run dev
npx cap run ios --livereload --external

Pensez à supprimer server.url avant de compiler pour la production ! Vous ne voulez pas que votre app publiée pointe vers un serveur de développement.


Étape 12 : Compiler pour la production

iOS

  1. Ouvrez dans Xcode : npx cap open ios
  2. Sélectionnez Product puis Archive
  3. Dans l'Organizer, cliquez sur Distribute App
  4. Suivez le flux de signature et d'upload vers App Store Connect

Android

Générez un APK ou AAB signé :

cd android
./gradlew bundleRelease

Le fichier AAB sera dans android/app/build/outputs/bundle/release/app-release.aab.

Signez-le avec votre keystore :

jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
  -keystore my-release-key.jks \
  app-release.aab alias_name

Uploadez le AAB sur la Google Play Console.


Exemple complet

Voici un App.tsx complet qui rassemble le tout :

import { useEffect, useState } from "react";
import { SplashScreen } from "@capacitor/splash-screen";
import { PhotoCapture } from "./components/PhotoCapture";
import { storage } from "./lib/storage";
import { initPushNotifications } from "./lib/notifications";
import { getPlatformInfo } from "./lib/platform";
import "./App.css";
 
function App() {
  const [platform, setPlatform] = useState("");
  const [savedPhotos, setSavedPhotos] = useState<string[]>([]);
 
  useEffect(() => {
    const init = async () => {
      const info = getPlatformInfo();
      setPlatform(info.platform);
 
      // Charger les photos sauvegardées
      const photos = await storage.get<string[]>("photos");
      if (photos) setSavedPhotos(photos);
 
      // Initialiser les notifications push
      await initPushNotifications();
 
      // Masquer l'écran de démarrage
      await SplashScreen.hide();
    };
 
    init();
  }, []);
 
  return (
    <div className="app">
      <header className="app-header">
        <h1>Mon App Mobile</h1>
        <span className="platform-badge">{platform}</span>
      </header>
 
      <main>
        <PhotoCapture />
 
        {savedPhotos.length > 0 && (
          <section className="gallery">
            <h2>Photos sauvegardées</h2>
            <div className="photo-grid">
              {savedPhotos.map((url, i) => (
                <img key={i} src={url} alt={`Photo ${i + 1}`} />
              ))}
            </div>
          </section>
        )}
      </main>
    </div>
  );
}
 
export default App;

Dépannage

Erreur "Unable to determine the current platform"

Assurez-vous d'avoir exécuté npx cap sync après l'installation de nouveaux plugins.

Échec du build iOS avec des erreurs de signature

Ouvrez Xcode, allez dans Signing & Capabilities, et sélectionnez votre équipe de développement. Avec un compte Apple Developer gratuit, vous pouvez tester sur un appareil physique mais pas publier.

L'émulateur Android est lent

Activez l'accélération matérielle (HAXM sur Intel, Hypervisor sur Apple Silicon). Utilisez une image système x86_64 pour de meilleures performances.

La caméra ne fonctionne pas dans le navigateur

Certains plugins Capacitor fonctionnent en mode dégradé sur le web, d'autres non. Le plugin Camera ouvre un sélecteur de fichiers sur le web en remplacement.

Le rechargement à chaud ne se connecte pas sur l'appareil

Assurez-vous que votre appareil et votre machine de développement sont sur le même réseau Wi-Fi, et vérifiez les paramètres du pare-feu.


Prochaines étapes

  • Explorez le registre de plugins Capacitor pour plus de fonctionnalités natives
  • Ajoutez l'authentification biométrique avec @capacitor/biometrics
  • Intégrez les liens profonds avec @capacitor/app pour la navigation par URL
  • Mettez en place le CI/CD avec Appflow ou GitHub Actions pour les builds automatisés
  • Envisagez d'ajouter Ionic Framework par-dessus pour des composants UI mobiles préconstruits

Conclusion

Capacitor vous permet d'exploiter vos compétences React et web pour créer de vraies applications mobiles natives — sans apprendre Swift ou Kotlin. Vous gardez vos outils familiers (Vite, TypeScript, CSS), vous accédez aux API natives via un système de plugins propre, et vous pouvez même livrer le même code en PWA.

L'approche est pragmatique : pour les apps principalement orientées contenu, formulaires ou CRUD, Capacitor offre des résultats de qualité native avec une fraction de l'effort d'un développement entièrement natif. Pour les jeux intensifs en GPU ou les apps nécessitant une intégration plateforme profonde, le développement natif ou React Native pourrait être plus adapté.

Commencez avec votre app React existante, ajoutez Capacitor, et publiez sur les deux stores — le tout depuis une seule base de code.


Vous voulez lire plus de tutoriels? Découvrez notre dernier tutoriel sur Révolutionner l'engagement client : Les agents virtuels alimentés par l'IA de Twilio.

Discutez de votre projet avec nous

Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.

Trouvons les meilleures solutions pour vos besoins.

Articles connexes