关于 axiom-alarmkit-ref
面向 iOS 开发者的 AlarmKit Swift 参考技能,涵盖授权、闹钟与计时器调度、界面呈现及 Live Activity 集成。
主要功能
- 01AlarmKit API 组件参考
- 02授权请求与状态观察
- 03一次性及重复闹钟
- 04倒计时、暂停、恢复与稍后提醒
- 05闹钟界面与 Live Activity 指引
适用场景
- 01在 iOS 应用中实现定时闹钟
- 02添加支持暂停与恢复的倒计时
- 03构建锁定屏幕和灵动岛闹钟界面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-alarmkit-ref安装后在 Claude Code 中输入/axiom-alarmkit-ref确认已加载。
详细介绍
AlarmKit 参考
AlarmKit 的完整 API 参考。AlarmKit 是 Apple 的框架,用于安排闹钟和倒计时计时器,并提供系统级提醒、Dynamic Island 集成,以及对专注模式和静音模式的覆盖。
概览
AlarmKit 允许应用创建行为类似于内置“时钟”应用的闹钟和计时器——它们会覆盖“勿扰模式”、显示在 Dynamic Island 中,并显示在锁定屏幕上。该框架通过一组以 AlarmManager 为核心的类型处理安排、稍后提醒、暂停/继续和 UI 呈现。
系统要求
- iOS 26+(AlarmKit 在 iOS 26 中引入)
- 需要 Widget Extension 来呈现实时活动 / Dynamic Island
- 建议使用实体设备进行闹钟声音和通知测试
第 1 部分:关键组件
AlarmManager
所有闹钟操作的单例入口。
import AlarmKit
let manager = AlarmManager.shared
所有安排、取消和观察流程都通过此共享实例进行。
Alarm
描述可触发一次或按重复计划触发的闹钟。
struct Alarm {
var id: UUID
var schedule: Schedule?
var countdownDuration: CountdownDuration?
var state: AlarmState
}
AlarmPresentation
闹钟 UI 在三种状态下的内容——提醒中、倒计时和已暂停。
struct AlarmPresentation {
var alert: Alert // Required: shown when alarm fires
var countdown: Countdown? // Optional: shown during countdown
var paused: Paused? // Optional: shown when paused
}
AlarmAttributes
用于将呈现内容与应用专属元数据和色调配对的通用容器。用于配置实时活动小组件。
struct AlarmAttributes<Metadata: AlarmMetadata> {
var presentation: AlarmPresentation
var metadata: Metadata
var tintColor: Color
}
AlarmMetadata
用于附加到闹钟的应用专属数据协议。可以遵循一个空结构体以满足最低使用需求,也可以添加属性以实现更丰富的 UI。
struct RecipeMetadata: AlarmMetadata {
let recipeName: String
let cookingStep: String
}
第 2 部分:授权
应用必须先请求权限,才能安排闹钟。将 NSAlarmKitUsageDescription 添加到 Info.plist。
请求授权
func requestAlarmAuthorization() async -> Bool {
do {
let state = try await AlarmManager.shared.requestAuthorization()
return state == .authorized
} catch {
print("Authorization error: \(error)")
return false
}
}
检查当前状态
使用 authorizationState(而不是 authorizationStatus)读取当前值:
let state = await AlarmManager.shared.authorizationState
// .authorized | .denied | .notDetermined
观察授权变更
for await authState in AlarmManager.shared.authorizationUpdates {
switch authState {
case .authorized: enableAlarmUI()
case .denied: showPermissionPrompt()
case .notDetermined: break
@unknown default: break
}
}
第 3 部分:安排闹钟
每个闹钟都需要一个 UUID、一个 AlarmManager.AlarmConfiguration,以及对 schedule(id:configuration:) 的调用。
单次闹钟
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)
重复闹钟
使用 .weekly(Array(weekdays)) 指定具体日期:
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])
))
倒计时计时器
将 schedule: nil,并提供 countdownDuration 和一个 preAlert 时间间隔:
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
)
计时器支持暂停/继续;提供 AlarmPresentation.countdown 时,会显示倒计时呈现内容。
稍后提醒配置
稍后提醒使用 CountdownDuration.postAlert,并配合 .snoozeButton 次要操作:
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
)
第 4 部分:自定义闹钟 UI
提醒呈现
闹钟触发时显示提醒状态。停止按钮为必需项;次要按钮为可选项。
// 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
)
倒计时呈现
计时器倒计时期间显示。仅适用于设置了 countdownDuration.preAlert 的闹钟。
let countdown = AlarmPresentation.Countdown(
title: "Timer Running",
pauseButton: .pauseButton
)
暂停呈现
倒计时计时器暂停时显示。
let paused = AlarmPresentation.Paused(
title: "Timer Paused",
resumeButton: .resumeButton
)
完整的三态呈现
组合全部三种状态,打造完整的计时器体验:
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
)
)
第 5 部分:管理闹钟
获取所有闹钟
let alarms = try AlarmManager.shared.alarms
暂停 / 继续
try await AlarmManager.shared.pause(id: alarmID)
try await AlarmManager.shared.resume(id: alarmID)
取消
try await AlarmManager.shared.cancel(id: alarmID)
观察闹钟更新
使用 alarmUpdates 使 UI 保持同步。若某个闹钟未出现在发出的数组中,则表示它已不再安排。
for await alarms in AlarmManager.shared.alarmUpdates {
self.alarms = alarms
}
第 6 部分:实时活动集成
AlarmKit 闹钟通过 ActivityConfiguration 显示在 Dynamic Island 和锁定屏幕上。添加一个 Widget Extension 目标,并使用 AlarmAttributes 实现小组件。
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")
}
}
}
}
第 7 部分:SwiftUI 集成
使用 @Observable 的 ViewModel 模式
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)
}
}
}
}
闹钟列表视图
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()
}
}
}
}
第 8 部分:最佳实践
| 实践 | 详情 |
|---|---|
| 尽早请求授权 | 在首次启动或首次尝试创建闹钟时请求 |
| 妥善处理拒绝授权的情况 | 如果用户拒绝了权限,引导他们前往“设置” |
| 持久化闹钟 UUID | 存储 ID,以便在应用启动之间管理闹钟 |
| 实现小组件扩展 | 倒计时/灵动岛展示所必需 |
使用 alarmUpdates | 让 UI 保持同步;不要轮询或缓存过期状态 |
| 在实体设备上测试 | 闹钟声音、通知和实时活动需要真实硬件 |
| 遵守系统限制 | 系统对每个应用可创建的闹钟数量设有上限 |
使用 authorizationState | 不是 authorizationStatus——正确的属性名称是 authorizationState |
资源
WWDC:2025-230
文档:/alarmkit, /alarmkit/alarmmanager, /alarmkit/alarm, /alarmkit/alarmpresentation, /alarmkit/alarmattributes
技能:axiom-extensions-widgets-ref, axiom-swiftui-26-ref