Chapitre 11.4 — Prebuild & CNG : android/ ouvert, puis refermé
Où on en est : les builds passent, les plugins écrivent le natif. Dernière étape de la partie : regarder UNE fois ce que prebuild génère — pour ne plus jamais avoir peur du dossier android/, ni la tentation d’y toucher.
⏱️ TL;DR —
npx expo prebuildgénèreandroid/depuis app.config.ts + les plugins : un projet gradle standard (manifest, res/, build.gradle). Le contrat CNG : ce dossier est un artefact jetable — dans le .gitignore, régénérable (--clean), jamais édité à la main (toute modif manuelle = perdue au prochain prebuild ou, pire, en conflit silencieux). Le workflow : config → prebuild → gradle, toujours dans ce sens.
🎯 Objectifs
- Générer et LIRE le dossier android/ (la visite guidée, sans peur).
- Intérioriser le contrat CNG : pourquoi on ne touche jamais au généré.
- Savoir gérer les exceptions (le jour où un besoin sort des plugins).
- Maîtriser prebuild —clean et sa place dans le workflow.
La visite guidée
npx expo prebuild --platform androidLe résultat, avec les correspondances :
android/
├── app/
│ ├── build.gradle ← versionCode, package (depuis app.config.ts)
│ ├── src/main/
│ │ ├── AndroidManifest.xml ← permissions, scheme, intent-filters (les plugins !)
│ │ ├── java/com/alex/drill/ ← MainActivity/MainApplication (générés, minces)
│ │ └── res/ ← icônes (mipmap-*), splash, notification-icon, strings.xml
├── build.gradle ← versions Android/gradle globales
├── gradle.properties ← flags (new arch, hermes…)
└── settings.gradle ← inclut les modules natifs autolinésOuvrez AndroidManifest.xml (exercice du chapitre précédent) : chaque ligne remonte à votre
config. Ouvrez res/mipmap-* : vos icônes, déclinées par densité. Ce projet est un projet
Android parfaitement standard — Android Studio sait l’ouvrir, gradle sait le compiler.
Il n’a qu’une particularité : il n’est pas à vous.
Le contrat CNG
Continuous Native Generation — le nom dit tout : le natif est généré en continu, comme un lockfile ou un dossier .next :
android/est dans le .gitignore (posé dès le ch. 2.5) — il ne se commit pas.- Toute vérité vit dans app.config.ts + plugins — la source, versionnée, revuable.
- On régénère au doute :
npx expo prebuild --clean(supprime et refait). Les montées de SDK, changements de plugins, bizarreries de build : —clean d’abord. - On n’édite JAMAIS le généré. Une modif manuelle dans android/ fonctionne… jusqu’au prochain prebuild —clean, qui l’efface sans un mot. Le bug différé le plus vicieux du monde Expo.
Et le jour où les plugins ne suffisent pas ?
L’ordre d’escalade, du plus propre au dernier recours :
- Un plugin existe déjà — cherchez (le besoin est rarement inédit) : la lib elle-même,
ou le recueil communautaire
@config-plugins/*. - Écrire son mini-plugin (ch. 11.3) — withAndroidManifest & co couvrent l’immense majorité des cas (une permission, un meta-data, une propriété gradle).
- Le bare workflow — commiter android/ et le maintenir à la main. C’est un aller (presque) simple : on perd prebuild, les montées de SDK assistées, la CNG. Réservé aux apps à natif TRÈS custom — hors périmètre de ce cours, et de 99 % des apps.
La bonne nouvelle statistique : Drill, avec ses notifications, SQLite, animations, gestes, deep links… n’a eu besoin de zéro ligne de natif manuel. C’est représentatif de l’app 2026 typique.
La place de prebuild dans le workflow
En pratique quotidienne, vous ne lancez presque jamais prebuild vous-même :
expo run:android le fait si besoin, EAS Build le fait toujours (serveurs : —clean par
nature). Les moments où la commande explicite sert :
- Inspecter ce qu’un plugin génère (la visite de ce chapitre, le debug d’un plugin maison).
--cleanaprès un changement de config important ou une montée de SDK, avant un run:android, pour repartir d’un natif sûr.- Vérifier en CI que le prebuild passe (la config est valide).
⚠️ Piège — Le symptôme du contrat violé : « ça marchait, j’ai mis à jour le SDK / lancé —clean, et ma [modif manuelle oubliée] a disparu ». Personne n’est immunisé — la parade est mécanique : si vous DEVEZ toucher au natif pour tester une hypothèse, faites-le, validez l’hypothèse… puis transcrivez immédiatement en plugin et —clean pour vérifier que la régénération reproduit votre fix. Le natif manuel est un brouillon, jamais un livrable.
💡 Pour un dev Next.js — android/ est votre
.next/: généré, ignoré par git, jetable — et pourtant c’est LUI qui tourne. Vous ne patchez pas .next/ à la main ; même réflexe ici. La différence : .next/ se régénère à chaque build, android/ seulement quand on le demande — d’où la discipline —clean au doute.
✏️ Exercices
1. Le test du contrat : ajoutez à la main une permission bidon dans AndroidManifest.xml
généré, vérifiez qu’elle survit à un expo run:android… puis lancez prebuild --clean et
constatez. Transcrivez ensuite la leçon en une phrase dans le README.
✅ Solution
run:android ne régénère pas forcément (le dossier existe) → la modif survit et DONNE CONFIANCE — c’est le piège. —clean : disparue. Phrase pour le README : « android/ est généré : toute vérité native va dans app.config.ts ou un plugin, jamais dans android/ — un —clean efface tout le reste. »
2. Comparez le manifest des deux variantes : prebuild en APP_VARIANT=development puis en prod, diffez les AndroidManifest.xml. Combien de lignes diffèrent, et lesquelles ?
✅ Solution
$env:APP_VARIANT='development'; npx expo prebuild --clean → copier le manifest →
variante prod → git diff --no-index (ou Compare-Object). Attendu : le package name, le
label (Drill Dev), le scheme (drill-dev) — 3-4 lignes. La démonstration que les variantes du
ch. 11.3 sont bien de la GÉNÉRATION, pas de la duplication de projets.
3. Votre future app a besoin d’un <meta-data> Google Maps dans le manifest (clé d’API
publique). Écrivez le chemin complet SANS toucher android/ : quel plugin, quel code, quelle
vérification.
✅ Solution
Chemin 1 (le vrai) : la lib react-native-maps a un config plugin officiel — plugins: [['react-native-maps', { androidApiKey: … }]] — toujours vérifier d’abord. Chemin 2
(pédagogique) : plugin maison withAndroidManifest qui pousse
{ $: { 'android:name': 'com.google.android.geo.API_KEY', 'android:value': key } } dans
application.meta-data. Vérification : prebuild → lire le manifest généré → la ligne y est →
—clean → elle y est ENCORE (reproductible). C’est le cycle de dev d’un plugin.
🧠 Quiz
1. Que génère npx expo prebuild, à partir de quoi ?
Réponse
Le projet natif android/ (manifest, gradle, res/, MainActivity) à partir d’app.config.ts + les config plugins des dépendances — un projet gradle standard, mais généré.
2. Récitez les 4 clauses du contrat CNG.
Réponse
android/ dans le .gitignore ; la vérité dans config+plugins ; régénérer au doute (—clean) ; ne jamais éditer le généré (toute modif manuelle est condamnée).
3. Pourquoi une modif manuelle dans android/ est-elle un bug différé ?
Réponse
Elle survit tant que personne ne régénère… puis un —clean (montée de SDK, EAS, collègue) l’efface silencieusement — le fix disparaît longtemps après avoir été oublié.
4. Quel est l’ordre d’escalade quand les plugins existants ne couvrent pas un besoin natif ?
Réponse
Chercher un plugin existant (lib ou @config-plugins/*) → écrire un mini-plugin (withAndroidManifest & co) → en tout dernier recours le bare workflow (commiter le natif — on perd la CNG).
5. Quand lance-t-on prebuild explicitement ?
Réponse
Pour inspecter le généré, avec —clean après un changement de config/SDK, ou en CI pour valider la config — le quotidien passe par run:android et EAS qui le font tout seuls.
👉 Partie suivante : Partie 12 — Builds & distribution perso — l’APK de production sur TON téléphone, et les mises à jour OTA sans réinstaller. La partie que tu attendais.