axiom-alarmkit-ref

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AlarmKit Reference

AlarmKit 参考文档

Complete API reference for AlarmKit, Apple's framework for scheduling alarms and countdown timers with system-level alerting, Dynamic Island integration, and focus/silent mode override.
Apple官方AlarmKit框架的完整API参考,该框架用于设置闹钟和倒计时计时器,支持系统级提醒、Dynamic Island集成,以及绕过专注/静音模式。

Overview

概述

AlarmKit lets apps create alarms and timers that behave like the built-in Clock app -- they override Do Not Disturb, appear in the Dynamic Island, and show on the Lock Screen. The framework handles scheduling, snooze, pause/resume, and UI presentation through a small set of types centered on
AlarmManager
.
AlarmKit允许应用创建与系统自带“时钟”App行为一致的闹钟和计时器——它们可以绕过“请勿打扰”模式、显示在Dynamic Island中,还能在锁屏界面展示。该框架通过以
AlarmManager
为核心的少量类型,处理调度、贪睡、暂停/恢复以及UI展示等操作。

System Requirements

系统要求

  • iOS 26+ (AlarmKit introduced in iOS 26)
  • Widget Extension required for Live Activity / Dynamic Island presentation
  • Physical device recommended for alarm sound and notification testing

  • iOS 26+(AlarmKit在iOS 26中首次推出)
  • Widget Extension:实现Live Activity / Dynamic Island展示的必要组件
  • 物理设备:推荐用于测试闹钟声音和通知

Part 1: Key Components

第一部分:核心组件

AlarmManager

AlarmManager

Singleton entry point for all alarm operations.
swift
import AlarmKit

let manager = AlarmManager.shared
All scheduling, cancellation, and observation flows through this shared instance.
所有闹钟操作的单例入口。
swift
import AlarmKit

let manager = AlarmManager.shared
所有调度、取消和监听流程都通过这个共享实例完成。

Alarm

Alarm

Describes an alarm that can alert once or on a repeating schedule.
swift
struct Alarm {
    var id: UUID
    var schedule: Schedule?
    var countdownDuration: CountdownDuration?
    var state: AlarmState
}
描述可单次触发或重复触发的闹钟。
swift
struct Alarm {
    var id: UUID
    var schedule: Schedule?
    var countdownDuration: CountdownDuration?
    var state: AlarmState
}

AlarmPresentation

AlarmPresentation

Content for the alarm UI across three states -- alerting, counting down, and paused.
swift
struct AlarmPresentation {
    var alert: Alert           // Required: shown when alarm fires
    var countdown: Countdown?  // Optional: shown during countdown
    var paused: Paused?        // Optional: shown when paused
}
闹钟在三种状态下的UI内容——触发提醒、倒计时中、已暂停。
swift
struct AlarmPresentation {
    var alert: Alert           // 必填:闹钟触发时显示
    var countdown: Countdown?  // 可选:倒计时过程中显示
    var paused: Paused?        // 可选:暂停时显示
}

AlarmAttributes

AlarmAttributes

Generic container pairing presentation with app-specific metadata and tint color. Used to configure the Live Activity widget.
swift
struct AlarmAttributes<Metadata: AlarmMetadata> {
    var presentation: AlarmPresentation
    var metadata: Metadata
    var tintColor: Color
}
通用容器,用于关联展示内容、应用专属元数据和色调,配置Live Activity小组件时会用到。
swift
struct AlarmAttributes<Metadata: AlarmMetadata> {
    var presentation: AlarmPresentation
    var metadata: Metadata
    var tintColor: Color
}

AlarmMetadata

AlarmMetadata

Protocol for app-specific data attached to an alarm. Conform an empty struct for minimal usage, or add properties for richer UI.
swift
struct RecipeMetadata: AlarmMetadata {
    let recipeName: String
    let cookingStep: String
}

用于附加到闹钟的应用专属数据协议。可遵循空结构体实现基础用法,或添加属性以实现更丰富的UI。
swift
struct RecipeMetadata: AlarmMetadata {
    let recipeName: String
    let cookingStep: String
}

Part 2: Authorization

