-
Despertar con la AlarmKit API
¡Rrrr-rrrrr-innng! Desde los temporizadores de cuenta regresiva de la app de recetas hasta las alarmas para despertar de la app de planificación de viajes, el marco AlarmKit en iOS y iPadOS 26 lleva los temporizadores y las alarmas a la pantalla de bloqueo, a Dynamic Island y mucho más. Aprende a crear y gestionar las alarmas de tu app, personalizar las Actividades en Vivo y ofrecer acciones de alerta personalizadas mediante el marco App Intents. Para aprovechar al máximo este video, te recomendamos ver primero "Meet ActivityKit" del WWDC23.
Capítulos
- 0:00 - Te damos la bienvenida
- 0:32 - Descripción general
- 1:39 - Autorización
- 3:06 - Creación
- 16:32 - Ciclo de vida
Recursos
- Scheduling an alarm with AlarmKit
- AlarmKit
- Creating your first app intent
- Human Interface Guidelines: Live Activities
- ActivityKit
- App Intents
Videos relacionados
WWDC25
WWDC23
-
Buscar este video…
-
-
2:41 - Check authorization status
// Check authorization status import AlarmKit func checkAuthorization() { switch AlarmManager.shared.authorizationState { case .notDetermined: // Manually request authorization case .authorized: // Proceed with scheduling case .denied: // Inform status is not authorized } } -
4:08 - Set up the countdown duration
// Set up the countdown duration import AlarmKit func scheduleAlarm() { /* ... */ let countdownDuration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) /* ... */ } -
4:40 - Set a fixed schedule
// Set a fixed schedule import AlarmKit func scheduleAlarm() { /* ... */ let keynoteDateComponents = DateComponents( calendar: .current, year: 2025, month: 6, day: 9, hour: 9, minute: 41) let keynoteDate = Calendar.current.date(from: keynoteDateComponents)! let scheduleFixed = Alarm.Schedule.fixed(keynoteDate) /* ... */ } -
5:13 - Set a relative schedule
// Set a relative schedule import AlarmKit func scheduleAlarm() { /* ... */ let time = Alarm.Schedule.Relative.Time(hour: 7, minute: 0) let recurrence = Alarm.Schedule.Relative.Recurrence.weekly([ .monday, .wednesday, .friday ]) let schedule = Alarm.Schedule.Relative(time: time, repeats: recurrence) /* ... */ } -
5:43 - Set up alert appearance with dismiss button
// Set up alert appearance with dismiss button import AlarmKit func scheduleAlarm() async throws { typealias AlarmConfiguration = AlarmManager.AlarmConfiguration<CookingData> let id = UUID() let duration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) let stopButton = AlarmButton( text: "Dismiss", textColor: .white, systemImageName: "stop.circle") let alertPresentation = AlarmPresentation.Alert( title: "Food Ready!", stopButton: stopButton) let attributes = AlarmAttributes<CookingData>( presentation: AlarmPresentation( alert: alertPresentation), tintColor: Color.green) let alarmConfiguration = AlarmConfiguration( countdownDuration: duration, attributes: attributes) try await AlarmManager.shared.schedule(id: id, configuration: alarmConfiguration) } -
7:17 - Set up alert appearance with repeat button
// Set up alert appearance with repeat button import AlarmKit func scheduleAlarm() async throws { typealias AlarmConfiguration = AlarmManager.AlarmConfiguration<CookingData> let id = UUID() let duration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) let stopButton = AlarmButton( text: "Dismiss", textColor: .white, systemImageName: "stop.circle") let repeatButton = AlarmButton( text: "Repeat", textColor: .white, systemImageName: "repeat.circle") let alertPresentation = AlarmPresentation.Alert( title: "Food Ready!", stopButton: stopButton, secondaryButton: repeatButton, secondaryButtonBehavior: .countdown) let attributes = AlarmAttributes<CookingData>( presentation: AlarmPresentation(alert: alertPresentation), tintColor: Color.green) let alarmConfiguration = AlarmConfiguration( countdownDuration: duration, attributes: attributes) try await AlarmManager.shared.schedule(id: id, configuration: alarmConfiguration) } -
9:15 - Create a Live Activity for a countdown
// Create a Live Activity for a countdown import AlarmKit import ActivityKit import WidgetKit struct AlarmLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: AlarmAttributes<CookingData>.self) { context in switch context.state.mode { case .countdown: countdownView(context) case .paused: pausedView(context) case .alert: alertView(context) } } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.leading) { leadingView(context) } DynamicIslandExpandedRegion(.trailing) { trailingView(context) } } compactLeading: { compactLeadingView(context) } compactTrailing: { compactTrailingView(context) } minimal: { minimalView(context) } } } } -
10:26 - Create custom metadata for the Live Activity
// Create custom metadata for the Live Activity import AlarmKit struct CookingData: AlarmMetadata { let method: Method init(method: Method) { self.method = method } enum Method: String, Codable { case frying = "frying.pan" case grilling = "flame" } } -
10:43 - Provide custom metadata to the Live Activity
// Provide custom metadata to the Live Activity import AlarmKit func scheduleAlarm() async throws { typealias AlarmConfiguration = AlarmManager.AlarmConfiguration<CookingData> let id = UUID() let duration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) let customMetadata = CookingData(method: .frying) let stopButton = AlarmButton( text: "Dismiss", textColor: .white, systemImageName: "stop.circle") let repeatButton = AlarmButton( text: "Repeat", textColor: .white, systemImageName: "repeat.circle") let alertPresentation = AlarmPresentation.Alert( title: "Food Ready!", stopButton: stopButton, secondaryButton: repeatButton, secondaryButtonBehavior: .countdown) let attributes = AlarmAttributes<CookingData>( presentation: AlarmPresentation(alert: alertPresentation), metadata: customMetadata, tintColor: Color.green) let alarmConfiguration = AlarmConfiguration( countdownDuration: duration, attributes: attributes) try await AlarmManager.shared.schedule(id: id, configuration: alarmConfiguration) } -
11:01 - Use custom metadata in the Live Activity
// Use custom metadata in the Live Activity import AlarmKit import ActivityKit import WidgetKit struct AlarmLiveActivity: Widget { var body: some WidgetConfiguration { /* ... */ } func alarmIcon(context: ActivityViewContext<AlarmAttributes<CookingData>>) -> some View { let method = context.attributes.metadata?.method ?? .grilling return Image(systemName: method.rawValue) } } -
12:03 - Set up the system countdown appearance
// Set up the system countdown appearance import AlarmKit func scheduleAlarm() async throws { typealias AlarmConfiguration = AlarmManager.AlarmConfiguration<CookingData> let id = UUID() let duration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) let customMetadata = CookingData(method: .frying) let stopButton = AlarmButton( text: "Dismiss", textColor: .white, systemImageName: "stop.circle") let repeatButton = AlarmButton( text: "Repeat", textColor: .white, systemImageName: "repeat.circle") let alertPresentation = AlarmPresentation.Alert( title: "Food Ready!", stopButton: stopButton, secondaryButton: repeatButton, secondaryButtonBehavior: .countdown) let pauseButton = AlarmButton( text: "Pause", textColor: .green, systemImageName: "pause") let countdownPresentation = AlarmPresentation.Countdown( title: "Cooking", pauseButton: pauseButton) let attributes = AlarmAttributes<CookingData>( presentation: AlarmPresentation( alert: alertPresentation, countdown: countdownPresentation), metadata: customMetadata, tintColor: Color.green) let alarmConfiguration = AlarmConfiguration( countdownDuration: duration, attributes: attributes) try await AlarmManager.shared.schedule(id: id, configuration: alarmConfiguration) } -
12:43 - Set up the system paused appearance
// Set up the system paused appearance import AlarmKit func scheduleAlarm() async throws { typealias AlarmConfiguration = AlarmManager.AlarmConfiguration<CookingData> let id = UUID() let duration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) let customMetadata = CookingData(method: .frying) let stopButton = AlarmButton( text: "Dismiss", textColor: .white, systemImageName: "stop.circle") let repeatButton = AlarmButton( text: "Repeat", textColor: .white, systemImageName: "repeat.circle") let alertPresentation = AlarmPresentation.Alert( title: "Food Ready!", stopButton: stopButton, secondaryButton: repeatButton, secondaryButtonBehavior: .countdown) let pauseButton = AlarmButton( text: "Pause", textColor: .green, systemImageName: "pause") let countdownPresentation = AlarmPresentation.Countdown( title: "Cooking", pauseButton: pauseButton) let resumeButton = AlarmButton( text: "Resume", textColor: .green, systemImageName: "play") let pausedPresentation = AlarmPresentation.Paused( title: "Paused", resumeButton: resumeButton) let attributes = AlarmAttributes<CookingData>( presentation: AlarmPresentation( alert: alertPresentation, countdown: countdownPresentation, paused: pausedPresentation), metadata: customMetadata, tintColor: Color.green) let alarmConfiguration = AlarmConfiguration( countdownDuration: duration, attributes: attributes) try await AlarmManager.shared.schedule(id: id, configuration: alarmConfiguration) } -
14:09 - Add a custom button
// Add a custom button import AlarmKit import AppIntents func scheduleAlarm() async throws { typealias AlarmConfiguration = AlarmManager.AlarmConfiguration<CookingData> let id = UUID() let duration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) let customMetadata = CookingData(method: .frying) let secondaryIntent = OpenInApp(alarmID: id.uuidString) let stopButton = AlarmButton( text: "Dismiss", textColor: .white, systemImageName: "stop.circle") let openButton = AlarmButton( text: "Open", textColor: .white, systemImageName: "arrow.right.circle.fill") let alertPresentation = AlarmPresentation.Alert( title: "Food Ready!", stopButton: stopButton, secondaryButton: openButton, secondaryButtonBehavior: .custom) let pauseButton = AlarmButton( text: "Pause", textColor: .green, systemImageName: "pause") let countdownPresentation = AlarmPresentation.Countdown( title: "Cooking", pauseButton: pauseButton) let resumeButton = AlarmButton( text: "Resume", textColor: .green, systemImageName: "play") let pausedPresentation = AlarmPresentation.Paused( title: "Paused", resumeButton: resumeButton) let attributes = AlarmAttributes<CookingData>( presentation: AlarmPresentation( alert: alertPresentation, countdown: countdownPresentation, paused: pausedPresentation), metadata: customMetadata, tintColor: Color.green) let alarmConfiguration = AlarmConfiguration( countdownDuration: duration, attributes: attributes, secondaryIntent: secondaryIntent) try await AlarmManager.shared.schedule(id: id, configuration: alarmConfiguration) } public struct OpenInApp: LiveActivityIntent { public func perform() async throws -> some IntentResult { .result() } public static var title: LocalizedStringResource = "Open App" public static var description = IntentDescription("Opens the Sample app") public static var openAppWhenRun = true @Parameter(title: "alarmID") public var alarmID: String public init(alarmID: String) { self.alarmID = alarmID } public init() { self.alarmID = "" } } -
16:10 - Add a custom sound
// Add a custom sound import AlarmKit import AppIntents func scheduleAlarm() async throws { typealias AlarmConfiguration = AlarmManager.AlarmConfiguration<CookingData> let id = UUID() let duration = Alarm.CountdownDuration(preAlert: (10 * 60), postAlert: (5 * 60)) let customMetadata = CookingData(method: .frying) let secondaryIntent = OpenInApp(alarmID: id.uuidString) let stopButton = AlarmButton( text: "Dismiss", textColor: .white, systemImageName: "stop.circle") let openButton = AlarmButton( text: "Open", textColor: .white, systemImageName: "arrow.right.circle.fill") let alertPresentation = AlarmPresentation.Alert( title: "Food Ready!", stopButton: stopButton, secondaryButton: openButton, secondaryButtonBehavior: .custom) let pauseButton = AlarmButton( text: "Pause", textColor: .green, systemImageName: "pause") let countdownPresentation = AlarmPresentation.Countdown( title: "Cooking", pauseButton: pauseButton) let resumeButton = AlarmButton( text: "Resume", textColor: .green, systemImageName: "play") let pausedPresentation = AlarmPresentation.Paused( title: "Paused", resumeButton: resumeButton) let attributes = AlarmAttributes<CookingData>( presentation: AlarmPresentation( alert: alertPresentation, countdown: countdownPresentation, paused: pausedPresentation), metadata: customMetadata, tintColor: Color.green) let sound = AlertConfiguration.AlertSound.named("Chime") let alarmConfiguration = AlarmConfiguration( countdownDuration: duration, attributes: attributes, secondaryIntent: secondaryIntent, sound: sound) try await AlarmManager.shared.schedule(id: id, configuration: alarmConfiguration) } public struct OpenInApp: LiveActivityIntent { public func perform() async throws -> some IntentResult { .result() } public static var title: LocalizedStringResource = "Open App" public static var description = IntentDescription("Opens the Sample app") public static var openAppWhenRun = true @Parameter(title: "alarmID") public var alarmID: String public init(alarmID: String) { self.alarmID = alarmID } public init() { self.alarmID = "" } }
-
-
- 0:00 - Te damos la bienvenida
AlarmKit es una nueva estructura que puedes usar para crear temporizadores y alarmas. Aprende sobre la experiencia, cómo obtener autorización, crear alarmas y administrar su ciclo de vida.
- 0:32 - Descripción general
Las alarmas son alertas programadas que interrumpen el modo silencioso y muestran un título personalizado y el nombre de la app. También pueden mostrar una cuenta regresiva. Las personas pueden detener o posponer la alarma, o interactuar con botones personalizados. Las alarmas son visibles en la pantalla de bloqueo, Dynamic Island, En Espera y el Apple Watch, y las personas deben aceptarlas por app.
- 1:39 - Autorización
Para habilitar la programación de alarmas en una app, las personas deben autorizarla. Esto se puede hacer automáticamente al crear la primera alarma, o manualmente a través de la API requestAuthorization de AlarmManager. Debes agregar NSAlarmKitUsageDescription a Info.plist para explicar cómo se usan las alarmas. Las personas pueden cambiar el estado de autorización en Configuración. Antes de programar una alarma, la app puede verificar el estado de la autorización; si se deniega, debes informar a las personas que no se programará.
- 3:06 - Creación
La creación de una alarma implica varios componentes clave. Primero, se puede configurar con una duración de cuenta regresiva, que puede incluir un intervalo de prealerta y otro de posalerta. Cuando la alarma está programada con una cuenta regresiva, esta se muestra en una IU mientras dura la prealerta. Una vez transcurrido este tiempo, la alarma se dispara, y muestra una IU de alerta personalizada. Si se pospone, la IU de cuenta regresiva reaparecerá durante el intervalo posalerta antes de activarse de nuevo.. Para las alarmas se pueden usar un programa fijo o uno relativo. Un programa fijo especifica una única fecha y hora futuras, mientras que un programa relativo permite una hora diaria con un patrón de recurrencia semanal opcional, lo que garantiza que la alarma se ajuste correctamente a los cambios de zona horaria. Además de programar, también puedes personalizar la apariencia de la alarma. Esto incluye la creación y configuración de botones de alerta, como el botón Descartar, y la configuración del título de la alarma. Para las alarmas con función de cuenta regresiva, también puedes agregar un botón Repetir. Luego se definen la presentación y los atributos de la alerta para especificar cómo se ve y se comporta la alarma cuando se activa. Si una alarma incluye una función de cuenta regresiva, debes implementar una actividad en vivo para mostrar la IU de cuenta regresiva en la pantalla de bloqueo, Dynamic Island y En Espera. Esto implica crear una IU personalizada para la cuenta regresiva y configurar una ActivityConfiguration con los atributos de alarma adecuados. La Actividad en Vivo puede mostrar diferentes vistas dependiendo de si la cuenta regresiva está activa o en pausa, lo que proporciona una experiencia de usuario perfecta en distintos estados del dispositivo. El ejemplo introduce metadatos personalizados para pasar información adicional a la Actividad en Vivo. Estos metadatos incluyen una enumeración personalizada, que permite que la alarma muestre un ícono basado en el valor de la enumeración tanto en la pantalla de bloqueo como en Dynamic Island durante la cuenta regresiva. La sesión describe cómo crear App Intents personalizados para ejecutar código específico cuando se tocan botones, como al abrir la app. También describe cómo configurar el sonido de la alarma, lo que permite elegir un sonido personalizado o usar el sonido predeterminado del sistema.
- 16:32 - Ciclo de vida
AlarmKit permite crear, programar y administrar alarmas usando la clase AlarmManager. Las alarmas se pueden configurar, rastrear a través de identificadores únicos y colocar en varios estados (cuenta regresiva, pausa, detenida, etc.). Las mejores prácticas incluyen el uso de alarmas para cuentas regresivas y alertas recurrentes, garantizar una presentación clara de la alerta e incluir toda la información y las acciones esenciales en la actividad en vivo de la cuenta regresiva.