Files
coach-ios/docs/live-activity-runbook-mac.md
Sylvain Bettinelli 21d39f2e98 Piloter la séance depuis la Live Activity (Pause / Terminer)
Comme l'app Exercice : deux boutons sur la bannière de l'écran verrouillé et
dans l'île dépliée. iOS n'expose aucun geste de balayage pour révéler des
actions — depuis iOS 17, ce sont des boutons intégrés (App Intents), et c'est
le seul mécanisme public.

- Intents `CoachTogglePauseIntent` / `CoachEndWorkoutIntent`, conformes à
  LiveActivityIntent (sans quoi `perform()` n'est jamais appelé).
- Ils vivent dans CoachLiveActivityAttributes.swift, seul fichier déjà membre
  des deux targets : un fichier neuf imposerait une manip Target Membership
  dans Xcode, source d'erreurs répétées ici.
- Commandes relayées à la montre par WCSession, avec repli transferUserInfo :
  isReachable retombe à false quand la séance tourne en arrière-plan profond,
  la commande est alors différée au réveil de l'app montre.
- L'état de pause remonte depuis HKWorkoutSession (seule source fiable : la
  montre peut mettre en pause d'elle-même) et bascule le libellé du bouton.
- Le watchdog de LiveStore est neutralisé pendant la pause : sans ça, l'absence
  de samples aurait affiché « connexion perdue » puis terminé l'activité.
- L'app watchOS gagne le bouton Pause qui lui manquait, aligné sur le même état.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 13:25:14 +00:00

5.9 KiB

Build du correctif « Live Activity fantôme » — runbook Mac

Écrit le 2026-08-11. Concerne le commit 5e9b4a3 (La Live Activity restait affichée après la fin de séance).

Compte 15 minutes. C'est un build simple : aucun fichier nouveau, aucune target à créer, aucune capability à ajouter. Les cinq fichiers modifiés sont déjà membres de leurs targets (vérifié dans project.pbxproj).

⚠️ La montre doit être rebuildée aussi, pas seulement l'iPhone : le message de fin de séance part de CoachWatch. Un build iPhone seul ne corrige rien.


Étape 1 — Récupérer le code

Xcode fermé (Cmd+Q, pas juste la fenêtre) :

cd ~/coach-ios
git pull
git log --oneline -1     # doit afficher 5e9b4a3 ou plus récent

Pas besoin de npm install ni de npx cap sync ios : aucune dépendance ni config Capacitor n'a bougé. Si Xcode râle sur no such module 'Capacitor', alors seulement, lance npx cap sync ios (Xcode fermé).

Étape 2 — Build sur l'iPhone

open ios/App/App.xcodeproj
  1. iPhone branché et déverrouillé, Apple Watch au poignet et appairée
  2. Schéma App + ton iPhone comme destination
  3. Run (Cmd+R)

Pas de Clean Build Folder nécessaire — cinq fichiers modifiés, la compilation incrémentale suffit.

Étape 3 — Installer la nouvelle app sur la Watch

L'app watchOS est embarquée dans l'app iPhone, mais watchOS ne la réinstalle pas toujours tout de suite. Le plus fiable : builder directement dessus.

  1. Schéma CoachWatch (menu des schémas, en haut)
  2. Destination : ton Apple Watch Ultra 3
  3. Run (Cmd+R)

Le premier lancement sur la montre peut demander 2-3 minutes et afficher « Waiting to attach » — c'est normal.

Alternative sans Xcode : iPhone → app WatchApps installées → Coach → attendre la réinstallation. Plus lent et moins déterministe.

Vérifier que la montre a bien la nouvelle version : dans les logs (étape 4), la ligne fin de séance signalée à l'iPhone n'existe que dans ce build.

Étape 4 — Tester (3 minutes)

Le test se fait dans cet ordre, en gardant Console.app ouvert sur le Mac :

Console.app → ton iPhone dans la colonne de gauche
Filtre : subsystem:ch.hypnotruck.coach
  1. Démarrer une séance depuis l'app Coach sur la Watch → la Live Activity apparaît sur l'iPhone (cœur + FC qui bouge) → log Live Activity started
  2. Terminer la séance sur la Watch → log côté montre : fin de séance signalée à l'iPhone (reason=session-ended) → log côté iPhone : fin de séance reçue de la Watch puis Live Activity endedla Live Activity disparaît immédiatement de l'écran

C'est ce dernier point qui valide le correctif. Avant, elle restait ~4 h avec la dernière FC figée.

  1. Écran verrouillé : referme l'iPhone pendant la séance, termine sur la montre, rallume l'écran. La bannière ne doit plus être là. C'est le cas qui échouait vraiment — le watchdog reposait sur un Timer qui ne tourne pas quand l'app est suspendue.

  2. Vérifie au passage que la FC remonte toujours sur /live (le flux de samples n'a pas changé, mais CoachLiveBridge a été touché).

Le cœur fantôme actuellement à l'écran

Il vient de l'ancien build. Il partira soit au premier liveEnded reçu (la nouvelle app reprend la main dessus via adoptExisting()), soit après 6 h, soit tout de suite si tu le fermes à la main (appui long → fermer).

Étape 4bis — Les boutons Pause / Terminer (build du 2026-08-11, second lot)

La Live Activity porte maintenant deux boutons, comme l'app Exercice : Pause / Reprendre et Terminer. Ils apparaissent sur la bannière de l'écran verrouillé et dans l'île dynamique dépliée (appui long sur l'île) — pas en mode compact, où iOS n'accepte aucun bouton.

Aucune manipulation Xcode : les intents vivent dans CoachLiveActivityAttributes.swift, déjà membre des deux targets.

À tester, séance en cours :

  1. Appui long sur l'île → les deux boutons apparaissent
  2. Pause → la séance se met en pause sur la montre, le bouton devient Reprendre, et la page /live ne bascule pas en « Connexion perdue » (le watchdog est neutralisé pendant la pause)
  3. Reprendre → la FC repart
  4. Terminer → la séance s'arrête sur la montre et la Live Activity disparaît immédiatement

⚠️ Limite Apple, à connaître avant de crier au bug : WCSession.isReachable retombe à false quand l'app watchOS tourne sa séance en arrière-plan profond (poignet baissé, écran éteint). La commande bascule alors sur transferUserInfo : elle est garantie mais différée, donc elle s'applique au réveil de l'app montre et non à la seconde. Poignet levé, c'est immédiat. Aucune API publique ne fait mieux.

Détail mineur : en mode test (FC simulée), la pause bascule l'état mais la simulation continue d'émettre des samples. Sans effet sur une vraie séance.

Étape 5 — TestFlight (facultatif)

Rien de spécifique ici : c'est la procédure habituelle, étapes 7 à 9 de docs/SESSION-XCODE.md. Pense à incrémenter le numéro de build.


Si ça ne compile pas

Erreur Cause probable Solution
cannot find 'CoachAuth' in scope CoachAuth.swift absent (non versionné) étape 2 de docs/SESSION-XCODE.md
no such module 'Capacitor' sync manquant npx cap sync ios, Xcode fermé
value of type 'ConnectivityManager' has no member 'sendEnded' la target CoachWatch compile un ancien ConnectivityManager.swift vérifie que le git pull a bien eu lieu et que Xcode n'a pas restauré un pbxproj en mémoire
erreur de signing sur CoachWatch profil pas régénéré Signing & Capabilities → décoche/recoche Automatically manage signing

En cas de blocage, envoie-moi l'étape, le message exact, et :

cd ~/coach-ios && git log --oneline -3 && git status -sb