第二部分:授权

Apps must request permission before scheduling alarms. Add
NSAlarmKitUsageDescription
to Info.plist.
应用在设置闹钟前必须请求权限。需在Info.plist中添加
NSAlarmKitUsageDescription
字段。

Requesting Authorization

请求授权

swift
func requestAlarmAuthorization() async -> Bool {
    do {
        let state = try await AlarmManager.shared.requestAuthorization()
        return state == .authorized
    } catch {
        print("Authorization error: \(error)")
        return false
    }
}
swift
func requestAlarmAuthorization() async -> Bool {
    do {
        let state = try await AlarmManager.shared.requestAuthorization()
        return state == .authorized
    } catch {
        print("Authorization error: \(error)")
        return false
    }
}

Checking Current State

检查当前状态

Use
authorizationState
(not
authorizationStatus
) to read the current value:
swift
let state = await AlarmManager.shared.authorizationState
// .authorized | .denied | .notDetermined
使用
authorizationState
(而非
authorizationStatus
)读取当前权限状态:
swift
let state = await AlarmManager.shared.authorizationState
// .authorized | .denied | .notDetermined

Observing Authorization Changes

监听授权状态变化

swift
for await authState in AlarmManager.shared.authorizationUpdates {
    switch authState {
    case .authorized: enableAlarmUI()
    case .denied:     showPermissionPrompt()
    case .notDetermined: break
    @unknown default: break
    }
}

swift
for await authState in AlarmManager.shared.authorizationUpdates {
    switch authState {
    case .authorized: enableAlarmUI()
    case .denied:     showPermissionPrompt()
    case .notDetermined: break
    @unknown default: break
    }
}

Part 3: Scheduling Alarms

第三部分:设置闹钟

Every alarm requires a
UUID
, an
AlarmManager.AlarmConfiguration
, and a call to
schedule(id:configuration:)
.
每个闹钟都需要一个
UUID
、一个
AlarmManager.AlarmConfiguration
,并调用
schedule(id:configuration:)
方法。

One-Time Alarm

单次闹钟

swift
let id = UUID()
let time = Alarm.Schedule.Relative.Time(hour: 7, minute: 30)
let schedule = Alarm.Schedule.relative(.init(
    time: time,
    repeats: .never
))

let alert = AlarmPresentation.Alert(
    title: "Wake Up",
    stopButton: .stopButton,
    secondaryButton: .snoozeButton,
    secondaryButtonBehavior: .countdown
)

struct EmptyMetadata: AlarmMetadata {}
let config = AlarmManager.AlarmConfiguration(
    countdownDuration: nil,
    schedule: schedule,
    attributes: AlarmAttributes(
        presentation: AlarmPresentation(alert: alert),
        metadata: EmptyMetadata(),
        tintColor: .blue
    ),
    sound: .default
)

let alarm = try await AlarmManager.shared.schedule(id: id, configuration: config)
swift
let id = UUID()
let time = Alarm.Schedule.Relative.Time(hour: 7, minute: 30)
let schedule = Alarm.Schedule.relative(.init(
    time: time,
    repeats: .never
))

let alert = AlarmPresentation.Alert(
    title: "Wake Up",
    stopButton: .stopButton,
    secondaryButton: .snoozeButton,
    secondaryButtonBehavior: .countdown
)

struct EmptyMetadata: AlarmMetadata {}
let config = AlarmManager.AlarmConfiguration(
    countdownDuration: nil,
    schedule: schedule,
    attributes: AlarmAttributes(
        presentation: AlarmPresentation(alert: alert),
        metadata: EmptyMetadata(),
        tintColor: .blue
    ),
    sound: .default
)

let alarm = try await AlarmManager.shared.schedule(id: id, configuration: config)

Repeating Alarm

重复闹钟

Use
.weekly(Array(weekdays))
for specific days:
swift
let time = Alarm.Schedule.Relative.Time(hour: 6, minute: 0)
let schedule = Alarm.Schedule.relative(.init(
    time: time,
    repeats: .weekly([.monday, .tuesday, .wednesday, .thursday, .friday])
))
使用
.weekly(Array(weekdays))
指定重复的日期:
swift
let time = Alarm.Schedule.Relative.Time(hour: 6, minute: 0)
let schedule = Alarm.Schedule.relative(.init(
    time: time,
    repeats: .weekly([.monday, .tuesday, .wednesday, .thursday, .friday])
))

