From 40ffb04f313b8df8b449e0841243a869db8972fa Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 17:54:09 +0200 Subject: [PATCH 01/11] fix: Dynamic Island, Live Activity errors, background audio stop, CFBundleVersion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 — Audio background resilience: - Remove .mixWithOthers, app takes audio focus for coach cues - Add AVAudioSession.interruptionNotification handler (re-activates after calls/Siri) - Add AVAudioSession.routeChangeNotification handler (re-activates on headphone changes) Phase 2 — Live Activity error surfacing: - PlayerViewModel: @Published liveActivityError captures auth-denied + request errors - PlayerView: translucent error banner with dismiss button (non-blocking) Phase 3 — CFBundleVersion 1→2 in all 4 Info.plist files (match project.yml CURRENT_PROJECT_VERSION: 2) --- tabatago-swift/TabataGo/Resources/Info.plist | 2 +- .../TabataGo/Services/AudioService.swift | 45 ++++++++++++++++++- .../TabataGo/ViewModels/PlayerViewModel.swift | 8 +++- .../TabataGo/Views/Player/PlayerView.swift | 34 ++++++++++++++ .../TabataGoWatch/Complications/Info.plist | 2 +- .../TabataGoWatch/Resources/Info.plist | 2 +- tabatago-swift/TabataGoWidget/Info.plist | 2 +- 7 files changed, 89 insertions(+), 6 deletions(-) diff --git a/tabatago-swift/TabataGo/Resources/Info.plist b/tabatago-swift/TabataGo/Resources/Info.plist index 9af55fc..36ae005 100644 --- a/tabatago-swift/TabataGo/Resources/Info.plist +++ b/tabatago-swift/TabataGo/Resources/Info.plist @@ -28,7 +28,7 @@ CFBundleVersion - 1 + 2 NSHealthShareUsageDescription TabataGo reads your health data to show fitness stats and personalize your workouts. NSHealthUpdateUsageDescription diff --git a/tabatago-swift/TabataGo/Services/AudioService.swift b/tabatago-swift/TabataGo/Services/AudioService.swift index 0b053a3..ec8c6b4 100644 --- a/tabatago-swift/TabataGo/Services/AudioService.swift +++ b/tabatago-swift/TabataGo/Services/AudioService.swift @@ -28,12 +28,55 @@ final class AudioService { try audioSession.setCategory( .playback, mode: .default, - options: [.mixWithOthers, .allowAirPlay, .allowBluetooth] + options: [.allowAirPlay, .allowBluetooth] ) try audioSession.setActive(true) } catch { print("[Audio] Session configuration failed: \(error)") } + + // ─── Interruption Handler + NotificationCenter.default.addObserver( + forName: AVAudioSession.interruptionNotification, + object: nil, + queue: .main + ) { [weak self] notification in + guard let self, + let typeValue = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt, + let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { return } + + if type == .ended { + guard let optionsValue = notification.userInfo?[AVAudioSessionInterruptionOptionKey] as? UInt, + AVAudioSession.InterruptionOptions(rawValue: optionsValue).contains(.shouldResume) else { return } + do { + try self.audioSession.setActive(true) + } catch { + print("[Audio] Re-activation failed after interruption: \(error)") + } + } + } + + // ─── Route Change Handler + NotificationCenter.default.addObserver( + forName: AVAudioSession.routeChangeNotification, + object: nil, + queue: .main + ) { [weak self] notification in + guard let self, + let reasonValue = notification.userInfo?[AVAudioSessionRouteChangeReasonKey] as? UInt, + let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else { return } + + switch reason { + case .newDeviceAvailable, .oldDeviceUnavailable: + do { + try self.audioSession.setActive(true) + } catch { + print("[Audio] Route re-activation failed: \(error)") + } + default: + break + } + } } // ─── Phase Audio Cues ───────────────────────────────────────── diff --git a/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift b/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift index 087cd8c..ec53046 100644 --- a/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift +++ b/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift @@ -39,6 +39,7 @@ final class PlayerViewModel: ObservableObject { @Published var isComplete: Bool = false @Published var showExitConfirmation: Bool = false @Published private(set) var completedSession: WorkoutSession? = nil + @Published var liveActivityError: String? = nil // Track info for Live Activity — set by View when music changes var currentTrackTitle = "" @@ -382,7 +383,10 @@ final class PlayerViewModel: ObservableObject { // ─── Dynamic Island / Live Activity ───────────────────────────── func syncActivity(shouldAlert: Bool = false) { - guard ActivityAuthorizationInfo().areActivitiesEnabled else { return } + guard ActivityAuthorizationInfo().areActivitiesEnabled else { + liveActivityError = "Live Activities are disabled in Settings" + return + } guard isRunning else { return } let isPlayingMusic = (phase == .work || phase == .rest) && isRunning && !isPaused @@ -449,8 +453,10 @@ final class PlayerViewModel: ObservableObject { attributes: attrs, content: ActivityContent(state: state, staleDate: staleDate) ) + liveActivityError = nil observeActivityState() } catch { + liveActivityError = error.localizedDescription print("❌ Failed to start Live Activity: \(error.localizedDescription)") } } diff --git a/tabatago-swift/TabataGo/Views/Player/PlayerView.swift b/tabatago-swift/TabataGo/Views/Player/PlayerView.swift index c43cb71..ea6a7a8 100644 --- a/tabatago-swift/TabataGo/Views/Player/PlayerView.swift +++ b/tabatago-swift/TabataGo/Views/Player/PlayerView.swift @@ -66,6 +66,40 @@ struct PlayerView: View { } } + // ══════════════════════════════════════════════════ + // Live Activity error banner (non-blocking) + // ══════════════════════════════════════════════════ + if let error = vm.liveActivityError { + VStack { + HStack(spacing: 8) { + Image(systemName: "exclamationmark.triangle.fill") + .font(.caption) + .foregroundStyle(.yellow) + Text(error) + .font(.caption2.weight(.medium)) + .foregroundStyle(.white.opacity(0.9)) + Spacer() + Button { + vm.liveActivityError = nil + } label: { + Image(systemName: "xmark") + .font(.system(size: 10, weight: .bold)) + .foregroundStyle(.white.opacity(0.6)) + } + } + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(.ultraThinMaterial.opacity(0.9)) + .clipShape(RoundedRectangle(cornerRadius: 12)) + .padding(.horizontal, 16) + .padding(.top, 60) + Spacer() + } + .transition(.move(edge: .top).combined(with: .opacity)) + .animation(.spring(duration: 0.3), value: vm.liveActivityError) + .zIndex(100) + } + // ══════════════════════════════════════════════════ // Layer 4 — Compact timer ring (top-right corner) // ══════════════════════════════════════════════════ diff --git a/tabatago-swift/TabataGoWatch/Complications/Info.plist b/tabatago-swift/TabataGoWatch/Complications/Info.plist index e556090..5bfd1a7 100644 --- a/tabatago-swift/TabataGoWatch/Complications/Info.plist +++ b/tabatago-swift/TabataGoWatch/Complications/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 1 + 2 NSExtension NSExtensionPointIdentifier diff --git a/tabatago-swift/TabataGoWatch/Resources/Info.plist b/tabatago-swift/TabataGoWatch/Resources/Info.plist index 0eed266..ea4cb6f 100644 --- a/tabatago-swift/TabataGoWatch/Resources/Info.plist +++ b/tabatago-swift/TabataGoWatch/Resources/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 1 + 2 NSHealthShareUsageDescription TabataGo reads your heart rate and calories during workouts. NSHealthUpdateUsageDescription diff --git a/tabatago-swift/TabataGoWidget/Info.plist b/tabatago-swift/TabataGoWidget/Info.plist index fb382bf..b64cae1 100644 --- a/tabatago-swift/TabataGoWidget/Info.plist +++ b/tabatago-swift/TabataGoWidget/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 1 + 2 NSExtension NSExtensionPointIdentifier -- 2.49.1 From a17367081c16bff592a0d311fe07d101f8956121 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 18:07:59 +0200 Subject: [PATCH 02/11] fix: add widget target, push entitlement, error handling, force-unwrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 — Widget extension target: - Add TabataGoWidget target to project.yml (app-extension, iOS 26.0) - Embed in TabataGo, add to scheme build targets Phase 2 — Push notification capability: - Add aps-environment: development to TabataGo.entitlements - Required by iOS 26 for AppIntents-based Live Activity buttons Phase 3 — Error handling hardening: - Catch ActivityAuthorizationError specifically with user message - Truncate generic errors to 200 chars to avoid UI overflow - Fix force-unwrap at WorkoutLiveActivity.swift:556 (widgetURL) --- .../TabataGo/Resources/TabataGo.entitlements | 2 ++ .../TabataGo/ViewModels/PlayerViewModel.swift | 6 +++- .../TabataGoWidget/WorkoutLiveActivity.swift | 2 +- tabatago-swift/project.yml | 28 +++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/tabatago-swift/TabataGo/Resources/TabataGo.entitlements b/tabatago-swift/TabataGo/Resources/TabataGo.entitlements index 800b1a1..7169ba0 100644 --- a/tabatago-swift/TabataGo/Resources/TabataGo.entitlements +++ b/tabatago-swift/TabataGo/Resources/TabataGo.entitlements @@ -8,6 +8,8 @@ health-records + aps-environment + development com.apple.security.application-groups diff --git a/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift b/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift index ec53046..88641a7 100644 --- a/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift +++ b/tabatago-swift/TabataGo/ViewModels/PlayerViewModel.swift @@ -455,8 +455,12 @@ final class PlayerViewModel: ObservableObject { ) liveActivityError = nil observeActivityState() + } catch let authError as ActivityAuthorizationError { + liveActivityError = "Live Activities: \(authError.localizedDescription)" } catch { - liveActivityError = error.localizedDescription + let msg = error.localizedDescription + let truncated = msg.count > 200 ? String(msg.prefix(200)) + "…" : msg + liveActivityError = "Live Activity error: \(truncated)" print("❌ Failed to start Live Activity: \(error.localizedDescription)") } } diff --git a/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift b/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift index 59441fe..cdcc2e4 100644 --- a/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift +++ b/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift @@ -553,7 +553,7 @@ struct WorkoutLiveActivity: Widget { .contentMargins(.leading, 8, for: .expanded) .contentMargins(.trailing, 8, for: .expanded) .contentMargins(.bottom, 6, for: .expanded) - .widgetURL(URL(string: "tabatago://workout")!) + .widgetURL(URL(string: "tabatago://workout") ?? URL(string: "about:blank")!) } .supplementalActivityFamilies([.small, .medium]) } diff --git a/tabatago-swift/project.yml b/tabatago-swift/project.yml index 7f7d5db..136052b 100644 --- a/tabatago-swift/project.yml +++ b/tabatago-swift/project.yml @@ -76,6 +76,8 @@ targets: - target: TabataGoWatch embed: true + - target: TabataGoWidget + embed: true settings: base: PRODUCT_BUNDLE_IDENTIFIER: fr.millianlmx.tabatago @@ -156,6 +158,31 @@ targets: TARGETED_DEVICE_FAMILY: "4" WATCHOS_DEPLOYMENT_TARGET: "11.0" + TabataGoWidget: + type: app-extension + platform: iOS + deploymentTarget: "26.0" + sources: + - path: TabataGoWidget + excludes: + - "**/.DS_Store" + info: + path: TabataGoWidget/Info.plist + properties: + CFBundleDisplayName: TabataGoWidget + CFBundleShortVersionString: "1.0" + CFBundleVersion: "2" + NSExtension: + NSExtensionPointIdentifier: com.apple.widgetkit-extension + NSSupportsLiveActivities: true + NSSupportsLiveActivitiesFrequentUpdates: true + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: fr.millianlmx.tabatago.widget + IPHONEOS_DEPLOYMENT_TARGET: "26.0" + TARGETED_DEVICE_FAMILY: "1" + ENABLE_PREVIEWS: YES + TabataGoTests: type: bundle.unit-test platform: iOS @@ -185,6 +212,7 @@ schemes: build: targets: TabataGo: all + TabataGoWidget: all run: config: Debug archive: -- 2.49.1 From 1bb6a544e4e2034bbb21549842179ddbc78b428c Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 18:11:16 +0200 Subject: [PATCH 03/11] fix: add shared model sources to TabataGoWidget target Widget extension references WorkoutPhase, WorkoutActivityAttributes, TogglePauseIntent (WorkoutLiveActivity) and MusicActivityAttributes (MusicLiveActivity) but cannot import parent app module. Shared source files must be compiled in both targets, following existing pattern of WatchConnectivityTypes.swift shared between iOS/watch. --- tabatago-swift/project.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tabatago-swift/project.yml b/tabatago-swift/project.yml index 136052b..150c4b7 100644 --- a/tabatago-swift/project.yml +++ b/tabatago-swift/project.yml @@ -38,6 +38,8 @@ targets: - path: TabataGo excludes: - "**/.DS_Store" + - path: TabataGo/Models/WorkoutActivityAttributes.swift + - path: TabataGo/Models/MusicActivityAttributes.swift resources: - path: TabataGo/Resources excludes: @@ -98,6 +100,8 @@ targets: - path: TabataGoWatch excludes: - "**/.DS_Store" + - path: TabataGo/Models/WorkoutActivityAttributes.swift + - path: TabataGo/Models/MusicActivityAttributes.swift - "Resources/Info.plist" - "Complications/**" # Shared protocol types — referenced by both targets @@ -144,6 +148,8 @@ targets: - path: TabataGoWatch/Complications excludes: - "**/.DS_Store" + - path: TabataGo/Models/WorkoutActivityAttributes.swift + - path: TabataGo/Models/MusicActivityAttributes.swift info: path: TabataGoWatch/Complications/Info.plist properties: @@ -166,6 +172,8 @@ targets: - path: TabataGoWidget excludes: - "**/.DS_Store" + - path: TabataGo/Models/WorkoutActivityAttributes.swift + - path: TabataGo/Models/MusicActivityAttributes.swift info: path: TabataGoWidget/Info.plist properties: -- 2.49.1 From 210c254298fc6bb19bd26d7ee4167e45baf97679 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 18:15:11 +0200 Subject: [PATCH 04/11] fix: scope shared model sources to TabataGoWidget only Previous sed command accidentally injected shared model files into TabataGo, TabataGoWatch, and TabataGoWatchWidget targets, corrupting their YAML structure. Restored all targets; shared files now correctly scoped to TabataGoWidget target only. --- tabatago-swift/project.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tabatago-swift/project.yml b/tabatago-swift/project.yml index 150c4b7..01818c0 100644 --- a/tabatago-swift/project.yml +++ b/tabatago-swift/project.yml @@ -38,8 +38,6 @@ targets: - path: TabataGo excludes: - "**/.DS_Store" - - path: TabataGo/Models/WorkoutActivityAttributes.swift - - path: TabataGo/Models/MusicActivityAttributes.swift resources: - path: TabataGo/Resources excludes: @@ -100,8 +98,6 @@ targets: - path: TabataGoWatch excludes: - "**/.DS_Store" - - path: TabataGo/Models/WorkoutActivityAttributes.swift - - path: TabataGo/Models/MusicActivityAttributes.swift - "Resources/Info.plist" - "Complications/**" # Shared protocol types — referenced by both targets @@ -148,8 +144,6 @@ targets: - path: TabataGoWatch/Complications excludes: - "**/.DS_Store" - - path: TabataGo/Models/WorkoutActivityAttributes.swift - - path: TabataGo/Models/MusicActivityAttributes.swift info: path: TabataGoWatch/Complications/Info.plist properties: -- 2.49.1 From ee01380be83721c015f038312f2a3ed4569e5d78 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 18:19:37 +0200 Subject: [PATCH 05/11] =?UTF-8?q?fix:=20remove=20remaining=20force-unwrap?= =?UTF-8?q?=20in=20widgetURL=20(AGENTS.md=20=C2=A77)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift b/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift index cdcc2e4..a84ea57 100644 --- a/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift +++ b/tabatago-swift/TabataGoWidget/WorkoutLiveActivity.swift @@ -553,7 +553,7 @@ struct WorkoutLiveActivity: Widget { .contentMargins(.leading, 8, for: .expanded) .contentMargins(.trailing, 8, for: .expanded) .contentMargins(.bottom, 6, for: .expanded) - .widgetURL(URL(string: "tabatago://workout") ?? URL(string: "about:blank")!) + .widgetURL(URL(string: "tabatago://workout")) } .supplementalActivityFamilies([.small, .medium]) } -- 2.49.1 From 807361449b12dfdb46db426667d41ad9054b29ec Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 18:26:12 +0200 Subject: [PATCH 06/11] =?UTF-8?q?fix:=20remove=20info.properties=20from=20?= =?UTF-8?q?widget=20target=20=E2=80=94=20use=20on-disk=20Info.plist=20with?= =?UTF-8?q?=20NSSupportsLiveActivities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tabatago-swift/project.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tabatago-swift/project.yml b/tabatago-swift/project.yml index 01818c0..aac4124 100644 --- a/tabatago-swift/project.yml +++ b/tabatago-swift/project.yml @@ -170,14 +170,6 @@ targets: - path: TabataGo/Models/MusicActivityAttributes.swift info: path: TabataGoWidget/Info.plist - properties: - CFBundleDisplayName: TabataGoWidget - CFBundleShortVersionString: "1.0" - CFBundleVersion: "2" - NSExtension: - NSExtensionPointIdentifier: com.apple.widgetkit-extension - NSSupportsLiveActivities: true - NSSupportsLiveActivitiesFrequentUpdates: true settings: base: PRODUCT_BUNDLE_IDENTIFIER: fr.millianlmx.tabatago.widget -- 2.49.1 From b956e5189b66a7fabe9a76832798e88660245e59 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 18:50:12 +0200 Subject: [PATCH 07/11] fix(ci): eliminate pipeline bug preventing ios-deploy fallback When devicectl fails under bash -e -o pipefail, the pipeline (xcrun devicectl ... | tail -3) exits non-zero and -e kills the script before the if-check. The ios-deploy USB fallback was dead code. Fix: redirect to temp file, capture exit code explicitly. No pipeline = pipefail has no side-channel effect. --- .github/workflows/pr-iphone-deploy.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-iphone-deploy.yml b/.github/workflows/pr-iphone-deploy.yml index 4fbb346..61531e1 100644 --- a/.github/workflows/pr-iphone-deploy.yml +++ b/.github/workflows/pr-iphone-deploy.yml @@ -106,8 +106,10 @@ jobs: # 1. Try WiFi first (Xcode 15+ devicectl network discovery) echo "📱 Trying WiFi install via devicectl..." - xcrun devicectl device install app --device "$UDID" "$APP" 2>&1 | tail -3 - if [ ${PIPESTATUS[0]} -eq 0 ]; then + xcrun devicectl device install app --device "$UDID" "$APP" > /tmp/devicectl.log 2>&1 + DEVICECTL_EXIT=$? + tail -10 /tmp/devicectl.log + if [ $DEVICECTL_EXIT -eq 0 ]; then echo "✅ Installed via WiFi" exit 0 fi -- 2.49.1 From b57584f890801680b7233bfbbb3898228ffa6588 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 18:59:21 +0200 Subject: [PATCH 08/11] fix(ci): wrap deploy commands in if blocks for -e protection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bash -e doesn't just kill on pipefail — it exits on ANY non-zero command. Even without a pipeline, both xcrun devicectl and ios-deploy return non-zero on failure, killing the script before the exit-code check. Fix: wrap both in 'if command; then exit 0; fi' so -e treats them as condition-tested (no early exit). Fallback now actually runs. --- .github/workflows/pr-iphone-deploy.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-iphone-deploy.yml b/.github/workflows/pr-iphone-deploy.yml index 61531e1..d7b6b42 100644 --- a/.github/workflows/pr-iphone-deploy.yml +++ b/.github/workflows/pr-iphone-deploy.yml @@ -106,18 +106,15 @@ jobs: # 1. Try WiFi first (Xcode 15+ devicectl network discovery) echo "📱 Trying WiFi install via devicectl..." - xcrun devicectl device install app --device "$UDID" "$APP" > /tmp/devicectl.log 2>&1 - DEVICECTL_EXIT=$? - tail -10 /tmp/devicectl.log - if [ $DEVICECTL_EXIT -eq 0 ]; then + if xcrun devicectl device install app --device "$UDID" "$APP" > /tmp/devicectl.log 2>&1; then echo "✅ Installed via WiFi" exit 0 fi + tail -10 /tmp/devicectl.log # 2. Fallback to USB via ios-deploy echo "🔌 WiFi failed, trying USB..." - ios-deploy --bundle "$APP" --id "$UDID" --justlaunch - if [ $? -eq 0 ]; then + if ios-deploy --bundle "$APP" --id "$UDID" --justlaunch; then echo "✅ Installed via USB" exit 0 fi @@ -125,6 +122,7 @@ jobs: echo "❌ Install failed (both WiFi and USB)" exit 1 + - name: Post "Ready to test" comment env: GT_TOKEN: ${{ secrets.PR_API_TOKEN }} -- 2.49.1 From 309d67c88a8336b5f8d78476c71f3c5a0f4d0130 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 19:13:54 +0200 Subject: [PATCH 09/11] fix(widget): add NSExtension to info.properties for xcodegen compat xcodegen parses info.path plist and generates INFOPLIST_KEY_* settings, but silently drops nested dictionaries like NSExtension. Adding it to info.properties ensures xcodegen produces: INFOPLIST_KEY_NSExtension_NSExtensionPointIdentifier = widgetkit-extension which Xcode preserves at build time. --- tabatago-swift/project.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tabatago-swift/project.yml b/tabatago-swift/project.yml index aac4124..24cecad 100644 --- a/tabatago-swift/project.yml +++ b/tabatago-swift/project.yml @@ -170,6 +170,11 @@ targets: - path: TabataGo/Models/MusicActivityAttributes.swift info: path: TabataGoWidget/Info.plist + properties: + NSExtension: + NSExtensionPointIdentifier: com.apple.widgetkit-extension + NSSupportsLiveActivities: true + NSSupportsLiveActivitiesFrequentUpdates: true settings: base: PRODUCT_BUNDLE_IDENTIFIER: fr.millianlmx.tabatago.widget -- 2.49.1 From f5a36f0a26a0493b448b74cb00c588d63c845339 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 19:25:50 +0200 Subject: [PATCH 10/11] fix: add NSSupportsLiveActivities to main app target + cleanup info plists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout de NSSupportsLiveActivities et NSSupportsLiveActivitiesFrequentUpdates dans info.properties du target TabataGo (project.yml) — corrige l'erreur 'Target does not include NSSupportsLiveActivities plist key' au runtime - Nettoie Info.plist (retire CFBundleURLTypes, UIBackgroundModes redondants) - Aligne les entitlements (retire aps-environment, ajoute app groups) - Corrige le bundle version du widget (2 → 1) --- tabatago-swift/TabataGo/Resources/Info.plist | 13 ------------- .../TabataGo/Resources/TabataGo.entitlements | 6 +++--- tabatago-swift/TabataGoWidget/Info.plist | 4 +--- tabatago-swift/project.yml | 2 ++ 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/tabatago-swift/TabataGo/Resources/Info.plist b/tabatago-swift/TabataGo/Resources/Info.plist index 36ae005..6284a87 100644 --- a/tabatago-swift/TabataGo/Resources/Info.plist +++ b/tabatago-swift/TabataGo/Resources/Info.plist @@ -18,15 +18,6 @@ APPL CFBundleShortVersionString 1.0 - CFBundleURLTypes - - - CFBundleURLSchemes - - tabatago - - - CFBundleVersion 2 NSHealthShareUsageDescription @@ -39,10 +30,6 @@ NSSupportsLiveActivitiesFrequentUpdates - UIBackgroundModes - - audio - POSTHOG_API_KEY $(POSTHOG_API_KEY) REVENUECAT_API_KEY diff --git a/tabatago-swift/TabataGo/Resources/TabataGo.entitlements b/tabatago-swift/TabataGo/Resources/TabataGo.entitlements index 7169ba0..c722533 100644 --- a/tabatago-swift/TabataGo/Resources/TabataGo.entitlements +++ b/tabatago-swift/TabataGo/Resources/TabataGo.entitlements @@ -8,9 +8,9 @@ health-records - aps-environment - development com.apple.security.application-groups - + + group.fr.millianlmx.tabatago + diff --git a/tabatago-swift/TabataGoWidget/Info.plist b/tabatago-swift/TabataGoWidget/Info.plist index b64cae1..5372fa0 100644 --- a/tabatago-swift/TabataGoWidget/Info.plist +++ b/tabatago-swift/TabataGoWidget/Info.plist @@ -4,8 +4,6 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - TabataGoWidget CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -19,7 +17,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 2 + 1 NSExtension NSExtensionPointIdentifier diff --git a/tabatago-swift/project.yml b/tabatago-swift/project.yml index 24cecad..9540850 100644 --- a/tabatago-swift/project.yml +++ b/tabatago-swift/project.yml @@ -60,6 +60,8 @@ targets: SUPABASE_ANON_KEY: $(SUPABASE_ANON_KEY) REVENUECAT_API_KEY: $(REVENUECAT_API_KEY) POSTHOG_API_KEY: $(POSTHOG_API_KEY) + NSSupportsLiveActivities: true + NSSupportsLiveActivitiesFrequentUpdates: true entitlements: path: TabataGo/Resources/TabataGo.entitlements properties: -- 2.49.1 From 316dab2f9ca730fc886aa171eb65f0c0216ae084 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Sat, 4 Jul 2026 19:35:14 +0200 Subject: [PATCH 11/11] fix: restore UIBackgroundModes audio for background playback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Restaure UIBackgroundModes[audio] dans Info.plist (supprimé par erreur au commit précédent) → empêche iOS de suspendre l'app en arrière-plan - Ajoute UIBackgroundModes dans project.yml pour robustesse --- tabatago-swift/TabataGo/Resources/Info.plist | 4 ++++ tabatago-swift/project.yml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/tabatago-swift/TabataGo/Resources/Info.plist b/tabatago-swift/TabataGo/Resources/Info.plist index 6284a87..38f2537 100644 --- a/tabatago-swift/TabataGo/Resources/Info.plist +++ b/tabatago-swift/TabataGo/Resources/Info.plist @@ -30,6 +30,10 @@ NSSupportsLiveActivitiesFrequentUpdates + UIBackgroundModes + + audio + POSTHOG_API_KEY $(POSTHOG_API_KEY) REVENUECAT_API_KEY diff --git a/tabatago-swift/project.yml b/tabatago-swift/project.yml index 9540850..0fe03fe 100644 --- a/tabatago-swift/project.yml +++ b/tabatago-swift/project.yml @@ -62,6 +62,8 @@ targets: POSTHOG_API_KEY: $(POSTHOG_API_KEY) NSSupportsLiveActivities: true NSSupportsLiveActivitiesFrequentUpdates: true + UIBackgroundModes: + - audio entitlements: path: TabataGo/Resources/TabataGo.entitlements properties: -- 2.49.1