Application mobile
Une app iOS + Android Ă partir de ton backend Next.js existant, avec React Native + Expo. Ce n'est pas un projet Ă part â c'est une couche en plus sur ce que tu as dĂ©jĂ .
PrĂ©requis important : ce guide part du principe que tu as dĂ©jĂ un projet Next.js avec Prisma/Supabase et Better Auth en place (voir les autres guides). L'app mobile ne recrĂ©e pas de backend â elle appelle celui qui existe dĂ©jĂ .
Réutilisable vs spécifique : les étapes réutilisable sont valables pour n'importe quelle app mobile de ta stack. Les étapes spécifique dépendent du produit que tu construis.
Initialiser le projet Expo
Une app qui démarre sur ton téléphone via Expo Go, dans un dossier séparé du projet web.
Prérequis : Node.js et pnpm installés. L'app Expo Go installée sur ton téléphone (App Store / Play Store).
-
Crée le projet Expo, à cÎté de ton projet web
npx create-expo-app@latest mon-app-mobile --template default cd mon-app-mobile
C'est un dĂ©pĂŽt sĂ©parĂ© du projet Next.js â le mobile et le web restent deux applications distinctes qui parlent Ă la mĂȘme base de donnĂ©es via l'API.đ Comment voir le rĂ©sultat : tapelsdansmon-app-mobileâapp/,package.jsondoivent exister. -
Initialise Git
git init git add -A git commit -m "chore: init projet Expo"
đ Comment voir le rĂ©sultat : tapegit log --onelineâ une ligne avec ton message de commit doit s'afficher. -
Lance le serveur de développement
npx expo start
Un QR code s'affiche dans le terminal. Scanne-le avec l'appareil photo (iOS) ou l'app Expo Go (Android) pour ouvrir l'app sur ton tĂ©lĂ©phone, en direct.đ Comment voir le rĂ©sultat : l'app s'ouvre sur ton tĂ©lĂ©phone avec l'Ă©cran par dĂ©faut d'Expo. Modifie un texte dansapp/index.tsx, enregistre â le changement doit apparaĂźtre sur le tĂ©lĂ©phone en 1-2 secondes, sans rĂ©installer l'app (hot reload).
Exposer le backend en API
Ton app mobile peut appeler ton backend Next.js par HTTP, comme n'importe quel client.
Prérequis : le projet Next.js existe déjà (Prisma + Supabase branché).
-
Comprends la diffĂ©rence clĂ©Les Server Actions (utilisĂ©es dans le web) ne sont appelables que depuis une page Next.js du mĂȘme projet â pas depuis une app mobile. Il faut donc des Route Handlers classiques : des vraies routes API avec une URL, comme une API REST.
-
Dans ton projet Next.js (pas le projet Expo), crée le dossier et le fichier de la route
mkdir -p app/api/produits && touch app/api/produits/route.tsNew-Item -ItemType Directory -Force -Path app/api/produits; New-Item -ItemType File -Force -Path app/api/produits/route.ts
-
Colle le contenu de la route API
// app/api/produits/route.ts import { prisma } from "@/lib/db/client"; export async function GET() { const produits = await prisma.produit.findMany(); return Response.json(produits); }Chaque donnĂ©e dont l'app mobile a besoin doit avoir sa route sousapp/api/.... C'est le mĂȘme Prisma, la mĂȘme base â juste exposĂ©e diffĂ©remment. -
Autorise les requĂȘtes venant de l'app mobile (CORS)Par dĂ©faut, Next.js n'accepte que les requĂȘtes venant de son propre domaine. Ajoute les en-tĂȘtes CORS nĂ©cessaires dans la route, ou un middleware, pour autoriser ton app mobile Ă appeler l'API en dĂ©veloppement comme en production.
-
Teste la route depuis un navigateur ou
curlcurl http://localhost:3000/api/produitsInvoke-RestMethod http://localhost:3000/api/produits
đ Comment voir le rĂ©sultat : le terminal doit afficher du JSON (ex.[{"id":"...","nom":"..."}]), pas une page d'erreur HTML. Teste ensuite depuis l'app mobile (sur le mĂȘme Wi-Fi que ton ordinateur, avec l'IP locale au lieu delocalhost) pour confirmer que la requĂȘte aboutit aussi depuis le tĂ©lĂ©phone.
Authentification mobile â Better Auth
Se connecter depuis le téléphone, avec la session gérée en toute sécurité.
Prérequis : Better Auth déjà configuré cÎté serveur Next.js.
-
Installe le client Better Auth pour Expo
npx expo install @better-auth/expo expo-secure-store
Better Auth fournit un client pensĂ© pour React Native â il gĂšre les appels rĂ©seau vers ton serveur d'auth existant.đ Comment voir le rĂ©sultat :@better-auth/expoapparaĂźt danspackage.json. -
Crée le fichier du client auth
touch lib/auth-client.tsNew-Item -ItemType File -Force -Path lib/auth-client.ts
// lib/auth-client.ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import * as SecureStore from "expo-secure-store"; export const authClient = createAuthClient({ baseURL: "http://TON-IP-LOCALE:3000", plugins: [ expoClient({ scheme: "monappmobile", storagePrefix: "monappmobile", storage: SecureStore, }), ], });Contrairement au web (cookies), le mobile stocke le token dansexpo-secure-storeâ un espace chiffrĂ© du tĂ©lĂ©phone, pas dans une simple variable ou un fichier en clair. RemplaceTON-IP-LOCALEpar l'IP locale de ton ordinateur (paslocalhost, qui sur un tĂ©lĂ©phone pointerait vers le tĂ©lĂ©phone lui-mĂȘme) ; en production tu pointeras vers ton URL Vercel (Ă©tape 6). -
Crée les fichiers des écrans connexion / inscription
touch app/login.tsx app/signup.tsxNew-Item -ItemType File -Force -Path app/login.tsx, app/signup.tsx
-
Colle le contenu de l'écran de connexion
// app/login.tsx import { useState } from "react"; import { View, TextInput, Button, Text } from "react-native"; import { router } from "expo-router"; import { authClient } from "@/lib/auth-client"; export default function LoginScreen() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); async function handleLogin() { const { error } = await authClient.signIn.email({ email, password }); if (error) return setError(error.message ?? "Connexion refusĂ©e"); router.replace("/"); } return ( <View className="flex-1 justify-center p-6 gap-3"> <TextInput placeholder="Email" value={email} onChangeText={setEmail} autoCapitalize="none" className="border p-3 rounded" /> <TextInput placeholder="Mot de passe" value={password} onChangeText={setPassword} secureTextEntry className="border p-3 rounded" /> {error ? <Text className="text-red-500">{error}</Text> : null} <Button title="Se connecter" onPress={handleLogin} /> </View> ); }Duplique la mĂȘme structure pourapp/signup.tsx(fonctionSignupScreen) en remplaçantauthClient.signIn.email(...)parauthClient.signUp.email({ email, password, name: email }).đ Comment voir le rĂ©sultat : sur ton tĂ©lĂ©phone, crĂ©e un compte test depuis l'Ă©cran d'inscription â puis vĂ©rifie dans Prisma Studio (cĂŽtĂ© projet web) qu'une ligne apparaĂźt dans la tableUser. Reconnecte-toi ensuite depuis l'Ă©cran de connexion avec les mĂȘmes identifiants. -
Colle le contenu du fichier
app/_layout.tsxpour protĂ©ger les Ă©crans// app/_layout.tsx import { Redirect, Slot } from "expo-router"; import { authClient } from "@/lib/auth-client"; export default function RootLayout() { const { data: session, isPending } = authClient.useSession(); if (isPending) return null; if (!session) return <Redirect href="/login" />; return <Slot />; }Ce fichier existe dĂ©jĂ (créé parcreate-expo-app) â remplace son contenu. Il s'applique Ă tous les Ă©crans : vĂ©rifie la session au lancement de l'app et redirige vers l'Ă©cran de connexion si elle est absente ou expirĂ©e.đ Comment voir le rĂ©sultat : ferme complĂštement l'app puis rouvre-la â tu dois rester connectĂ© (pas de retour Ă l'Ă©cran de connexion). DĂ©connecte-toi : tu dois ĂȘtre redirigĂ© vers l'Ă©cran de connexion, et rouvrir l'app ne doit plus te reconnecter automatiquement.
Style â NativeWind
Les mĂȘmes classes Tailwind que sur le web, appliquĂ©es Ă des composants React Native.
Prérequis : étape 1 validée.
-
Installe NativeWind
npx expo install nativewind tailwindcss
Tailwind CSS n'existe pas nativement en React Native (pas de navigateur, pas de vrai CSS) â NativeWind traduit les classes Tailwind en styles React Native au moment de la compilation. -
Configure Tailwind pour le projet mobile
npx tailwindcss init
Untailwind.config.jspropre au projet mobile â les fichiers scannĂ©s ne sont pas les mĂȘmes que cĂŽtĂ© web (App.tsx,app/**/*.tsxau lieu deapp/Next.js).đ Comment voir le rĂ©sultat :ls tailwind.config.jsâ le fichier doit exister. -
Utilise les classes directement dans les composants
// exemple <View className="flex-1 items-center justify-center bg-white"> <Text className="text-lg font-bold">Bonjour</Text> </View>đ Comment voir le rĂ©sultat : ouvreapp/index.tsx(l'Ă©cran d'accueil créé automatiquement Ă l'Ă©tape 1), remplace le JSX retournĂ© par cet exemple, enregistre â sur ton tĂ©lĂ©phone, le texte « Bonjour » doit s'afficher centrĂ©, en gras, sur fond blanc. Changebg-whiteenbg-red-500pour confirmer que les classes prennent bien effet. -
Déclare tes couleurs une seule fois, dans
tailwind.config.js// tailwind.config.js module.exports = { content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"], theme: { extend: { colors: { primary: "#2563eb", background: "#ffffff", }, }, }, };Sans ça, tu retapes le mĂȘme code couleur (#2563eb) dans chaque Ă©cran â si tu veux changer de teinte plus tard, tu dois le faire une seule fois ici, plutĂŽt que de chasser chaque occurrence dans tous les fichiers.đ Comment voir le rĂ©sultat : remplacebg-red-500parbg-primaryettext-lgreste, sauvegarde â le fond doit prendre la couleur bleue dĂ©clarĂ©e dansprimary. -
Pour modifier le style plus tardGarde
npx expo startlancĂ© en continu â c'est le rechargement Ă chaud (« Fast Refresh ») : tu ouvres l'Ă©cran concernĂ© (dansapp/), tu changes les classes dansclassName, tu sauvegardes, l'app se met Ă jour seule sur le tĂ©lĂ©phone sans recompiler. Pour changer une couleur partout d'un coup, retouchetailwind.config.jsplutĂŽt que chaque Ă©cran un par un. Pour savoir ce que fait une classe (p-4,rounded-lg,text-xl...), consulte le lexique ou tailwindcss.com/docs.
Ăcrans & fonctionnalitĂ©s
Le cĆur mĂ©tier de l'app â ce qui change Ă chaque projet.
Prérequis : étapes 2 et 3 validées.
-
Mets en place la navigation entre écrans
npx expo install expo-router
Expo Router fonctionne par dossiers, comme l'App Router de Next.js â un fichier = un Ă©cran. Le repĂšre est le mĂȘme que celui que tu connais dĂ©jĂ cĂŽtĂ© web.đ Comment voir le rĂ©sultat : crĂ©e un deuxiĂšme Ă©cran (ex.app/profil.tsx) et un lien vers lui â tape dessus sur ton tĂ©lĂ©phone, tu dois naviguer vers le nouvel Ă©cran avec l'animation de transition native. -
Crée le fichier d'un écran qui appelle ta route API
touch app/produits.tsxNew-Item -ItemType File -Force -Path app/produits.tsx
-
Colle le contenu de l'écran
// app/produits.tsx import { useEffect, useState } from "react"; import { View, Text, FlatList } from "react-native"; type Produit = { id: string; nom: string }; export default function ProduitsScreen() { const [produits, setProduits] = useState<Produit[]>([]); useEffect(() => { fetch("http://TON-IP-LOCALE:3000/api/produits") .then((r) => r.json()) .then(setProduits); }, []); return ( <FlatList data={produits} keyExtractor={(p) => p.id} renderItem={({ item }) => ( <View className="p-4 border-b"> <Text>{item.nom}</Text> </View> )} /> ); }MĂȘme logique que cĂŽtĂ© web (rĂ©cupĂ©rer des donnĂ©es, les afficher, les valider avec Zod avant envoi cĂŽtĂ© formulaire) â seuls les composants d'affichage changent. En production, remplace l'URL par ton domaine Vercel (Ă©tape 6).đ Comment voir le rĂ©sultat : ouvre l'Ă©cranproduitssur ton tĂ©lĂ©phone â les vraies donnĂ©es de ta base (créées via Prisma Studio ou l'app web) doivent s'afficher, pas des donnĂ©es factices codĂ©es en dur. -
GĂšre les notifications push si le projet en a besoin
npx expo install expo-notifications
Uniquement si le produit en a l'usage (ex. prĂ©venir un utilisateur) â ne l'ajoute pas par dĂ©faut.
Build & publication â EAS
Une app installable, publiée sur l'App Store et le Play Store.
Prérequis : compte Expo (expo.dev), compte développeur Apple et Google si publication réelle visée.
-
Installe l'outil de build EAS
npm install -g eas-cli eas login
đ Comment voir le rĂ©sultat : tapeeas whoamiâ ton nom de compte Expo doit s'afficher. -
Configure le projet pour le build
eas build:configure
đ Comment voir le rĂ©sultat : un fichiereas.jsonapparaĂźt Ă la racine du projet. -
Renseigne les variables d'environnement de prod
eas secret:create --name API_URL --value https://tondomaine.vercel.app
L'app mobile en production doit appeler ton backend Next.js dĂ©ployĂ©, paslocalhost.đ Comment voir le rĂ©sultat :eas secret:listdoit afficherAPI_URLdans la liste. -
Lance un build de test
eas build --platform android --profile preview
Un build « preview » s'installe directement sur un tĂ©lĂ©phone pour tester, sans passer par les stores â plus rapide qu'un cycle de validation complet.đ Comment voir le rĂ©sultat : une fois le build terminĂ© (~10-20 min, suivi sur expo.dev), un lien de tĂ©lĂ©chargement.apks'affiche dans le terminal â installe-le sur un tĂ©lĂ©phone Android, l'app doit se lancer et appeler ton API de production. -
Soumets aux stores quand tu es prĂȘt
eas build --platform all --profile production eas submit --platform all
La validation Apple prend en gĂ©nĂ©ral quelques jours ; celle de Google est plus rapide. PrĂ©vois cette marge avant une date de lancement.đ Comment voir le rĂ©sultat : le statut de la soumission est visible sur App Store Connect et Google Play Console â il passe de « En cours d'examen » à « ApprouvĂ© » (ou un refus avec le motif, Ă corriger).