Countdown Timer

倒计时计时器

Set
schedule: nil
and provide
countdownDuration
with a
preAlert
interval:
swift
let countdown = Alarm.CountdownDuration(
    preAlert: 300,  // 5 minutes
    postAlert: 10   // Optional post-alert snooze window
)

let config = AlarmManager.AlarmConfiguration(
    countdownDuration: countdown,
    schedule: nil,
    attributes: attributes,
    sound: .default
)
Timers support pause/resume and show a countdown presentation when
AlarmPresentation.countdown
is provided.
设置
schedule: nil
并提供带有
preAlert
时间间隔的
countdownDuration
swift
let countdown = Alarm.CountdownDuration(
    preAlert: 300,  // 5分钟
    postAlert: 10   // 可选的提醒后贪睡窗口
)

let config = AlarmManager.AlarmConfiguration(
    countdownDuration: countdown,
    schedule: nil,
    attributes: attributes,
    sound: .default
)
计时器支持暂停/恢复,当提供
AlarmPresentation.countdown
时会显示倒计时界面。

Snooze Configuration

贪睡配置

Snooze uses
CountdownDuration.postAlert
combined with a
.snoozeButton
secondary action:
swift
let alert = AlarmPresentation.Alert(
    title: "Alarm",
    stopButton: .stopButton,
    secondaryButton: .snoozeButton,
    secondaryButtonBehavior: .countdown  // Starts post-alert countdown
)

let countdownDuration = Alarm.CountdownDuration(
    preAlert: nil,
    postAlert: 9 * 60  // 9-minute snooze
)

贪睡功能结合
CountdownDuration.postAlert
.snoozeButton
次要操作实现:
swift
let alert = AlarmPresentation.Alert(
    title: "Alarm",
    stopButton: .stopButton,
    secondaryButton: .snoozeButton,
    secondaryButtonBehavior: .countdown  // 启动提醒后倒计时
)

let countdownDuration = Alarm.CountdownDuration(
    preAlert: nil,
    postAlert: 9 * 60  // 9分钟贪睡
)

Part 4: Customizing Alarm UI

第四部分:自定义闹钟UI

Alert Presentation

提醒界面

The alert state is shown when the alarm fires. The stop button is required; secondary button is optional.
swift
// Minimal
let basic = AlarmPresentation.Alert(
    title: "Alarm",
    stopButton: .stopButton
)

// With custom button labels
let custom = AlarmPresentation.Alert(
    title: "Medication Reminder",
    stopButton: AlarmButton(label: "Taken"),
    secondaryButton: AlarmButton(label: "Remind Later"),
    secondaryButtonBehavior: .countdown
)

// With open-app action
let openApp = AlarmPresentation.Alert(
    title: "Workout Time",
    stopButton: .stopButton,
    secondaryButton: .openAppButton,
    secondaryButtonBehavior: .custom
)
闹钟触发时显示提醒状态。停止按钮为必填项,次要按钮为可选。
swift
// 基础版
let basic = AlarmPresentation.Alert(
    title: "Alarm",
    stopButton: .stopButton
)

// 自定义按钮标签
let custom = AlarmPresentation.Alert(
    title: "Medication Reminder",
    stopButton: AlarmButton(label: "Taken"),
    secondaryButton: AlarmButton(label: "Remind Later"),
    secondaryButtonBehavior: .countdown
)

// 带打开应用操作
let openApp = AlarmPresentation.Alert(
    title: "Workout Time",
    stopButton: .stopButton,
    secondaryButton: .openAppButton,
    secondaryButtonBehavior: .custom
)

Countdown Presentation

倒计时界面

