expo-alarm-kit
v0.1.6
Published
An Expo module for iOS AlarmKit integration - schedule native alarms with optional app launch on dismissal
Downloads
472
Maintainers
Readme
expo-alarm-kit
An Expo module for iOS AlarmKit integration. Schedule native iOS alarms with optional app launch on dismissal or snooze intents.
⚠️ Requirements:
- iOS Deployment Target: 26.0+
- Expo SDK: 50+
- Framework: Apple AlarmKit
Features
- 📅 Schedule Native Alarms: Create alarms that persist even if the app is killed.
- 🔄 Repeating Alarms: Support for weekly repeating schedules.
- 🚀 App Launch Triggers: Optionally launch your app when the user dismisses or snoozes the alarm.
- 🧩 Custom Intent Payloads: Attach optional payload strings for dismiss/snooze events.
- 🎨 Customization: Configure titles, snooze settings, and tint colors.
- 💾 Shared State: Uses App Groups to synchronize alarm state between the system and your app.
Installation
npm install expo-alarm-kit
# or
yarn add expo-alarm-kit
Since this module utilizes native iOS frameworks, you must prebuild your project:
npx expo prebuild
Configuration (Required)
This module requires native iOS configuration to function. If these steps are skipped, the module will throw errors.
1. Set Deployment Target
In Xcode, navigate to your project's Build Settings and ensure the iOS Deployment Target is set to 26.0 or higher.
❌ Error: Failing to do this will result in a "Module not found: ExpoAlarmKit" error.
2. Add Usage Description
Apple requires you to justify why you need access to alarms.
- Open your project in Xcode.
- Select your app target and go to the Info tab.
- Add a new key:
Privacy - Alarm Kit Usage Description. - Value: Enter a short description (e.g., "We use alarms to wake you up at your scheduled times.")
3. Configure App Groups
App Groups allow the Alarm extension to communicate with your main application.
- In Xcode, select your app target.
- Go to Signing & Capabilities.
- Click + Capability and select App Groups.
- Add a new group identifier (e.g.,
group.com.yourcompany.yourapp).
Important: This identifier must match exactly what you pass to the
configure()method in your JavaScript code.
Usage
1. Initialization
You must configure the module with your App Group ID as early as possible in your app's lifecycle (e.g., inside App.tsx or _layout.tsx).
import { useEffect } from 'react';
import { configure, getLaunchPayload } from 'expo-alarm-kit';
export default function App() {
useEffect(() => {
// 1. Initialize the module
const isConfigured = configure('group.com.yourcompany.yourapp');
if (!isConfigured) {
console.error('Failed to configure ExpoAlarmKit. Check App Group ID.');
}
// 2. Check if app was launched via an alarm dismiss/snooze intent
const payload = getLaunchPayload();
if (payload) {
console.log('App launched by alarm:', payload.alarmId);
// Navigate to specific screen or perform action
}
}, []);
return <YourAppContent />;
}
2. Scheduling Alarms
import {
scheduleAlarm,
scheduleRepeatingAlarm,
generateUUID,
requestAuthorization
} from 'expo-alarm-kit';
const handleSchedule = async () => {
// Always request permission first
const authStatus = await requestAuthorization();
if (authStatus !== 'authorized') return;
// Example: Schedule a one-time alarm for 1 hour from now
const alarmId = generateUUID();
await scheduleAlarm({
id: alarmId,
epochSeconds: Date.now() / 1000 + 3600,
title: 'Power Nap Over',
soundName: 'alarm.wav', // Must be in Xcode bundle resources
launchAppOnDismiss: true,
dismissPayload: 'nap-dismiss',
doSnoozeIntent: true,
launchAppOnSnooze: true,
snoozePayload: 'nap-snooze',
snoozeDuration: 300, // 5 minutes
});
};
const handleRepeatingSchedule = async () => {
// Example: Schedule for Mon-Fri at 7:30 AM
const id = generateUUID();
await scheduleRepeatingAlarm({
id,
hour: 7,
minute: 30,
weekdays: [2, 3, 4, 5, 6], // 1=Sun, 2=Mon...
title: 'Work Alarm',
launchAppOnDismiss: true,
dismissPayload: 'work-dismiss',
doSnoozeIntent: true,
launchAppOnSnooze: false,
snoozePayload: 'work-snooze',
});
};
3. Managing Alarms
import { cancelAlarm, getAllAlarms } from 'expo-alarm-kit';
// Get list of active alarm IDs
const activeAlarms = getAllAlarms();
// Cancel a specific alarm
await cancelAlarm('your-alarm-uuid');
How It Works
App Groups & Shared Storage
This module relies on iOS App Groups to share UserDefaults between the main app process and the system alarm extension.
- Persistence: When you schedule an alarm, the metadata is written to this shared storage.
- Sync: Both the Native Module and the App Extension read from this same source of truth.
App Launch on Dismiss/Snooze
When launchAppOnDismiss: true or (doSnoozeIntent: true + launchAppOnSnooze: true) is set:
- The user dismisses or snoozes the alarm on the lock screen.
- The system launches your app in the background/foreground.
- The module writes a
LaunchPayloadto the shared storage. - When your React Native JS bundle loads, calling
getLaunchPayload()retrieves and clears this data, allowing you to react to the event.
API Reference
Configuration & Auth
configure(appGroupIdentifier: string): boolean
Initializes the module. Must be called before other methods.
- Returns:
trueif the App Group was accessible.
requestAuthorization(): Promise<AuthorizationStatus>
Prompts the user for permission to schedule alarms.
- Returns:
'authorized' | 'denied' | 'notDetermined'
Scheduling
scheduleAlarm(options): Promise<boolean>
Schedules a non-repeating alarm.
Options Object:
| Property | Type | Required | Description |
| --- | --- | --- | --- |
| id | string | Yes | Unique UUID. |
| epochSeconds | number | No* | Unix timestamp (seconds) for the alarm. |
| date | Date | No* | Alternative: JS Date object. |
| title | string | Yes | Main text displayed on lock screen. |
| soundName | string | No | Filename of sound in app bundle. |
| launchAppOnDismiss | boolean | No | If true, opens app when stopped. |
| dismissPayload | string | No | Optional payload string for dismiss intent (null in payload if omitted). |
| doSnoozeIntent | boolean | No | If true, enables custom snooze intent (default: false). |
| launchAppOnSnooze | boolean | No | If true, opens app when snooze intent runs. |
| snoozePayload | string | No | Optional payload string for snooze intent (null in payload if omitted). |
| stopButtonLabel | string | No | Text for stop button (default: 'Stop'). |
| snoozeButtonLabel | string | No | Text for snooze button. |
| stopButtonColor | string | No | Hex color string. |
| snoozeButtonColor | string | No | Hex color string. |
| tintColor | string | No | Overall UI tint color. |
| snoozeDuration | number | No | Duration in seconds (default: 540). |
*Note: Provide either epochSeconds OR date, not both.
scheduleRepeatingAlarm(options): Promise<boolean>
Schedules a weekly repeating alarm.
Options Object:
| Property | Type | Required | Description |
| --- | --- | --- | --- |
| id | string | Yes | Unique UUID. |
| hour | number | Yes | 0-23 |
| minute | number | Yes | 0-59 |
| weekdays | number[] | Yes | Array of integers: 1 (Sun) to 7 (Sat). |
| title | string | Yes | Main text displayed. |
| launchAppOnDismiss | boolean | No | If true, opens app when stopped. |
| dismissPayload | string | No | Optional payload string for dismiss intent (null in payload if omitted). |
| doSnoozeIntent | boolean | No | If true, enables custom snooze intent (default: false). |
| launchAppOnSnooze | boolean | No | If true, opens app when snooze intent runs. |
| snoozePayload | string | No | Optional payload string for snooze intent (null in payload if omitted). |
| ... | ... | ... | Supports all visual options from scheduleAlarm. |
Utilities
cancelAlarm(id: string): Promise<boolean>
Cancels the alarm in AlarmKit and removes it from shared storage.
generateUUID(): string
Helper to generate a unique ID string for new alarms.
getAllAlarms(): string[]
Returns an array of IDs for all currently scheduled alarms.
getLaunchPayload(): LaunchPayload | null
Returns data if the app was launched via an alarm.
interface LaunchPayload {
alarmId: string;
payload: string | null;
}
removeAlarm(id: string): void
Advanced: Removes an alarm from local storage records without cancelling the native AlarmKit instance. Use cancelAlarm for standard usage.
Known Issues
- Custom Labels/Colors: The
stopButtonLabel,stopButtonColorproperties are not correctly modifying the stop button/slider.
