Chapitre 9.1 — Le catalogue expo-* : le mode d’emploi
Où on en est : Drill maîtrise l’écran, les données, la base. Pour toucher au matériel (notifs, vibreur, capteurs), il faut le rituel des modules natifs — le même pour les ~80 modules du SDK.
⏱️ TL;DR — Chaque module expo-* = 4 étapes : installer (
npx expo install), permissions (déclaratives dans app.json + demande à l’exécution), config plugin (si le module modifie le projet natif), utiliser. Les permissions Android se demandent AU MOMENT du besoin, avec un fallback gracieux si refusées. Certains modules exigent un development build — repérer la mention dans la doc AVANT de coder.
🎯 Objectifs
- Dérouler le rituel install → permission → config → usage sur n’importe quel module.
- Comprendre les deux étages de permissions Android (manifeste + runtime).
- Savoir lire une page de doc Expo (les 4 sections qui comptent).
- Reconnaître un module « Expo Go OK » d’un module « dev build requis ».
Lire une page de doc Expo
Ouvrez docs.expo.dev/versions/latest/sdk/haptics — l’anatomie type :
- Le bandeau de compatibilité : plateformes (Android/iOS/web) et — crucial — si ça marche dans Expo Go ou s’il faut un development build. Réflexe n°1 : vérifier AVANT de coder.
- Installation : toujours
npx expo install expo-<module>(la version alignée SDK, chapitre 1.4). - Configuration : le config plugin éventuel (à ajouter dans
pluginsd’app.json) et les permissions requises. - API : les fonctions, avec les patterns de permission.
Les permissions Android : deux étages
Étage 1 — le manifeste (déclaratif) : Android exige que l’app déclare ses permissions dans
AndroidManifest.xml. Vous n’y touchez jamais : les config plugins des modules le font au
prebuild, et app.json permet d’affiner :
// app.json — l'exemple type (les notifications, chapitre suivant)
{
"expo": {
"plugins": [
["expo-notifications", { "icon": "./assets/images/notification-icon.png", "color": "#087ea4" }]
],
"android": {
"permissions": [] // pour AJOUTER des permissions rares — la plupart viennent des plugins
}
}
}Étage 2 — le runtime (interactif) : depuis Android 6, les permissions sensibles se demandent à l’exécution, via une boîte système. Le pattern universel :
import * as Notifications from 'expo-notifications'
async function ensureNotificationPermission(): Promise<boolean> {
const current = await Notifications.getPermissionsAsync()
if (current.granted) return true
if (!current.canAskAgain) return false // refus définitif : ne PAS re-demander
const asked = await Notifications.requestPermissionsAsync()
return asked.granted
}Trois états à gérer, toujours : accordée, refusée mais redemandable, refusée
définitivement (canAskAgain: false → la seule issue est les Paramètres système —
Linking.openSettings() pour y emmener l’utilisateur, sans le harceler).
L’art de demander
Les règles UX qui font la différence entre une app polie et une app effrayante :
- Demander au moment du besoin, jamais au premier lancement : l’utilisateur qui active « Rappel quotidien » dans les Réglages comprend POURQUOI la boîte de permission apparaît. Le même dialogue à l’ouverture de l’app = refus quasi garanti.
- Pré-expliquer si l’enjeu est fort : un petit écran « Drill aimerait te rappeler ton
défi quotidien » AVANT la boîte système double les taux d’acceptation (et préserve le
canAskAgain). - Fallback gracieux : permission refusée ≠ feature cassée. Pas de notifs → le Switch des Réglages reste off avec un lien « Autoriser dans les paramètres ». L’app fonctionne.
⚠️ Piège — Tester les permissions demande de la méthode : une fois accordée/refusée, la boîte ne réapparaît plus. Pour re-tester le flux complet :
adb shell pm clear com.alex.drill(remise à zéro totale) ou révoquer dans Paramètres → Applications → Drill → Autorisations. Testez TOUJOURS le chemin « refusé » — c’est celui que vos utilisateurs les plus méfiants prendront.
💡 Pour un dev Next.js — Le web a ses permissions (géoloc, notifs) mais le navigateur gère la boîte et le blocage. Ici VOUS orchestrez le flux entier — en échange, l’éventail est immense : vibreur, capteurs, Bluetooth, arrière-plan… Le catalogue expo-* est votre nouvelle stdlib ; la compétence de ce chapitre (le rituel) est la clé de toutes ses portes.
✏️ Exercices
1. Sur trois modules que Drill utilisera (expo-notifications, expo-haptics, expo-audio), vérifiez dans la doc : Expo Go OK ? Config plugin ? Permission runtime ? Faites le tableau.
✅ Solution
| Module | Expo Go | Config plugin | Permission runtime |
|---|---|---|---|
| expo-haptics | ✅ | non | aucune (le vibreur « court » est libre) |
| expo-audio | ✅ | optionnel (micro) | aucune en lecture |
| expo-notifications | ⚠️ locales OK, push NON | oui (icône/couleur) | oui (Android 13+) |
Leçon : même famille, exigences très différentes — d’où le réflexe bandeau de compatibilité.
2. Écrivez le helper générique ensurePermission réutilisable (get + canAskAgain + request)
paramétré par les fonctions du module, puis dérivez ensureNotificationPermission.
✅ Solution
// lib/permissions.ts
type PermissionAPI = {
get: () => Promise<{ granted: boolean; canAskAgain: boolean }>
request: () => Promise<{ granted: boolean }>
}
export async function ensurePermission(api: PermissionAPI): Promise<'granted' | 'denied' | 'blocked'> {
const cur = await api.get()
if (cur.granted) return 'granted'
if (!cur.canAskAgain) return 'blocked'
const res = await api.request()
return res.granted ? 'granted' : 'denied'
}
export const ensureNotificationPermission = () =>
ensurePermission({
get: Notifications.getPermissionsAsync,
request: Notifications.requestPermissionsAsync,
})Le retour à 3 états (‘blocked’ ≠ ‘denied’) force les appelants à gérer le cas openSettings.
3. Rédigez le micro-copy du pré-écran de permission pour le rappel quotidien de Drill (2 phrases max + 2 boutons). Qu’est-ce qui le rend efficace ?
✅ Solution
« Un défi par jour ? Drill peut te rappeler chaque soir de jouer ta session — une seule notification, jamais plus. » [Activer le rappel] [Plus tard]. Efficace : bénéfice concret (le défi), engagement borné (« une seule, jamais plus » — la peur n°1 est le spam), et le refus est indolore (« Plus tard » ne brûle pas le canAskAgain système puisque la vraie boîte n’apparaît qu’après le OUI).
🧠 Quiz
1. Quelles sont les 4 étapes du rituel d’un module expo-* ?
Réponse
Installer (npx expo install), permissions (manifeste via plugin + runtime), config plugin si
le module touche au natif, utiliser l’API. Plus le réflexe zéro : vérifier la compatibilité
Expo Go dans la doc.
2. Qui remplit AndroidManifest.xml dans un projet Expo ?
Réponse
Les config plugins des modules, au prebuild (CNG) — complétés au besoin par
android.permissions d’app.json. Jamais d’édition manuelle.
3. Que signifie canAskAgain: false ?
Réponse
Refus définitif : la boîte système ne peut plus être montrée. Seule issue : les paramètres
système (Linking.openSettings()) — proposé sans harcèlement.
4. Quand demander une permission ?
Réponse
Au moment du besoin, déclenchée par une action utilisateur qui l’explique (activer le rappel → boîte notifications) — jamais en rafale au premier lancement.
5. Comment re-tester un flux de permission déjà répondu ?
Réponse
adb shell pm clear <package> (reset complet) ou révocation manuelle dans Paramètres →
Applications → Autorisations. Et toujours tester le chemin « refusé ».
👉 Chapitre suivant : 9.2 — Notifications locales — le défi quotidien, de la permission au deep link.