alarmkit

alarmkit

热门

在 iOS 和 iPadOS 上实现 AlarmKit 闹钟和倒计时器,支持锁定屏幕、灵动岛、待机显示和配对的 Apple Watch 系统 UI。涵盖 AlarmManager 调度、AlarmAttributes 和 AlarmPresentation、系统停止和 AlarmButton 辅助操作、授权、状态观察、倒计时小组件扩展交接以及实时活动集成。适用于构建需要 Apple 系统闹钟体验的起床闹钟、倒计时器或闹钟式提醒。

936Star
47Fork
更新于 2026/7/15
SKILL.md
readonly只读
name
alarmkit
description

在 iOS 和 iPadOS 上实现 AlarmKit 闹钟和倒计时器,支持锁定屏幕、灵动岛、待机显示和配对的 Apple Watch 系统 UI。涵盖 AlarmManager 调度、AlarmAttributes 和 AlarmPresentation、系统停止和 AlarmButton 辅助操作、授权、状态观察、倒计时小组件扩展交接以及实时活动集成。适用于构建需要 Apple 系统闹钟体验的起床闹钟、倒计时器或闹钟式提醒。

AlarmKit

调度醒目的闹钟和倒计时器,当闹钟触发时显示在锁定屏幕、灵动岛、待机显示和配对的 Apple Watch 上。AlarmKit 需要 iOS 26+ / iPadOS 26+。闹钟可以突破专注模式和静音模式。

AlarmKit 使用 ActivityKit 数据模型作为其实时活动,但触发提醒是系统管理的闹钟 UI,而非通用的自定义通知 UI 界面。自定义 UI 仅属于倒计时和暂停的实时活动状态,由使用相同 AlarmAttributes<Metadata>AlarmPresentationState 的小组件扩展渲染。

请参阅 references/alarmkit-patterns.md 获取完整的代码模式,包括授权、调度、倒计时器、贪睡处理和小组件设置。

import AlarmKit

目录

工作流程

1. 创建新闹钟或计时器

  1. 在 Info.plist 中添加 NSAlarmKitUsageDescription,提供面向用户的字符串。
  2. 当应用能够解释价值时,使用 AlarmManager.shared.requestAuthorization() 请求授权,或处理首次调度的系统提示。
  3. 如果授权状态为 .denied 或未 .authorized,则显示恢复 UI 而非调度。
  4. 配置 AlarmPresentation(提醒、倒计时、暂停状态)。
  5. 创建 AlarmAttributes,包含呈现、可选元数据和色调颜色。
  6. 构建 AlarmManager.AlarmConfiguration(.alarm 或 .timer)。
  7. 使用 AlarmManager.shared.schedule(id:configuration:) 调度。
  8. 观察 alarmManager.alarmUpdates,确认调度的 ID 达到预期状态。
  9. 如果使用倒计时,为相同的 AlarmAttributes<Metadata> 类型添加一个带有 ActivityConfiguration 的小组件扩展目标。

2. 审查现有闹钟代码

运行本文档末尾的审查清单。

授权

AlarmKit 需要用户授权。在应用能够解释价值时尽早请求,或让 AlarmKit 在首次调度时自动提示。如果在显式或自动提示后未授予授权,则闹钟不会被调度且不会提醒。

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) 计时器 (.timer)
触发时间 特定时间(调度) 持续时间结束后
倒计时 UI 可选 始终显示
重复 是(每周几天)
使用场景 起床、定时提醒 烹饪、锻炼间隔

当在时钟时间触发时使用 .alarm(schedule:...)。当从现在起经过一段时间后触发时使用 .timer(duration:...)

调度闹钟

Alarm.Schedule

使用 .fixed(date) 表示一次性绝对日期,或使用 .relative 表示本地时钟时间,并配合 .never.weekly 重复。加载重复闹钟模式以获取每日、工作日、周末和固定日期变体。

