# Tags NFC — déclencher le contenu depuis un tag > **Analysé dans le code le 2026-09-16.** Carte kanban : `cards/5-planifie/265-…` > ⚠️ **Document retourné trois fois** par les précisions de Thomas. Version arrêtée ci-dessous : > le tag ouvre **l'app mobile sur le bon contenu**, et la page de téléchargement web reste > le fallback quand l'app n'est pas installée. --- ## Le comportement retenu ``` tag NFC (NDEF : URL du QR) │ ├─ app installée → App Link / Universal Link → mymuseum-visitapp s'ouvre sur la section │ └─ app absente → app.myinfomate.be/download/{instanceId}/{configId}/{sectionId} → page « installez l'application » ← comportement actuel, conservé ``` **Le tag porte exactement l'URL du QR.** Pas d'entité `NfcTag`, pas de code opaque, pas d'endpoint de résolution, pas de colonne sur `Section`. Un tag NFC est un QR code sans caméra — c'est ce qui rend ce chantier petit. ✅ **Et il n'y a aucun code NFC à écrire pour le cas nominal.** Sur iOS (iPhone XS+) comme sur Android, l'OS lit le tag NDEF, affiche une bannière et **ouvre l'URL** ; c'est le lien universel qui aiguille vers l'app. `nfc_manager`, la permission NFC et l'entitlement Core NFC ne servent qu'à la lecture **in-app** — utile seulement pour le bouton « Scanner un tag » du lot 4. --- ## Ce qui manque vraiment : la colle ### 1. Les liens universels n'existent pas — c'est le cœur du chantier Aucun `assetlinks.json` (Android) ni `apple-app-site-association` (iOS) n'est servi sur nos domaines. Le seul du workspace est dans `OpenGlasses`, qui n'est pas à nous. ⚠️ **Ils doivent être servis par le domaine de l'URL du tag**, donc par `app.myinfomate.be` — qui **n'est pas déployé** (absent de `docker-compose-myinfomate.yml`, qui route `myinfomate.be`, `api.`, `manager.` et `monitor.`). La carte « Déployer le visiteur web », déjà `critical`, reste un **prérequis dur**. À réunir avant d'écrire les fichiers : le **SHA-256 de la clé de signature de release** Android (l'APK se construit par `tool/build_apk.sh`) et le **Team ID + bundle id** iOS. Une empreinte fausse ne produit aucune erreur visible — le lien s'ouvre simplement dans le navigateur. ### 2. L'app n'écoute pas les deep links entrants `app_links` est bien au `pubspec.yaml:89`, mais : ```dart void _listenGlassesDeepLinks() { if (!kEnableGlasses || !Platform.isAndroid) return; // ← main.dart:68 _deepLinkSub = AppLinks().uriLinkStream.listen( (uri) => MetaGlassesService.instance.handleDeepLink(uri.toString()), ); } ``` Tout part vers `MetaGlassesService`, le listener est **coupé sur iOS** et conditionné à `kEnableGlasses`. Il faut router **par motif d'URL**, sans casser le retour de registration Meta. ### 3. La résolution d'un code est enfermée dans le dialogue du scanner `ScannerDialog._onDetect` (`ScannerDialog.dart:107`) fait déjà **tout** ce qu'il faut : parsing des trois formats de QR du terrain, section appartenant ou non à la visite en cours, `_findConfigurationIdOfSection` quand l'id est brut, proposition d'ouvrir une **autre visite** du site, et télémétrie. Mais c'est un `State` : la méthode manipule `context`, `Navigator`, `ScaffoldMessenger`, et capture le navigator **avant** le `pop` pour survivre au démontage. **Extraire cette résolution dans un service** est le vrai morceau de travail — et il **profite au QR autant qu'au NFC**. À faire sans perdre les cas limites, qui sont tous des corrections de bugs réels documentées en commentaires dans le fichier. ### 4. `IsNFCEnabled`, sur le modèle exact de `IsQRCodeEnabled` `ApplicationInstance.IsQRCodeEnabled` (`ApplicationInstance.cs:57`, défaut `true`) est piloté par un switch dans `app_configuration_link_screen.dart:400` et consommé là où le bouton scanner s'affiche : `home_3.0.dart:651`, `configuration_page.dart:433`, `menu_page.dart:302`, et `visitapp-web` (`[slug]/page.tsx:44`). On ajoute `IsNFCEnabled` au même endroit, même défaut, même switch. ⚠️ **Ce que le flag pilote, et ce qu'il ne pilote pas.** Il masque le **bouton « Scanner un tag »** in-app et sert de déclaration commerciale. Il **ne peut pas** empêcher un tag posé au mur d'ouvrir l'app : le deep link vient de l'OS, et l'app le reçoit sans savoir s'il vient d'un tag ou d'un QR. Ne pas lui prêter un rôle de verrou qu'il n'aura pas. ⚠️ `Configuration.IsQRCode` (`Configuration.cs:52`) existe aussi mais **n'est lu par aucune app** — code mort. Ne pas dupliquer l'erreur en posant un flag NFC au niveau `Configuration`. ### 5. Sans quoi le NFC sera compté comme du QR dans les stats `_onDetect` émet `VisitEventType.qrScan`. Un tag qui ouvre l'app par deep link n'a aucun moyen de se distinguer — sauf à ajouter un paramètre à l'URL encodée sur le tag (`?src=nfc`) et une valeur `NfcScan` à l'enum (`VisitEvent.cs:48`). ⚠️ L'enum passe par le client généré de `manager_api_new`, **à éditer à la main**. Sans ça, le canal NFC est invisible dans les stats et on ne saura jamais s'il sert. *(À traiter avec :* la page de téléchargement dit « scannez à nouveau le QR code depuis l'application » — faux pour un tag. Le `?src=nfc` permet aussi d'adapter ce texte.*)* --- ## Découpage | Lot | Contenu | Estimation | |---|---|---| | **0 — Déployer `app.myinfomate.be`** | Carte existante, déjà `critical`. **Prérequis dur** : c'est ce domaine qui sert les `.well-known` | (carte 210) | | **1 — Liens universels** | `assetlinks.json` + `apple-app-site-association` servis sur `app.myinfomate.be`, intent-filter `autoVerify` Android, Associated Domains iOS. Demande le SHA-256 de la clé de release et le Team ID | **1 j** | | **2 — Router le deep link entrant** | Découpler `main.dart:68` de `MetaGlassesService`, activer le listener sur iOS, router par motif | **0,5 j** | | **3 — Extraire la résolution du scanner** | Sortir `_onDetect` de `ScannerDialog` vers un service, sans perdre les cas limites. ✅ **Profite au QR** | **1,5 j** | | **4 — `IsNFCEnabled`** | Colonne + DTO + client généré à la main + switch manager + i18n FR/EN/NL, et le bouton « Scanner un tag » qu'il pilote (`nfc_manager`, permission Android, entitlement iOS `NDEF`) | **1 j** | | **5 — Distinguer le canal** | `?src=nfc` sur l'URL encodée, `VisitEventType.NfcScan`, texte de la page de téléchargement | **0,5 j** | | **6 — Encoder les tags** | **NFC Tools**, 2 s par tag, une URL par point. Geste d'exploitation | **0 j de dev** | **Total : 4,5 j**, dont les lots 2 et 3 **réparent aussi le QR** — aujourd'hui un QR scanné à l'appareil photo n'ouvre jamais l'app, même installée. --- ## À savoir avant de le vendre - **iPhone XS et plus** lisent un tag sans aucune app. Les **iPhone 7 / 8 / X**, non : il leur faut une app ouverte. Android : le NFC doit être activé dans les réglages, ce qui n'est pas universel. - **L'ouverture n'est pas automatique** : l'OS affiche une **bannière que le visiteur tape**. C'est l'expérience de l'appareil photo sur un QR, pas mieux. - **Un tag à plat sur du métal ne se lit pas** — tags sur mousse ou NTAG « on-metal ». NTAG213 (144 o) suffit largement pour l'URL. - **Aucune lecture NFC sur `visitapp-web`** : WebNFC est Chrome/Android uniquement, jamais Safari. Le plan **Essentiel étant web-only**, le NFC ne s'y vend pas — sauf comme « le tag ouvre la page web », qui reste vrai et gratuit. - **Le NFC ne remplace pas le beacon** : geste volontaire à 1-2 cm, aucun déclenchement à l'approche. Les déclencheurs se cumulent.