Shown while a timer counts down. Only relevant for alarms with
countdownDuration.preAlert
.
swift
let countdown = AlarmPresentation.Countdown(
    title: "Timer Running",
    pauseButton: .pauseButton
)
计时器倒计时过程中显示。仅对带有
countdownDuration.preAlert
的闹钟有效。
swift
let countdown = AlarmPresentation.Countdown(
    title: "Timer Running",
    pauseButton: .pauseButton
)

Paused Presentation

暂停界面

Shown when a countdown timer is paused.
swift
let paused = AlarmPresentation.Paused(
    title: "Timer Paused",
    resumeButton: .resumeButton
)
倒计时计时器暂停时显示。
swift
let paused = AlarmPresentation.Paused(
    title: "Timer Paused",
    resumeButton: .resumeButton
)

Full Three-State Presentation

完整三状态界面

Combine all three for a complete timer experience:
swift
let presentation = AlarmPresentation(
    alert: AlarmPresentation.Alert(
        title: "Timer Complete",
        stopButton: .stopButton,
        secondaryButton: .repeatButton,
        secondaryButtonBehavior: .countdown
    ),
    countdown: AlarmPresentation.Countdown(
        title: "Cooking Timer",
        pauseButton: .pauseButton
    ),
    paused: AlarmPresentation.Paused(
        title: "Timer Paused",
        resumeButton: .resumeButton
    )
)

结合三种状态实现完整的计时器体验:
swift
let presentation = AlarmPresentation(
    alert: AlarmPresentation.Alert(
        title: "Timer Complete",
        stopButton: .stopButton,
        secondaryButton: .repeatButton,
        secondaryButtonBehavior: .countdown
    ),
    countdown: AlarmPresentation.Countdown(
        title: "Cooking Timer",
        pauseButton: .pauseButton
    ),
    paused: AlarmPresentation.Paused(
        title: "Timer Paused",
        resumeButton: .resumeButton
    )
)

Part 5: Managing Alarms

第五部分:管理闹钟

Retrieve All Alarms

获取所有闹钟

swift
let alarms = try AlarmManager.shared.alarms
swift
let alarms = try AlarmManager.shared.alarms

Pause / Resume

暂停/恢复

swift
try await AlarmManager.shared.pause(id: alarmID)
try await AlarmManager.shared.resume(id: alarmID)
swift
try await AlarmManager.shared.pause(id: alarmID)
try await AlarmManager.shared.resume(id: alarmID)

Cancel

取消

swift
try await AlarmManager.shared.cancel(id: alarmID)
swift
try await AlarmManager.shared.cancel(id: alarmID)

Observe Alarm Updates

监听闹钟更新

Use
alarmUpdates
to keep UI in sync. An alarm absent from the emitted array is no longer scheduled.
swift
for await alarms in AlarmManager.shared.alarmUpdates {
    self.alarms = alarms
}

使用
alarmUpdates
保持UI同步。如果某个闹钟不在返回的数组中,则表示该闹钟已不再被调度。
swift
for await alarms in AlarmManager.shared.alarmUpdates {
    self.alarms = alarms
}

Part 6: Live Activity Integration

第六部分:Live Activity集成

AlarmKit alarms appear in the Dynamic Island and Lock Screen through
ActivityConfiguration
. Add a Widget Extension target and implement the widget using
AlarmAttributes
.
swift
struct AlarmWidgetView: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: AlarmAttributes<YourMetadata>.self) { context in
            // Lock Screen presentation
            VStack {
                Text(context.attributes.presentation.alert.title)
                if context.state.mode == .countdown {
                    Text(
                        timerInterval: context.state.countdownEndDate
                            .timeIntervalSinceNow,
                        countsDown: true
                    )
                    .bold()
                }
            }
            .padding()
        } dynamicIsland: { context in
            DynamicIsland {
                DynamicIslandExpandedRegion(.leading) {
                    Text(context.attributes.presentation.alert.title)
                }
                DynamicIslandExpandedRegion(.trailing) {
                    if context.state.mode == .countdown {
                        Text(
                            timerInterval: context.state.countdownEndDate
                                .timeIntervalSinceNow,
                            countsDown: true
                        )
                    }
                }
            } compactLeading: {
                Image(systemName: "alarm")
            } compactTrailing: {
                if context.state.mode == .countdown {
                    Text(
                        timerInterval: context.state.countdownEndDate
                            .timeIntervalSinceNow,
                        countsDown: true
                    )
                }
            } minimal: {
                Image(systemName: "alarm")
            }
        }
    }
}

