warm_alarm_ios
The iOS implementation of warm_alarm.
This package is endorsed, which means you do not add it directly to your
pubspec.yaml. It is automatically included when you depend on warm_alarm.
Platform capabilities
| Feature | Support | Notes |
|---|---|---|
| Notification scheduling | ✅ Full | UNUserNotificationCenter |
| Exact alarm scheduling | ⚠️ Limited | Notification-based; system may throttle background launch |
| Background audio playback | ⚠️ Limited | AVAudioSession .playback category; Silent mode bypass |
| Full-screen presentation | ❌ None | Full-screen intent is not supported; notification only |
| Wake-check | ❌ None | iOS cannot self-trigger background wakes after dismissal |
⚠️ Limited means the alarm fires via a UNUserNotificationCenter notification. The app is not
guaranteed to launch automatically in the background — audio plays only after the user interacts
with the notification (or if the app is already in the foreground).
Native implementation
Scheduling
Alarms are scheduled as UNNotificationRequest objects via UNUserNotificationCenter. The
UNCalendarNotificationTrigger fires at the exact scheduledAt time (subject to the operating
system's throttling policy for background notification delivery).
Audio
When the notification action is handled, WarmAlarmDelegate starts AVAudioPlayer with the
configured audio source (a local file path or a Flutter asset). If neither is provided, no in-app
audio is played — the notification itself still plays the bundled alarm_ring.caf (or the system
default) sound. The AVAudioSession category is set to .playback (with .mixWithOthers) so the
audio continues even when the device is in Silent mode. An optional fade-in is applied by scheduling
discrete volume steps as DispatchWorkItems (via DispatchQueue.main.asyncAfter), not a periodic
timer.
Recurrence
Weekly recurrence is delivered natively: one UNCalendarNotificationTrigger(repeats: true) is
registered per selected weekday, matching DateComponents(weekday, hour, minute), keyed
"{id}#{isoWeekday}". The series recurs without any re-arm and survives app termination. ISO
weekdays (1 = Mon … 7 = Sun) are mapped to Apple's Calendar weekdays (1 = Sun … 7 = Sat).
Dismissing an alarm ends only the current occurrence; cancelAlarm(id) removes every per-weekday
request and tears down the series. Note: each recurring alarm consumes up to 7 of iOS's 64
pending-notification slots.
Kill warning
setKillWarning(title, body) stores a warning message. If the app is backgrounded while an alarm is
ringing, the plugin posts a non-actionable notification warning the user not to force-quit the app.
clearKillWarning() removes the stored message; the pending notification is auto-dismissed when the
app returns to the foreground.
Events emitted
iOS emits a subset of the full event hierarchy — only events that are achievable within the notification delivery model:
WarmAlarmScheduledWarmAlarmFiredWarmAlarmStoppedWarmAlarmSnoozedWarmAlarmFailed
Wake-check events (WarmAlarmWakeCheckShown, WarmAlarmWakeCheckDismissed,
WarmAlarmWakeCheckExpired, WarmAlarmRetriggered) are not emitted on iOS.
Pigeon wire layer
All Dart ↔ Swift communication is generated by Pigeon. The schema lives in
pigeons/messages.dart; generated outputs (Messages.g.swift, lib/src/messages.g.dart) are
never hand-edited. Run melos run generate after any schema change.
License
BSD-3-Clause — Copyright (c) 2026, Dongmin Yu. See LICENSE for details.