Files
coach-ios/docs/SESSION-XCODE.md
Sylvain Bettinelli ddfd95cbd7 Le guide Xcode annoncait un fichier a ajouter, il y en a quatre
SESSION-XCODE.md disait « une seule exception : CoachWatchComplications.swift ».
C'etait vrai le 3 aout, jour ou il a ete ecrit. Le widget de saisie rapide est
arrive le 6 aout avec trois fichiers Swift de plus, et aucun n'appartient a une
target : CoachQuickLog.swift, CoachQuickSync.swift, CoachQuickWidget.swift.
Verifie dans project.pbxproj, pas suppose.

Consequence si on suivait le guide tel quel : l'extension ne compile pas, et le
widget « Saisie des repas et boissons » n'apparait nulle part - sans que rien
n'explique pourquoi, puisque le guide affirmait qu'il n'y avait rien a ajouter.

Une etape 4b liste les trois fichiers avec leur Target Membership exact.
CoachQuickLog va dans DEUX cibles, l'extension ecrivant la file que l'app vide.
Et ce qui est deja fait est dit comme tel, pour ne pas le refaire : le widget
est enregistre dans le WidgetBundle, et CoachQuickSync.flush() est bien appele
par AppDelegate.

Le point 4 du runbook widgets demandait de verifier le schema coachapp:// dans
l'Info.plist. Il est barre : depuis e715804 les boutons pointent sur des URL
https routees par Universal Links, precisement parce que coachapp:// n'etait
routé nulle part et ouvrait l'app sur sa derniere page consultee.

Aucun code touche, uniquement de la documentation de session.

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

299 lines
12 KiB
Markdown

