Skip to content

Commit 0ded288

Browse files
utsapoddarclaude
andcommitted
Fix background/locked/in-call alarm audio (v1.0.8)
- audioplayers now uses AVAudioSessionCategory.playback on iOS so alarm plays through speaker when app is backgrounded or screen is locked - restartAudioEngineIfNeeded uses timerAudioActive flag so silent loop correctly restarts after a phone call ends - Notifications set to timeSensitive to break through Focus/DND Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d60b0ed commit 0ded288

5 files changed

Lines changed: 14 additions & 9 deletions

File tree

work_timer/ios/Runner/AppDelegate.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct SiftActivityAttributes: ActivityAttributes {
2626
// Silent keep-alive loop — keeps app alive in background while timer runs
2727
private let audioEngine = AVAudioEngine()
2828
private let silentNode = AVAudioPlayerNode()
29+
private var timerAudioActive = false
2930

3031
override func application(
3132
_ application: UIApplication,
@@ -91,7 +92,7 @@ struct SiftActivityAttributes: ActivityAttributes {
9192
}
9293

9394
private func restartAudioEngineIfNeeded() {
94-
guard silentNode.isPlaying || audioEngine.isRunning else { return }
95+
guard timerAudioActive else { return }
9596
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
9697
guard let self = self else { return }
9798
try? AVAudioSession.sharedInstance().setActive(true)
@@ -205,6 +206,7 @@ struct SiftActivityAttributes: ActivityAttributes {
205206
}
206207

207208
private func startTimerAudio() {
209+
timerAudioActive = true
208210
guard !audioEngine.isRunning else { return }
209211
// Build a 0.5s silent buffer and loop it — keeps app alive in background
210212
// so Timer.periodic keeps firing and the alarm can play even on silent
@@ -223,6 +225,7 @@ struct SiftActivityAttributes: ActivityAttributes {
223225
}
224226

225227
private func stopTimerAudio() {
228+
timerAudioActive = false
226229
silentNode.stop()
227230
audioEngine.stop()
228231
}

work_timer/lib/services/audio.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ Future<void> playAlarm() async {
2121
stayAwake: false,
2222
),
2323
));
24+
} else if (Platform.isIOS) {
25+
await _player.setAudioContext(AudioContext(
26+
iOS: AudioContextIOS(
27+
category: AVAudioSessionCategory.playback,
28+
options: const {},
29+
),
30+
));
2431
}
2532
final custom = customRingtonePath;
2633
if (custom != null && custom.isNotEmpty && File(custom).existsSync()) {

work_timer/lib/services/notifications.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Future<void> scheduleAll(Schedule schedule, {int offsetMs = 0}) async {
124124
// alarm.caf is copied to Library/Sounds at app launch in AppDelegate
125125
sound: 'alarm.caf',
126126
categoryIdentifier: 'timer_alert',
127+
interruptionLevel: InterruptionLevel.timeSensitive,
127128
),
128129
macOS: const DarwinNotificationDetails(
129130
presentAlert: true,

work_timer/macos/Podfile.lock

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ PODS:
66
- FlutterMacOS
77
- flutter_local_notifications (0.0.1):
88
- FlutterMacOS
9-
- flutter_timezone (0.1.0):
10-
- FlutterMacOS
119
- FlutterMacOS (1.0.0)
1210
- shared_preferences_foundation (0.0.1):
1311
- Flutter
@@ -17,7 +15,6 @@ DEPENDENCIES:
1715
- audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/darwin`)
1816
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
1917
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
20-
- flutter_timezone (from `Flutter/ephemeral/.symlinks/plugins/flutter_timezone/macos`)
2118
- FlutterMacOS (from `Flutter/ephemeral`)
2219
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
2320

@@ -28,8 +25,6 @@ EXTERNAL SOURCES:
2825
:path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos
2926
flutter_local_notifications:
3027
:path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos
31-
flutter_timezone:
32-
:path: Flutter/ephemeral/.symlinks/plugins/flutter_timezone/macos
3328
FlutterMacOS:
3429
:path: Flutter/ephemeral
3530
shared_preferences_foundation:
@@ -38,8 +33,7 @@ EXTERNAL SOURCES:
3833
SPEC CHECKSUMS:
3934
audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5
4035
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
41-
flutter_local_notifications: 13862b132e32eb858dea558a86d45d08daeacfe7
42-
flutter_timezone: d272288c69082ad571630e0d17140b3d6b93dc0c
36+
flutter_local_notifications: 1fc7ffb10a83d6a2eeeeddb152d43f1944b0aad0
4337
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
4438
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
4539

work_timer/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: work_timer
22
description: "Work session timer with automatic break scheduling."
33
publish_to: 'none'
44

5-
version: 1.0.7+7
5+
version: 1.0.8+8
66

77
environment:
88
sdk: ^3.11.3

0 commit comments

Comments
 (0)