调度和配置

let id = UUID()

let alert = AlarmPresentation.Alert(
    title: "起床",
    secondaryButton: AlarmButton(
        text: "贪睡", textColor: .white, systemImageName: "bell.slash"
    ),
    secondaryButtonBehavior: .countdown
)
let presentation = AlarmPresentation(alert: alert)
struct EmptyAlarmMetadata: AlarmMetadata {}
let attributes = AlarmAttributes<EmptyAlarmMetadata>(
    presentation: presentation,
    metadata: nil,
    tintColor: .indigo
)

let snooze = Alarm.CountdownDuration(preAlert: nil, postAlert: 300)
let configuration = AlarmManager.AlarmConfiguration(
    countdownDuration: snooze,
    schedule: .relative(.init(
        time: .init(hour: 7, minute: 0),
        repeats: .never
    )),
    attributes: attributes,
    sound: .default
)

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

对于授权保护的函数和带元数据的变体,加载完整闹钟调度流程

stopIntentsecondaryIntent 默认为 nil。省略 stopIntent 以使用 AlarmKit 的标准系统停止行为;仅在停止需要执行应用清理、自定义停止行为或其他副作用时提供。省略 secondaryIntent 以使用普通的贪睡/重复行为,配合 secondaryButtonBehavior: .countdownAlarm.CountdownDuration.postAlert;仅在需要 .custom 辅助行为或应用清理/自定义行为时提供。

闹钟状态转换

cancel(id:)
    |
scheduled --> countdown --> alerting
    |             |             |
    |         pause(id:)    stop(id:) / countdown(id:)
    |             |
    |         paused ----> countdown (via resume(id:))
    |
cancel(id:) 从系统中完全移除
  • cancel(id:) -- 完全移除闹钟,包括重复闹钟
  • pause(id:) -- 暂停正在倒计时的闹钟;从其他状态调用会抛出错误
  • resume(id:) -- 恢复暂停的闹钟;从其他状态调用会抛出错误
  • stop(id:) -- 停止闹钟;一次性闹钟被移除,重复闹钟重新调度
  • countdown(id:) -- 从提醒状态重新开始倒计时(贪睡);从其他状态调用会抛出错误

倒计时器

计时器在持续时间后触发,并始终显示倒计时 UI。使用 Alarm.CountdownDuration 控制提醒前和提醒后的持续时间。

CountdownDuration

Alarm.CountdownDuration 控制可见的倒计时阶段:

  • preAlert -- 闹钟触发前倒计时的秒数(主倒计时)
  • postAlert -- 闹钟触发后重复/贪睡倒计时的秒数

加载完整倒计时器流程以获取计时器工厂、暂停/恢复呈现、元数据和调度门控。

闹钟状态

每个 Alarm 都有一个 state 属性,反映其当前生命周期位置。

状态 含义
.scheduled 已调度,准备在适当时间提醒
.countdown 正在倒计时(计时器或提醒前阶段)
.paused 倒计时被用户或应用暂停
.alerting 闹钟正在触发 -- 播放声音,UI 突出

观察状态变化

AlarmManager.shared.alarms 是一个抛出错误的 getter,用于获取当前守护进程快照。使用 try,并在依赖快照之前要么传播错误,要么在 do/catch 中包装启动刷新。

观察 alarmUpdates 而非维护独立的生命周期。加载使用异步序列的状态观察以获取完整的存储和刷新循环。

alarmUpdates 中消失的闹钟不再由 AlarmKit 调度。当需要区分已触发、已取消和已重新调度的闹钟时,与应用持久化的 ID 进行比较。

AlarmAttributes 和 AlarmPresentation

AlarmAttributes 遵循 ActivityAttributes,并定义闹钟实时活动的静态数据。它泛型于一个遵循 AlarmMetadataMetadata 类型,后者继承 DecodableEncodableHashableSendablemetadata 值本身是可选的,默认为 nil