# Session Xcode — guide pas à pas
**Écrit le 2026-08-03 pour Sylvain, à suivre sur le Mac mini.**
Cette session livre **tout le natif accumulé depuis le TestFlight de mai** :
login Apple/Google natif, watchOS live workout, widgets iPhone, complications
Watch, et la routine quotidienne sur la montre.
Compte ~1 h 30 la première fois. Les étapes 1 à 6 mènent à une app qui tourne
sur ton iPhone ; les étapes 7 à 9 la publient sur TestFlight. **Tu peux
t'arrêter après l'étape 6** et publier un autre jour.
---
## Avant de commencer — ce qui a changé
La plupart des Swift sont déjà déclarés dans les bonnes targets (commits
`caeac37`, `f30cc60`). **Quatre** ne le sont pas et doivent être ajoutés à la
main — état vérifié dans `project.pbxproj` le 2026-08-11 :
| Fichier | Target Membership à cocher | Étape |
|---|---|---|
| `App/CoachQuickLog.swift` | **App + CoachLiveActivity** | 4b |
| `App/CoachQuickSync.swift` | **App** seule | 4b |
| `CoachLiveActivity/CoachQuickWidget.swift` | **CoachLiveActivity** seule | 4b |
| `CoachWatchWidgets/CoachWatchComplications.swift` | **CoachWatchWidgets** (target à créer) | 5 |
⚠️ Les trois premiers sont arrivés le **2026-08-06**, après la rédaction de ce
guide, qui annonçait « une seule exception » — c'était vrai le 3 août. Sans eux,
le widget « Saisie des repas et boissons » ne se compile pas. Leur runbook
détaillé est `docs/widgets-runbook-mac.md`.
Déjà fait côté code, à ne pas refaire : `CoachQuickWidget()` est enregistré dans
le `WidgetBundle` (`CoachLiveActivityBundle.swift`) et `CoachQuickSync.flush()`
est appelé depuis `AppDelegate` (l. 57).
| Ce que tu vas activer | Étape |
|---|---|
| Login Apple + Google natif | rien à faire, déjà câblé |
| Live workout watchOS | rien à faire, déjà câblé |
| Routine sur la Watch | rien à faire, déjà câblé |
| Widgets iPhone (Séance du jour, Score de forme) | étapes 3-4 (App Group) |
| Widget Saisie rapide (eau, café, photo, scan) | étape 4b (3 fichiers à ajouter) |
| Complications sur le cadran Watch | étape 5 (facultative) |
---
## Étape 1 — Récupérer le code
⚠️ **Xcode doit être FERMÉ** (`Cmd+Q`, pas juste la fenêtre). Xcode réécrit le
`project.pbxproj` depuis sa mémoire ; un `git pull` fenêtre ouverte nous a déjà
bloqués deux fois.
```bash
cd ~/coach-ios
git pull
npm install
npx cap sync ios
```
**Vérification** — tu dois voir `f30cc60` ou plus récent :
```bash
git log --oneline -1
```
Si `npx cap sync` râle sur la version de Node :
```bash
nvm use 22 # Capacitor 8 exige Node >= 22
```
## Étape 2 — Le token d'auth (à ne pas oublier)
Le fichier `CoachAuth.swift` n'est pas versionné (il contient un secret). **Sans
lui, le projet ne compile pas.**
```bash
ls ios/App/App/CoachAuth.swift
```
- **Le fichier existe** → passe à l'étape 3.
- **Il n'existe pas** → récupère le token puis crée-le :
```bash
# le token est sur le VPS
ssh ubuntu@83.228.246.229 'grep COACH_WEB_TOKEN ~/.config/infomaniak.env'
# puis, en remplaçant <TOKEN> par la valeur affichée :
cat > ios/App/App/CoachAuth.swift <<'EOF'
import Foundation
enum CoachAuth { static let kCoachWebToken: String = "<TOKEN>" }
EOF
```
## Étape 3 — App Group sur le portail Apple
Nécessaire pour que les widgets lisent les données de l'app. À faire une seule
fois, dans le navigateur.
1. [developer.apple.com](https://developer.apple.com) → **Certificates, IDs & Profiles**
2. **Identifiers** → menu déroulant en haut à droite → **App Groups**
3. Le groupe `group.ch.hypnotruck.coach` existe déjà ? → rien à faire.
Sinon : **+** → *App Group* → Description `Coach Hypnotruck`, Identifier
`group.ch.hypnotruck.coach`**Continue****Register**
## Étape 4 — Activer la capability dans Xcode
```bash
open ios/App/App.xcworkspace
```
Pour **chacune** de ces trois targets (colonne de gauche → projet **App**
onglet **TARGETS**) :
| Target | Capability à ajouter |
|---|---|
| **App** | App Groups |
| **CoachLiveActivity** | App Groups |
| **CoachWatch** | App Groups |
Pour chaque target : onglet **Signing & Capabilities****+ Capability** (en
haut à gauche) → tape « App Groups » → double-clic → **coche**
`group.ch.hypnotruck.coach` dans la liste qui apparaît.
> Si le groupe n'apparaît pas dans la liste, clique sur le bouton **refresh**
> sous la liste, ou re-connecte ton compte (Xcode → Settings → Accounts).
⚠️ **Dès que c'est fait, commit + push** — sinon ton prochain `git pull` sera
bloqué par les modifications locales :
```bash
git add -A ios/App && git commit -m "chore(xcode): App Groups sur App, LiveActivity et Watch" && git push
```
## Étape 4b — Les trois fichiers du widget « Saisie rapide » *(~5 min)*
Ils existent dans le repo depuis le 6 août mais n'appartiennent à aucune target :
tant qu'ils n'y sont pas, le widget eau/café n'existe pas et l'extension ne
compile pas.
Dans Xcode, clic droit sur le dossier de la cible → **Add Files to "App"…**
**décoche** *Copy items if needed* → coche la ou les targets du tableau. Pour un
fichier déjà présent dans l'arborescence, passe par l'inspecteur de droite
(`Cmd+Option+1`) → **Target Membership**.
| Fichier | Cocher |
|---|---|
| `ios/App/App/CoachQuickLog.swift` | **App** *et* **CoachLiveActivity** |
| `ios/App/App/CoachQuickSync.swift` | **App** seule |
| `ios/App/CoachLiveActivity/CoachQuickWidget.swift` | **CoachLiveActivity** seule |
`CoachQuickLog.swift` doit bien être dans **les deux** cibles : l'extension
écrit la file d'attente, l'app la vide.
Rien d'autre à câbler — `CoachQuickWidget()` est déjà dans le `WidgetBundle` et
`CoachQuickSync.flush()` est déjà appelé par `AppDelegate`. Puis commit + push.
## Étape 5 — Complications Watch *(facultative, ~15 min)*
**Tu peux sauter cette étape** et y revenir plus tard : tout le reste fonctionne
sans. Elle n'ajoute que les complications sur le cadran de la montre.
1. Menu **File → New → Target…**
2. Onglet **watchOS****Widget Extension****Next**
3. Product Name : `CoachWatchWidgets` — décoche *Include Live Activity*
**Embed in Application** : `CoachWatch`**Finish**
4. Xcode propose d'activer le nouveau schéma → **Activate**
5. Dans le dossier `CoachWatchWidgets` créé, **supprime** le fichier
`CoachWatchWidgets.swift` généré (clic droit → Delete → *Move to Trash*)
6. Clic droit sur le dossier `CoachWatchWidgets`**Add Files to "App"…**
sélectionne `ios/App/CoachWatchWidgets/CoachWatchComplications.swift`
**décoche** *Copy items if needed*, **coche** la target `CoachWatchWidgets`
7. Sélectionne `CoachWidgetSnapshot.swift` dans la colonne de gauche →
inspecteur de droite (`Cmd+Option+1`) → **Target Membership** → coche
**CoachWatchWidgets**
8. Target `CoachWatchWidgets`**Signing & Capabilities****+ Capability** →
**App Groups** → coche `group.ch.hypnotruck.coach`
Puis commit + push (même raison qu'à l'étape 4).
## Étape 6 — Compiler et tester sur l'iPhone
1. Branche l'iPhone, déverrouille-le, avec l'Apple Watch au poignet et appairée
2. En haut de Xcode, sélectionne le schéma **App** et ton iPhone comme device
3. **Product → Clean Build Folder** (`Cmd+Shift+K`)
4. **Run** (`Cmd+R`)
### Si ça ne compile pas
| Erreur | Cause | Solution |
|---|---|---|
| `cannot find 'CoachAuth' in scope` | étape 2 sautée | crée `CoachAuth.swift` |
| `no such module 'Capacitor'` | sync manquant | `npx cap sync ios`, Xcode fermé |
| erreur de signing | profil pas régénéré | Signing & Capabilities → décoche/recoche *Automatically manage signing* |
| `CoachWidgetStore` introuvable | Target Membership | vérifie que `CoachWidgetSnapshot.swift` est coché pour la target qui râle |
### Tests, dans l'ordre (5 min)
1. **L'app se lance et tu es connecté** → le cookie natif fonctionne.
2. **Live workout** (le seul flux déjà validé, à ne pas casser) : démarre une
séance sur la Watch → la FC doit apparaître sur `/live` de l'iPhone.
⚠️ *C'est le test le plus important : j'ai touché à `CoachLiveBridge` pour
faire passer la routine. Si la FC ne remonte plus, dis-le-moi.*
3. **Routine sur la Watch** : ouvre `/routine` sur l'iPhone (ça pousse les blocs
vers la montre) → app Coach sur la Watch → **Routine du jour** → les 6 blocs
s'affichent → coche-en un → la page iPhone se met à jour **sans recharger**.
4. **Widgets iPhone** : écran d'accueil → appui long → **+** → cherche *Coach*
ajoute « Séance du jour » et « Score de forme ».
5. **Login natif** : déconnecte-toi, teste *Se connecter avec Apple* et *Google*.
Vérification serveur de la routine :
```bash
ssh ubuntu@83.228.246.229 'cat /home/ubuntu/coach_sportif/data/routine_log.json'
```
**Si tu t'arrêtes ici, c'est déjà un succès** : ton iPhone a tout le natif.
---
## Étape 7 — Préparer la distribution
Deux réglages avant d'archiver.
**a. Numéro de build** — target **App** → onglet **General** :
`Version` = `1.3`, `Build` = `23` (le repo est à 1.2 / 22).
**b. Push notifications en production**`ios/App/App/App.entitlements`
contient `aps-environment = development`. En TestFlight, les notifications push
distantes ne marcheront pas avec cette valeur.
Le plus simple : laisse Xcode gérer. Avec *Automatically manage signing*, le
profil de distribution force `production` à l'archivage. **Vérifie-le après
l'étape 8** : Organizer → clic droit sur l'archive → *Show in Finder* → clic
droit → *Afficher le contenu*`Products/Applications/App.app` → clic droit →
*Afficher le contenu* → ouvre `embedded.mobileprovision` avec TextEdit → cherche
`aps-environment`, il doit valoir `production`.
Si ce n'est pas le cas, édite `App.entitlements` en mettant `production`,
ré-archive, et **remets `development`** ensuite pour ne pas casser tes builds de
dev.
## Étape 8 — Archiver
1. En haut, remplace ton iPhone par **Any iOS Device (arm64)**
2. **Product → Archive** (compte 5-10 min)
3. La fenêtre **Organizer** s'ouvre sur l'archive
Si *Archive* est grisé : tu es encore sur un simulateur, repasse en *Any iOS Device*.
## Étape 9 — Envoyer sur TestFlight
1. Dans l'Organizer : **Distribute App****App Store Connect****Upload**
2. Laisse les options par défaut → **Next****Upload**
3. Attends 5-30 min qu'Apple finisse le *processing* (mail de confirmation)
4. [appstoreconnect.apple.com](https://appstoreconnect.apple.com) → **Coach
Hypnotruck** → **TestFlight** → le build 23 apparaît
5. ⚠️ **Assigne le build au groupe de testeurs internes** — sans ça, il
n'apparaît pas dans TestFlight sur ton iPhone. Ça nous a bloqués en mai :
*Internal Testing* → ton groupe → **+** → coche le build 23
6. Sur l'iPhone : app **TestFlight****Mettre à jour**
⚠️ Le cache WKWebView est tenace. Si l'app affiche encore l'ancienne interface
après mise à jour : **désinstalle l'app** puis réinstalle depuis TestFlight.
---
## En cas de blocage
Note l'étape et le message d'erreur exact, et envoie-les-moi. Utile à joindre :
```bash
# état du repo
cd ~/coach-ios && git log --oneline -3 && git status -sb
# les fichiers Swift sont-ils tous câblés ? (doit ne rien afficher sauf
# CoachWatchComplications si tu as sauté l'étape 5)
# -not -path '*/build/*' est indispensable : DerivedData et les checkouts SPM
# contiennent des centaines de .swift qui n'ont rien à faire dans le pbxproj
for f in $(find ios -name '*.swift' -not -path '*/build/*' -not -path '*/CapApp-SPM/*'); do
grep -q "$(basename $f)" ios/App/App.xcodeproj/project.pbxproj || echo "NON CÂBLÉ: $f"
done
```
Pour les erreurs de plugins à l'exécution : Safari → menu **Développement**
ton iPhone → `coach.hypnotruck.ch` → console :
```js
Object.keys(Capacitor.Plugins).filter(k => k.startsWith('Coach'))
// doit lister : CoachWorkoutKit, CoachHealthRoute, CoachWorkoutObserver,
// CoachLiveBridge, CoachAppleAuth, CoachGoogleAuth,
// CoachWidgetBridge, CoachRoutineBridge
```
## Rappels permanents
- **Toujours quitter Xcode avant un `git pull`.**
- **Toujours commit + push après une modification faite dans Xcode**
(capability, signing, target) — sinon le prochain pull est bloqué.
- Les changements **web** (templates, CSS, routes) ne demandent **aucun build** :
ils arrivent au prochain lancement de l'app.