Le tag porte l'URL du QR, rien d'autre : aucune entité, aucune colonne sur Section, aucun code NFC pour le cas nominal — l'OS lit le tag et c'est le lien universel qui aiguille. Ce qui reste à écrire, c'est la colle (assetlinks.json / AASA, routage du deep link), et elle répare au passage le QR code, qui n'ouvre jamais l'app depuis l'appareil photo. Prérequis dur : app.myinfomate.be doit être déployé pour servir les .well-known. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
129 lines
7.5 KiB
Markdown
129 lines
7.5 KiB
Markdown
# 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.
|