AlarmPresentation 提供必需的提醒内容和可选的倒计时/暂停内容。系统渲染提醒 UI;小组件扩展可以使用相同的属性和呈现状态自定义倒计时和暂停的实时活动视图。保持元数据轻量,在不需要时使用 nil,并与小组件扩展共享其类型。

AlarmPresentationState

AlarmPresentationState 是系统管理的闹钟实时活动的 ContentState。它包含闹钟 ID 和一个 Mode 枚举:

  • .alert(Alert) -- 闹钟正在触发,包含计划时间
  • .countdown(Countdown) -- 正在倒计时,包含触发日期和持续时间
  • .paused(Paused) -- 倒计时暂停,包含已过时间和总持续时间

小组件扩展读取 AlarmPresentationState.mode 以决定在非提醒状态下在灵动岛和锁定屏幕上渲染哪个 UI。

AlarmButton

AlarmButton 定义闹钟操作的文本、颜色和符号。上述代表性调度示例显示了一个标准的贪睡按钮。

辅助按钮行为

提醒 UI 上的辅助按钮有两种行为:

行为 效果
.countdown 使用 postAlert 持续时间重新开始倒计时(贪睡)
.custom 触发 secondaryIntent(例如打开应用)

实时活动集成

AlarmKit 闹钟在锁定屏幕、灵动岛、待机显示和配对的 Apple Watch 上显示为实时活动。系统管理提醒 UI。对于倒计时和暂停状态,添加一个小组件扩展目标,其 ActivityConfiguration 使用与调度闹钟时相同的 AlarmAttributes<Metadata> 类型。

如果闹钟使用倒计时呈现,则需要小组件扩展。保持该轻量元数据类型对应用和小组件扩展都可用。没有扩展时,闹钟可能会意外被解除或无法提醒,尽管系统在有限情况下(例如设备重启后首次解锁前)仍可能显示后备的倒计时 UI。

工作 负责人
授权、调度/状态、呈现、声音、系统闹钟操作 AlarmKit
主屏幕/智能叠放小组件、系列、时间线、刷新 widgetkit
非闹钟实时活动生命周期、令牌、远程内容状态 activitykit
APNs、通知类别/操作、自定义通知 UI push-notifications

AlarmKit 的提醒在锁定屏幕、灵动岛、待机显示和配对的 Apple Watch 上由系统渲染;只有倒计时/暂停状态使用小组件扩展。

对于设置,命名 Apple 文档中的 NSAlarmKitUsageDescriptionAlarmManager 授权。除非当前 Apple 来源有文档说明,否则不要要求不支持的 AlarmKit 设置键或 com.apple.developer.alarmkit。加载闹钟的实时活动小组件扩展以获取完整的共享属性小组件实现。

常见错误

错误 修正
缺少使用字符串或授权门控 添加 NSAlarmKitUsageDescription;在调度前处理拒绝
使用计时器实现重复 使用带有 .weekly([...]) 的闹钟
应用自有状态替代 alarmUpdates 观察系统序列并通过 ID 协调
为标准停止/贪睡添加意图 除非需要清理/自定义行为,否则省略
大型 AlarmMetadata 负载 保持轻量元数据或通过 ID 引用应用数据
已弃用的 stopButton 初始化器 使用 init(title:secondaryButton:secondaryButtonBehavior:)

审查清单

  • [ ] 设置和授权门控通过,无需不支持的授权键
  • [ ] 闹钟/计时器选择、呈现、元数据、意图、贪睡持续时间和色调有效
  • [ ] 调度的 ID 被保留并通过 alarmUpdates 协调;操作错误已处理
  • [ ] 倒计时使用共享的小组件扩展属性和呈现状态
  • [ ] 系统管理的提醒 UI 和相邻技能所有权遵循路由表
  • [ ] 声音、振动、停止/贪睡和状态变化通过设备测试

参考