alarmkit

alarmkit

熱門

在 iOS 和 iPadOS 上實作 AlarmKit 鬧鐘與倒數計時器,支援鎖定畫面、動態島、待機模式及配對 Apple Watch 的系統 UI。涵蓋 AlarmManager 排程、AlarmAttributes 與 AlarmPresentation、系統停止與 AlarmButton 次要動作、授權、狀態觀察、倒數計時 widget 擴充交接,以及即時活動整合。適用於建構需要 Apple 系統鬧鐘體驗的起床鬧鐘、倒數計時器或鬧鐘式提示。

936星標
47分支
更新於 2026/7/15
SKILL.md
唯讀
名稱
alarmkit
描述

在 iOS 和 iPadOS 上實作 AlarmKit 鬧鐘與倒數計時器,支援鎖定畫面、動態島、待機模式及配對 Apple Watch 的系統 UI。涵蓋 AlarmManager 排程、AlarmAttributes 與 AlarmPresentation、系統停止與 AlarmButton 次要動作、授權、狀態觀察、倒數計時 widget 擴充交接,以及即時活動整合。適用於建構需要 Apple 系統鬧鐘體驗的起床鬧鐘、倒數計時器或鬧鐘式提示。

AlarmKit

排程會在鎖定畫面、動態島、待機模式及配對的 Apple Watch 上顯示的醒目鬧鐘與倒數計時器。AlarmKit 需要 iOS 26+ / iPadOS 26+。鬧鐘可以突破專注模式與靜音模式。

AlarmKit 使用 ActivityKit 資料模型作為其即時活動,但觸發的提示是系統管理的鬧鐘 UI,而非一般的自訂通知 UI 表面。自訂 UI 僅屬於由 Widget 擴充所呈現的倒數計時與暫停即時活動狀態,該擴充使用與排程時相同的 AlarmAttributes<Metadata>AlarmPresentationState

請參閱 references/alarmkit-patterns.md 以取得完整的程式碼模式,包括授權、排程、倒數計時器、貪睡處理及 widget 設定。

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. 如果使用倒數計時,請新增一個 Widget 擴充目標,並使用與 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,用於取得目前 daemon 的快照。使用 try,並在依賴快照前傳播錯誤或將啟動重新整理包裝在 do/catch 中。

觀察 alarmUpdates 而非維護獨立的生命週期。請參閱使用非同步序列的狀態觀察以取得完整的儲存與重新整理迴圈。

alarmUpdates 中消失的鬧鐘表示已不再由 AlarmKit 排程。當需要區分已觸發、已取消和已重新排程的鬧鐘時,請與應用程式持久化的 ID 進行比對。

AlarmAttributes 與 AlarmPresentation

AlarmAttributes 符合 ActivityAttributes,並定義鬧鐘即時活動的靜態資料。它泛型於一個符合 AlarmMetadataMetadata 類型,該協定繼承 DecodableEncodableHashableSendablemetadata 值本身是可選的,預設為 nil

AlarmPresentation 提供必要的提示內容以及可選的倒數/暫停內容。系統呈現提示 UI;widget 擴充可以使用相同的屬性和呈現狀態來自訂倒數和暫停的即時活動視圖。保持中繼資料輕量,在不需要時使用 nil,並與 widget 擴充共用其類型。

AlarmPresentationState

AlarmPresentationState 是系統管理的鬧鐘即時活動的 ContentState。它包含鬧鐘 ID 和一個 Mode 列舉:

  • .alert(Alert) -- 鬧鐘正在觸發,包含排程時間
  • .countdown(Countdown) -- 正在倒數,包含觸發日期和持續時間
  • .paused(Paused) -- 倒數已暫停,包含已過和總持續時間

Widget 擴充讀取 AlarmPresentationState.mode 來決定在非提示狀態下於動態島和鎖定畫面呈現哪個 UI。

AlarmButton

AlarmButton 定義鬧鐘動作的文字、顏色和符號。上述代表性排程範例顯示了一個標準的貪睡按鈕。

次要按鈕行為

提示 UI 上的次要按鈕有兩種行為:

行為 效果
.countdown 使用 postAlert 持續時間重新開始倒數(貪睡)
.custom 觸發 secondaryIntent(例如開啟應用程式)

即時活動整合

AlarmKit 鬧鐘在鎖定畫面、動態島、待機模式及配對的 Apple Watch 上顯示為即時活動。系統管理提示 UI。對於倒數和暫停狀態,請新增一個 Widget 擴充目標,其 ActivityConfiguration 使用與排程鬧鐘時相同的 AlarmAttributes<Metadata> 類型。

如果您的鬧鐘使用倒數呈現,則需要 widget 擴充。保持該輕量中繼資料類型可供應用程式和 widget 擴充使用。如果沒有擴充,鬧鐘可能會意外被關閉或無法提示,儘管系統在某些有限情況下(例如裝置重新啟動後首次解鎖前)仍可顯示備用倒數 UI。

工作 負責方
授權、排程/狀態、呈現、聲音、系統鬧鐘動作 AlarmKit
主畫面/Smart Stack widget、系列、時間線、重新載入 widgetkit
非鬧鐘即時活動生命週期、令牌、遠端內容狀態 activitykit
APNs、通知類別/動作、自訂通知 UI push-notifications

AlarmKit 的提示由系統在鎖定畫面、動態島、待機模式及配對的 Apple Watch 上呈現;只有倒數/暫停狀態使用 widget 擴充。

關於設定,請使用 Apple 文件中的 NSAlarmKitUsageDescriptionAlarmManager 授權。除非目前的 Apple 來源有文件說明,否則不要要求不支援的 AlarmKit 設定金鑰或 com.apple.developer.alarmkit。請參閱鬧鐘的即時活動 Widget 擴充以取得完整的共用屬性 widget 實作。

常見錯誤

錯誤 修正
缺少使用說明字串或授權保護 加入 NSAlarmKitUsageDescription;在排程前處理拒絕情況
使用計時器來實現重複 使用帶有 .weekly([...]) 的鬧鐘
應用程式自有狀態取代 alarmUpdates 觀察系統序列並按 ID 比對
為標準停止/貪睡加入意圖 除非需要清理/自訂行為,否則省略
大型 AlarmMetadata 負載 保持中繼資料輕量,或透過 ID 參考應用程式資料
已棄用的 stopButton 初始化器 使用 init(title:secondaryButton:secondaryButtonBehavior:)

審查清單

  • [ ] 設定和授權保護通過,無需不支援的授權金鑰
  • [ ] 鬧鐘/計時器選擇、呈現、中繼資料、意圖、貪睡持續時間和色調均有效
  • [ ] 排程的 ID 已保留並透過 alarmUpdates 比對;操作錯誤已處理
  • [ ] 倒數使用共用的 Widget 擴充屬性和呈現狀態
  • [ ] 系統管理的提示 UI 和相鄰技能的擁有權遵循路由表
  • [ ] 聲音、震動、停止/貪睡和狀態變更通過裝置測試

參考資料