AlarmKit闹钟通过
ActivityConfiguration
在Dynamic Island和锁屏界面展示。需添加Widget Extension目标,并使用
AlarmAttributes
实现小组件。
swift
struct AlarmWidgetView: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: AlarmAttributes<YourMetadata>.self) { context in
            // 锁屏界面展示
            VStack {
                Text(context.attributes.presentation.alert.title)
                if context.state.mode == .countdown {
                    Text(
                        timerInterval: context.state.countdownEndDate
                            .timeIntervalSinceNow,
                        countsDown: true
                    )
                    .bold()
                }
            }
            .padding()
        } dynamicIsland: { context in
            DynamicIsland {
                DynamicIslandExpandedRegion(.leading) {
                    Text(context.attributes.presentation.alert.title)
                }
                DynamicIslandExpandedRegion(.trailing) {
                    if context.state.mode == .countdown {
                        Text(
                            timerInterval: context.state.countdownEndDate
                                .timeIntervalSinceNow,
                            countsDown: true
                        )
                    }
                }
            } compactLeading: {
                Image(systemName: "alarm")
            } compactTrailing: {
                if context.state.mode == .countdown {
                    Text(
                        timerInterval: context.state.countdownEndDate
                            .timeIntervalSinceNow,
                        countsDown: true
                    )
                }
            } minimal: {
                Image(systemName: "alarm")
            }
        }
    }
}

Part 7: SwiftUI Integration

第七部分:SwiftUI集成

ViewModel Pattern with @Observable

结合@Observable的ViewModel模式

swift
import AlarmKit

@Observable
class AlarmViewModel {
    var alarms: [Alarm] = []
    private let manager = AlarmManager.shared

    func requestAuthorization() {
        Task {
            _ = try? await manager.requestAuthorization()
        }
    }

    func loadAndObserve() {
        Task {
            alarms = (try? manager.alarms) ?? []
            for await updated in manager.alarmUpdates {
                alarms = updated
            }
        }
    }

    func addAlarm(hour: Int, minute: Int, weekdays: Set<Locale.Weekday>) {
        Task {
            let time = Alarm.Schedule.Relative.Time(hour: hour, minute: minute)
            let schedule = Alarm.Schedule.relative(.init(
                time: time,
                repeats: weekdays.isEmpty ? .never : .weekly(Array(weekdays))
            ))

            let alert = AlarmPresentation.Alert(
                title: "Alarm",
                stopButton: .stopButton,
                secondaryButton: .snoozeButton,
                secondaryButtonBehavior: .countdown
            )

            struct EmptyMetadata: AlarmMetadata {}
            let config = AlarmManager.AlarmConfiguration(
                countdownDuration: Alarm.CountdownDuration(
                    preAlert: nil, postAlert: 9 * 60
                ),
                schedule: schedule,
                attributes: AlarmAttributes(
                    presentation: AlarmPresentation(alert: alert),
                    metadata: EmptyMetadata(),
                    tintColor: .blue
                ),
                sound: .default
            )

            _ = try? await manager.schedule(id: UUID(), configuration: config)
        }
    }

    func cancel(id: UUID) {
        Task { try? await manager.cancel(id: id) }
    }

    func togglePause(id: UUID, isPaused: Bool) {
        Task {
            if isPaused {
                try? await manager.resume(id: id)
            } else {
                try? await manager.pause(id: id)
            }
        }
    }
}
swift
import AlarmKit

@Observable
class AlarmViewModel {
    var alarms: [Alarm] = []
    private let manager = AlarmManager.shared

    func requestAuthorization() {
        Task {
            _ = try? await manager.requestAuthorization()
        }
    }

    func loadAndObserve() {
        Task {
            alarms = (try? manager.alarms) ?? []
            for await updated in manager.alarmUpdates {
                alarms = updated
            }
        }
    }

