alarmkit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAlarmKit
AlarmKit
Schedule prominent alarms and countdown timers that surface on the Lock Screen,
Dynamic Island, and Apple Watch. AlarmKit requires iOS 26+ / iPadOS 26+. Alarms override
Focus and Silent mode automatically.
AlarmKit builds on Live Activities -- every alarm creates a system-managed Live
Activity with templated UI. You configure the presentation via
and rather than building custom widget views.
AlarmAttributesAlarmPresentationSee for complete code patterns including
authorization, scheduling, countdown timers, snooze handling, and widget setup.
references/alarmkit-patterns.mdswift
import AlarmKit在锁屏、灵动岛(Dynamic Island)和Apple Watch上显示醒目的闹钟和倒计时器。AlarmKit要求iOS 26+ / iPadOS 26+系统版本。闹钟会自动覆盖专注模式和静音模式。
AlarmKit 基于Live Activity构建——每个闹钟都会创建一个由系统管理的Live Activity,并使用模板化UI。你可以通过和配置展示效果,无需构建自定义Widget视图。
AlarmAttributesAlarmPresentation完整的代码模式(包括授权、调度、倒计时器、贪睡处理和Widget设置)请参考。
references/alarmkit-patterns.mdswift
import AlarmKitContents
目录
Workflow
工作流程
1. Create a new alarm or timer
1. 创建新闹钟或计时器
- Add to Info.plist with a user-facing string.
NSAlarmKitUsageDescription - Request authorization with .
AlarmManager.shared.requestAuthorization() - Configure (alert, countdown, paused states).
AlarmPresentation - Create with the presentation, optional metadata, and tint color.
AlarmAttributes - Build an (.alarm or .timer).
AlarmManager.AlarmConfiguration - Schedule with .
AlarmManager.shared.schedule(id:configuration:) - Observe state changes via .
alarmManager.alarmUpdates - If using countdown, add a widget extension target for non-alerting Live Activity UI.
- 在Info.plist中添加字段,并填写面向用户的说明字符串。
NSAlarmKitUsageDescription - 调用请求授权。
AlarmManager.shared.requestAuthorization() - 配置(提醒、倒计时、暂停状态)。
AlarmPresentation - 创建包含展示配置、可选元数据和色调的。
AlarmAttributes - 构建(选择
AlarmManager.AlarmConfiguration或.alarm类型)。.timer - 调用进行调度。
AlarmManager.shared.schedule(id:configuration:) - 通过监听状态变化。
alarmManager.alarmUpdates - 如果使用倒计时功能,需添加Widget扩展目标以支持非提醒状态的Live Activity UI。
2. Review existing alarm code
2. 审查现有闹钟代码
Run through the Review Checklist at the end of this document.
按照本文档末尾的检查清单进行审查。
Authorization
授权
AlarmKit requires explicit user authorization. Without it, alarms silently
fail to schedule. Request early (e.g., at onboarding) or let AlarmKit prompt
automatically on first schedule.
swift
let manager = AlarmManager.shared
// Request authorization explicitly
let state = try await manager.requestAuthorization()
guard state == .authorized else { return }
// Check current state synchronously
let current = manager.authorizationState // .authorized, .denied, .notDetermined
// Observe authorization changes
for await state in manager.authorizationUpdates {
switch state {
case .authorized: print("Alarms enabled")
case .denied: print("Alarms disabled")
case .notDetermined: break
@unknown default: break
}
}AlarmKit需要用户明确授权。未授权情况下,闹钟会静默调度失败。建议在应用引导阶段提前请求授权,或让AlarmKit在首次调度时自动提示用户。
swift
let manager = AlarmManager.shared
// 主动请求授权
let state = try await manager.requestAuthorization()
guard state == .authorized else { return }
// 同步检查当前授权状态
let current = manager.authorizationState // .authorized, .denied, .notDetermined
// 监听授权状态变化
for await state in manager.authorizationUpdates {
switch state {
case .authorized: print("闹钟功能已启用")
case .denied: print("闹钟功能已禁用")
case .notDetermined: break
@unknown default: break
}
}Alarm vs Timer Decision
闹钟与计时器的选择
| Feature | Alarm ( | Timer ( |
|---|---|---|
| Fires at | Specific time (schedule) | After duration elapses |
| Countdown UI | Optional | Always shown |
| Recurring | Yes (weekly days) | No |
| Use case | Wake-up, scheduled reminders | Cooking, workout intervals |
Use when firing at a clock time. Use
when firing after a duration from now.
.alarm(schedule:...).timer(duration:...)| 特性 | 闹钟( | 计时器( |
|---|---|---|
| 触发时机 | 特定时间(按调度) | 时长结束后 |
| 倒计时UI | 可选 | 始终显示 |
| 重复触发 | 支持(每周重复) | 不支持 |
| 使用场景 | 唤醒闹钟、定时提醒 | 烹饪计时、锻炼间隔 |
当需要在特定时钟时间触发时,使用;当需要从当前时间开始计时一段时间后触发时,使用。
.alarm(schedule:...).timer(duration:...)Scheduling Alarms
调度闹钟
Alarm.Schedule
Alarm.Schedule
Alarms use to define when they fire.
Alarm.Scheduleswift
// Fixed: fire at an exact Date (one-time only)
let fixed: Alarm.Schedule = .fixed(myDate)
// Relative one-time: fire at 7:30 AM in device time zone, no repeat
let oneTime: Alarm.Schedule = .relative(.init(
time: .init(hour: 7, minute: 30),
repeats: .never
))
// Recurring: fire at 6:00 AM on weekdays
let weekday: Alarm.Schedule = .relative(.init(
time: .init(hour: 6, minute: 0),
repeats: .weekly([.monday, .tuesday, .wednesday, .thursday, .friday])
))闹钟使用定义触发时间。
Alarm.Scheduleswift
// 固定时间:在指定的Date触发(仅一次)
let fixed: Alarm.Schedule = .fixed(myDate)
// 相对单次触发:在设备时区的早上7:30触发,不重复
let oneTime: Alarm.Schedule = .relative(.init(
time: .init(hour: 7, minute: 30),
repeats: .never
))
// 重复触发:工作日早上6:00触发
let weekday: Alarm.Schedule = .relative(.init(
time: .init(hour: 6, minute: 0),
repeats: .weekly([.monday, .tuesday, .wednesday, .thursday, .friday])
))Schedule and Configure
调度与配置
swift
let id = UUID()
let configuration = AlarmManager.AlarmConfiguration.alarm(
schedule: .relative(.init(
time: .init(hour: 7, minute: 0),
repeats: .never
)),
attributes: attributes,
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
secondaryIntent: SnoozeIntent(alarmID: id.uuidString),
sound: .default
)
let alarm = try await AlarmManager.shared.schedule(
id: id,
configuration: configuration
)swift
let id = UUID()
let configuration = AlarmManager.AlarmConfiguration.alarm(
schedule: .relative(.init(
time: .init(hour: 7, minute: 0),
repeats: .never
)),
attributes: attributes,
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
secondaryIntent: SnoozeIntent(alarmID: id.uuidString),
sound: .default
)
let alarm = try await AlarmManager.shared.schedule(
id: id,
configuration: configuration
)Alarm State Transitions
闹钟状态转换
text
cancel(id:)
|
scheduled --> countdown --> alerting
| | |
| pause(id:) stop(id:) / countdown(id:)
| |
| paused ----> countdown (via resume(id:))
|
cancel(id:) removes from system entirely- -- remove the alarm completely (any state)
cancel(id:) - -- pause a counting-down alarm
pause(id:) - -- resume a paused alarm
resume(id:) - -- stop an alerting alarm
stop(id:) - -- restart countdown from alerting state (snooze)
countdown(id:)
text
cancel(id:)
|
scheduled --> countdown --> alerting
| | |
| pause(id:) stop(id:) / countdown(id:)
| |
| paused ----> countdown (via resume(id:))
|
cancel(id:) removes from system entirely- -- 完全移除闹钟(任何状态下均可)
cancel(id:) - -- 暂停正在倒计时的闹钟
pause(id:) - -- 恢复暂停的闹钟
resume(id:) - -- 停止正在提醒的闹钟
stop(id:) - -- 从提醒状态重启倒计时(贪睡)
countdown(id:)
Countdown Timers
倒计时器
Timers fire after a duration and always show a countdown UI. Use
to control pre-alert and post-alert durations.
Alarm.CountdownDurationswift
// Simple timer: 5-minute countdown, no snooze
let timerConfig = AlarmManager.AlarmConfiguration.timer(
duration: 300,
attributes: attributes,
stopIntent: StopTimerIntent(timerID: id.uuidString),
sound: .default
)
let alarm = try await AlarmManager.shared.schedule(
id: UUID(),
configuration: timerConfig
)计时器在时长结束后触发,且始终显示倒计时UI。使用控制提醒前和提醒后的时长。
Alarm.CountdownDurationswift
// 简单计时器:5分钟倒计时,无贪睡
let timerConfig = AlarmManager.AlarmConfiguration.timer(
duration: 300,
attributes: attributes,
stopIntent: StopTimerIntent(timerID: id.uuidString),
sound: .default
)
let alarm = try await AlarmManager.shared.schedule(
id: UUID(),
configuration: timerConfig
)CountdownDuration
CountdownDuration
Alarm.CountdownDuration- -- seconds to count down before the alarm fires (the main countdown)
preAlert - -- seconds for a repeat/snooze countdown after the alarm fires
postAlert
swift
let countdown = Alarm.CountdownDuration(
preAlert: 600, // 10-minute countdown before alert
postAlert: 300 // 5-minute snooze countdown if user taps Repeat
)
let config = AlarmManager.AlarmConfiguration(
countdownDuration: countdown,
schedule: .relative(.init(
time: .init(hour: 8, minute: 0),
repeats: .never
)),
attributes: attributes,
stopIntent: stopIntent,
secondaryIntent: snoozeIntent,
sound: .default
)Alarm.CountdownDuration- -- 闹钟触发前的倒计时秒数(主倒计时)
preAlert - -- 闹钟触发后,重复/贪睡的倒计时秒数
postAlert
swift
let countdown = Alarm.CountdownDuration(
preAlert: 600, // 提醒前10分钟倒计时
postAlert: 300 // 用户点击重复后,5分钟贪睡倒计时
)
let config = AlarmManager.AlarmConfiguration(
countdownDuration: countdown,
schedule: .relative(.init(
time: .init(hour: 8, minute: 0),
repeats: .never
)),
attributes: attributes,
stopIntent: stopIntent,
secondaryIntent: snoozeIntent,
sound: .default
)Alarm States
闹钟状态
Each has a property reflecting its current lifecycle position.
Alarmstate| State | Meaning |
|---|---|
| Waiting to fire (alarm mode) or waiting to start countdown |
| Actively counting down (timer or pre-alert phase) |
| Countdown paused by user or app |
| Alarm is firing -- sound playing, UI prominent |
每个都有一个属性,反映其当前生命周期阶段。
Alarmstate| 状态 | 含义 |
|---|---|
| 等待触发(闹钟模式)或等待开始倒计时 |
| 正在倒计时(计时器或提醒前阶段) |
| 倒计时被用户或应用暂停 |
| 闹钟正在提醒——播放声音,UI醒目显示 |
Observing State Changes
监听状态变化
swift
let manager = AlarmManager.shared
// Get all current alarms
let alarms = manager.alarms
// Observe changes as an async sequence
for await updatedAlarms in manager.alarmUpdates {
for alarm in updatedAlarms {
switch alarm.state {
case .scheduled: print("\(alarm.id) waiting")
case .countdown: print("\(alarm.id) counting down")
case .paused: print("\(alarm.id) paused")
case .alerting: print("\(alarm.id) alerting!")
@unknown default: break
}
}
}An alarm that disappears from has been cancelled or fully stopped
and is no longer tracked by the system.
alarmUpdatesswift
let manager = AlarmManager.shared
// 获取所有当前闹钟
let alarms = manager.alarms
// 通过异步序列监听变化
for await updatedAlarms in manager.alarmUpdates {
for alarm in updatedAlarms {
switch alarm.state {
case .scheduled: print("\(alarm.id) 等待中")
case .countdown: print("\(alarm.id) 倒计时中")
case .paused: print("\(alarm.id) 已暂停")
case .alerting: print("\(alarm.id) 正在提醒!")
@unknown default: break
}
}
}从中消失的闹钟表示已被取消或完全停止,不再被系统跟踪。
alarmUpdatesAlarmAttributes and AlarmPresentation
AlarmAttributes与AlarmPresentation
AlarmAttributesActivityAttributesMetadataAlarmMetadataAlarmAttributesActivityAttributesAlarmMetadataMetadataAlarmPresentation
AlarmPresentation
Defines the UI content for each alarm state. The system renders a templated
Live Activity using this data -- you do not build custom SwiftUI views for the
alarm itself.
swift
// Alert state (required) -- shown when alarm is firing
let alert = AlarmPresentation.Alert(
title: "Wake Up",
secondaryButton: AlarmButton(
text: "Snooze",
textColor: .white,
systemImageName: "bell.slash"
),
secondaryButtonBehavior: .countdown // snooze restarts countdown
)
// Countdown state (optional) -- shown during pre-alert countdown
let countdown = AlarmPresentation.Countdown(
title: "Morning Alarm",
pauseButton: AlarmButton(
text: "Pause",
textColor: .orange,
systemImageName: "pause.fill"
)
)
// Paused state (optional) -- shown when countdown is paused
let paused = AlarmPresentation.Paused(
title: "Paused",
resumeButton: AlarmButton(
text: "Resume",
textColor: .green,
systemImageName: "play.fill"
)
)
let presentation = AlarmPresentation(
alert: alert,
countdown: countdown,
paused: paused
)定义每个闹钟状态下的UI内容。系统会使用这些数据渲染模板化的Live Activity——你无需为闹钟本身构建自定义SwiftUI视图。
swift
// 提醒状态(必填)——闹钟触发时显示
let alert = AlarmPresentation.Alert(
title: "起床",
secondaryButton: AlarmButton(
text: "贪睡",
textColor: .white,
systemImageName: "bell.slash"
),
secondaryButtonBehavior: .countdown // 贪睡会重启倒计时
)
// 倒计时状态(可选)——提醒前倒计时阶段显示
let countdown = AlarmPresentation.Countdown(
title: "晨间闹钟",
pauseButton: AlarmButton(
text: "暂停",
textColor: .orange,
systemImageName: "pause.fill"
)
)
// 暂停状态(可选)——倒计时暂停时显示
let paused = AlarmPresentation.Paused(
title: "已暂停",
resumeButton: AlarmButton(
text: "恢复",
textColor: .green,
systemImageName: "play.fill"
)
)
let presentation = AlarmPresentation(
alert: alert,
countdown: countdown,
paused: paused
)AlarmAttributes
AlarmAttributes
swift
struct CookingMetadata: AlarmMetadata {
var recipeName: String
var stepNumber: Int
}
let attributes = AlarmAttributes(
presentation: presentation,
metadata: CookingMetadata(recipeName: "Pasta", stepNumber: 3),
tintColor: .blue
)swift
struct CookingMetadata: AlarmMetadata {
var recipeName: String
var stepNumber: Int
}
let attributes = AlarmAttributes(
presentation: presentation,
metadata: CookingMetadata(recipeName: "意面", stepNumber: 3),
tintColor: .blue
)AlarmPresentationState
AlarmPresentationState
AlarmPresentationStateContentStateMode- -- alarm is firing, includes the scheduled time
.alert(Alert) - -- actively counting down, includes fire date and durations
.countdown(Countdown) - -- countdown paused, includes elapsed and total durations
.paused(Paused)
The widget extension reads to decide which UI to
render in the Dynamic Island and Lock Screen for non-alerting states.
AlarmPresentationState.modeAlarmPresentationStateContentStateMode- -- 闹钟正在提醒,包含调度时间
.alert(Alert) - -- 正在倒计时,包含触发日期和时长
.countdown(Countdown) - -- 倒计时已暂停,包含已流逝时长和总时长
.paused(Paused)
Widget扩展通过读取来决定在灵动岛和锁屏上为非提醒状态渲染何种UI。
AlarmPresentationState.modeAlarmButton
AlarmButton
AlarmButtonswift
let stopButton = AlarmButton(
text: "Stop",
textColor: .red,
systemImageName: "stop.fill"
)
let snoozeButton = AlarmButton(
text: "Snooze",
textColor: .white,
systemImageName: "bell.slash"
)AlarmButtonswift
let stopButton = AlarmButton(
text: "停止",
textColor: .red,
systemImageName: "stop.fill"
)
let snoozeButton = AlarmButton(
text: "贪睡",
textColor: .white,
systemImageName: "bell.slash"
)Secondary Button Behavior
次要按钮行为
The secondary button on the alert UI has two behaviors:
| Behavior | Effect |
|---|---|
| Restarts a countdown using |
| Triggers the |
提醒UI上的次要按钮有两种行为:
| 行为 | 效果 |
|---|---|
| 使用 |
| 触发 |
Live Activity Integration
Live Activity集成
AlarmKit alarms automatically appear as Live Activities on the Lock Screen
and Dynamic Island on iPhone, and in the Smart Stack on Apple Watch. The
system manages the alerting UI. For countdown and paused states, add a
widget extension that reads and .
AlarmAttributesAlarmPresentationStateA widget extension is required if your alarm uses countdown presentation.
Without it, the system may dismiss alarms unexpectedly.
swift
struct AlarmWidgetBundle: WidgetBundle {
var body: some Widget {
AlarmActivityWidget()
}
}
struct AlarmActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: AlarmAttributes<CookingMetadata>.self) { context in
// Lock Screen presentation for countdown/paused states
AlarmLockScreenView(context: context)
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.center) {
Text(context.attributes.presentation.alert.title)
}
DynamicIslandExpandedRegion(.bottom) {
// Show countdown or paused info based on mode
AlarmExpandedView(state: context.state)
}
} compactLeading: {
Image(systemName: "alarm.fill")
} compactTrailing: {
AlarmCompactTrailing(state: context.state)
} minimal: {
Image(systemName: "alarm.fill")
}
}
}
}AlarmKit闹钟会自动在iPhone的锁屏和灵动岛、Apple Watch的智能叠放中以Live Activity形式显示。系统管理提醒UI。对于倒计时和暂停状态,需添加Widget扩展来读取和。
AlarmAttributesAlarmPresentationState如果你的闹钟使用倒计时展示,必须添加Widget扩展。否则系统可能会意外取消闹钟。
swift
struct AlarmWidgetBundle: WidgetBundle {
var body: some Widget {
AlarmActivityWidget()
}
}
struct AlarmActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: AlarmAttributes<CookingMetadata>.self) { context in
// 倒计时/暂停状态的锁屏展示
AlarmLockScreenView(context: context)
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.center) {
Text(context.attributes.presentation.alert.title)
}
DynamicIslandExpandedRegion(.bottom) {
// 根据模式显示倒计时或暂停信息
AlarmExpandedView(state: context.state)
}
} compactLeading: {
Image(systemName: "alarm.fill")
} compactTrailing: {
AlarmCompactTrailing(state: context.state)
} minimal: {
Image(systemName: "alarm.fill")
}
}
}
}Common Mistakes
常见错误
DON'T: Forget in Info.plist.
DO: Add a descriptive usage string. Without it, AlarmKit cannot schedule alarms at all.
NSAlarmKitUsageDescriptionDON'T: Skip authorization and assume alarms will schedule.
DO: Call early and handle gracefully.
requestAuthorization().deniedDON'T: Use when you need a recurring schedule.
DO: Use with for recurring alarms. Timers are one-shot.
.timer.alarm.weekly([...])DON'T: Omit the widget extension when using countdown presentation.
DO: Add a widget extension target. AlarmKit requires it for countdown/paused Live Activity UI.
Why: Without a widget extension, the system may dismiss alarms before they alert.
DON'T: Ignore and track alarm state manually.
DO: Observe to stay synchronized with the system.
Why: Alarm state can change while your app is backgrounded.
alarmUpdatesalarmManager.alarmUpdatesDON'T: Forget to provide a -- it cannot be nil in practice.
DO: Always provide a for stop so the button performs cleanup.
stopIntentLiveActivityIntentDON'T: Store large data in . It is serialized with the Live Activity.
DO: Keep metadata lightweight. Store large data in your app and reference by ID.
AlarmMetadataDON'T: Use deprecated parameter on .
DO: Use the current initializer.
stopButtonAlarmPresentation.Alertinit(title:secondaryButton:secondaryButtonBehavior:)不要: 忘记在Info.plist中添加。
要: 添加描述性的使用说明字符串。没有它,AlarmKit根本无法调度闹钟。
NSAlarmKitUsageDescription不要: 跳过授权流程,默认认为闹钟会调度成功。
要: 尽早调用,并在UI中优雅处理状态。
requestAuthorization().denied不要: 当需要重复调度时使用。
要: 使用搭配实现重复闹钟。计时器仅支持单次触发。
.timer.alarm.weekly([...])不要: 使用倒计时展示时省略Widget扩展。
要: 添加Widget扩展目标。AlarmKit需要它来支持倒计时/暂停状态的Live Activity UI。
原因: 没有Widget扩展,系统可能在闹钟触发前就将其取消。
不要: 忽略,手动跟踪闹钟状态。
要: 监听以与系统状态保持同步。
原因: 应用在后台时,闹钟状态可能会发生变化。
alarmUpdatesalarmManager.alarmUpdates不要: 忘记提供——实际上它不能为nil。
要: 始终为停止操作提供实现,以便按钮执行清理操作。
stopIntentLiveActivityIntent不要: 在中存储大量数据。它会与Live Activity一起序列化。
要: 保持元数据轻量化。将大量数据存储在应用中,通过ID引用即可。
AlarmMetadata不要: 使用中已弃用的参数。
要: 使用当前的初始化方法。
AlarmPresentation.AlertstopButtoninit(title:secondaryButton:secondaryButtonBehavior:)Review Checklist
检查清单
- present in Info.plist with non-empty string
NSAlarmKitUsageDescription - Authorization requested and state handled in UI
.denied - covers all relevant states (alert, countdown, paused)
AlarmPresentation - Widget extension target added if countdown presentation is used
- metadata type conforms to
AlarmAttributesAlarmMetadata - Alarm ID stored for later cancel/pause/resume/stop operations
- async sequence observed to track state changes
alarmUpdates - and
stopIntentare validsecondaryIntentimplementationsLiveActivityIntent - duration set on
postAlertif snooze (CountdownDurationbehavior) is used.countdown - Tint color set on to differentiate from other apps
AlarmAttributes - Error handling for
AlarmManager.AlarmError.maximumLimitReached - Tested on device (alarm sound/vibration differs from Simulator)
- Info.plist中存在且字符串非空
NSAlarmKitUsageDescription - 已请求授权,并在UI中处理状态
.denied - 覆盖了所有相关状态(提醒、倒计时、暂停)
AlarmPresentation - 如果使用倒计时展示,已添加Widget扩展目标
- 的元数据类型遵循
AlarmAttributes协议AlarmMetadata - 已存储闹钟ID,用于后续的取消/暂停/恢复/停止操作
- 已监听异步序列以跟踪状态变化
alarmUpdates - 和
stopIntent是有效的secondaryIntent实现LiveActivityIntent - 如果使用贪睡(行为),已在
.countdown中设置CountdownDuration时长postAlert - 已在中设置色调,以与其他应用区分
AlarmAttributes - 已处理错误
AlarmManager.AlarmError.maximumLimitReached - 已在真机上测试(闹钟声音/振动与模拟器不同)
References
参考资料
- Patterns and code:
references/alarmkit-patterns.md - Apple docs: AlarmKit | AlarmManager | AlarmAttributes | Scheduling an alarm
- 模式与代码:
references/alarmkit-patterns.md - Apple文档:AlarmKit | AlarmManager | AlarmAttributes | Scheduling an alarm