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

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éristique | Capacitor | React Native | Cordova |
|---|---|---|---|
| Rendu UI | WebView (votre HTML/CSS) | Vues natives | WebView |
| Système de plugins | Moderne, TypeScript-first | Modules bridge | Legacy XML |
| Support PWA | Intégré | Aucun | Limité |
| Écosystème | En croissance, soutenu par Ionic | Massif | En déclin |
| Courbe d'apprentissage | Faible (si vous connaissez le web) | Moyenne-Élevée | Faible |
É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 installVérifiez que tout fonctionne :
npm run devOuvrez 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/cliInitialisez Capacitor :
npx cap initOn 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 androidCela 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 syncExé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 iosCela 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 iosAndroid
npx cap open androidCela ouvre le projet dans Android Studio. Sélectionnez un émulateur et cliquez sur Run, ou :
npx cap run androidVous 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 syncCré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 syncCré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 syncCré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 syncCré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/assetsPlacez vos images sources :
assets/icon-only.png— icône 1024x1024 (sans arrière-plan)assets/icon-background.png— arrière-plan 1024x1024assets/splash.png— écran de démarrage 2732x2732
Générez toutes les icônes pour les plateformes :
npx capacitor-assets generateCela 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 syncConfigurez 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 en0Maintenant lancez Vite et exécutez sur l'appareil :
npm run dev
npx cap run ios --livereload --externalPensez à 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
- Ouvrez dans Xcode :
npx cap open ios - Sélectionnez Product puis Archive
- Dans l'Organizer, cliquez sur Distribute App
- Suivez le flux de signature et d'upload vers App Store Connect
Android
Générez un APK ou AAB signé :
cd android
./gradlew bundleReleaseLe 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_nameUploadez 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/apppour 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.
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

Construire une Application Mobile Multiplateforme avec Expo, React Native et TypeScript en 2026
Apprenez à construire une application mobile prête pour la production avec Expo SDK 52, React Native et TypeScript. Ce tutoriel couvre le routage basé sur les fichiers, les API natives, la gestion d'état et le déploiement sur l'App Store et Google Play.

Construire des applications collaboratives Local-First avec Yjs et React
Apprenez à construire des applications collaboratives en temps réel fonctionnant hors ligne avec les CRDTs Yjs et React. Ce tutoriel couvre la synchronisation sans conflits, l'architecture offline-first et la création d'un éditeur de documents partagé.

Authentifier votre application Next.js 15 avec Auth.js v5 : Email, OAuth et contrôle des rôles
Apprenez à ajouter une authentification prête pour la production à votre application Next.js 15 avec Auth.js v5. Ce guide complet couvre Google OAuth, les identifiants email/mot de passe, les routes protégées, le middleware et le contrôle d'accès basé sur les rôles.