    func addAlarm(hour: Int, minute: Int, weekdays: Set<Locale.Weekday>) {
        Task {
            let time = Alarm.Schedule.Relative.Time(hour: hour, minute: minute)
            let schedule = Alarm.Schedule.relative(.init(
                time: time,
                repeats: weekdays.isEmpty ? .never : .weekly(Array(weekdays))
            ))

            let alert = AlarmPresentation.Alert(
                title: "Alarm",
                stopButton: .stopButton,
                secondaryButton: .snoozeButton,
                secondaryButtonBehavior: .countdown
            )

            struct EmptyMetadata: AlarmMetadata {}
            let config = AlarmManager.AlarmConfiguration(
                countdownDuration: Alarm.CountdownDuration(
                    preAlert: nil, postAlert: 9 * 60
                ),
                schedule: schedule,
                attributes: AlarmAttributes(
                    presentation: AlarmPresentation(alert: alert),
                    metadata: EmptyMetadata(),
                    tintColor: .blue
                ),
                sound: .default
            )

            _ = try? await manager.schedule(id: UUID(), configuration: config)
        }
    }

    func cancel(id: UUID) {
        Task { try? await manager.cancel(id: id) }
    }

    func togglePause(id: UUID, isPaused: Bool) {
        Task {
            if isPaused {
                try? await manager.resume(id: id)
            } else {
                try? await manager.pause(id: id)
            }
        }
    }
}

Alarm List View

闹钟列表视图

swift
struct AlarmListView: View {
    @State private var viewModel = AlarmViewModel()

    var body: some View {
        NavigationStack {
            List(viewModel.alarms, id: \.id) { alarm in
                AlarmRow(alarm: alarm, viewModel: viewModel)
            }
            .navigationTitle("Alarms")
            .onAppear {
                viewModel.requestAuthorization()
                viewModel.loadAndObserve()
            }
        }
    }
}

swift
struct AlarmListView: View {
    @State private var viewModel = AlarmViewModel()

    var body: some View {
        NavigationStack {
            List(viewModel.alarms, id: \.id) { alarm in
                AlarmRow(alarm: alarm, viewModel: viewModel)
            }
            .navigationTitle("Alarms")
            .onAppear {
                viewModel.requestAuthorization()
                viewModel.loadAndObserve()
            }
        }
    }
}

Part 8: Best Practices

第八部分:最佳实践

PracticeDetail
Request authorization earlyOn first launch or first alarm creation attempt
Handle denial gracefullyGuide users to Settings if permission was denied
Persist alarm UUIDsStore IDs to manage alarms across app launches
Implement widget extensionRequired for countdown/Dynamic Island presentation
Use
alarmUpdates
Keep UI in sync; don't poll or cache stale state
Test on physical deviceAlarm sounds, notifications, and Live Activities require real hardware
Respect system limitsThere is a system-imposed cap on alarms per app
Use
authorizationState
Not
authorizationStatus
-- the correct property name is
authorizationState

实践建议详细说明
尽早请求授权在首次启动或首次尝试创建闹钟时请求
优雅处理权限拒绝如果权限被拒绝,引导用户前往设置界面开启
持久化闹钟UUID存储ID以在应用重启后管理闹钟
实现小组件扩展倒计时/Dynamic Island展示的必要条件
使用
alarmUpdates
保持UI同步;不要轮询或缓存过期状态
在物理设备上测试闹钟声音、通知和Live Activities需要真实硬件支持
遵守系统限制系统对每个应用可设置的闹钟数量有上限
使用
authorizationState
正确的属性名称是
authorizationState
而非
authorizationStatus

Resources

参考资源

WWDC: 2025-230
Docs: /alarmkit, /alarmkit/alarmmanager, /alarmkit/alarm, /alarmkit/alarmpresentation, /alarmkit/alarmattributes
Skills: axiom-extensions-widgets-ref, axiom-swiftui-26-ref
WWDC: 2025-230
文档: /alarmkit, /alarmkit/alarmmanager, /alarmkit/alarm, /alarmkit/alarmpresentation, /alarmkit/alarmattributes
技能: axiom-extensions-widgets-ref, axiom-swiftui-26-ref