One.Calendar reads and writes events through EventKit. Give the app a
purpose string before prebuild:
calendar: { usage: 'Show and manage your events.', remindersUsage: 'Show and manage your reminders.',}Expo-prebuilt apps pass the same calendar option to the VXRN Expo plugin.
The event and reminders purpose strings are independent. Configure only the
one an app uses. Prebuild sets NSCalendarsFullAccessUsageDescription and
NSRemindersFullAccessUsageDescription for the strings supplied.
import { One } from 'one'
const status = await One.Calendar.requestPermission()if (status === 'fullAccess') { const startMs = Date.now() + 86_400_000 const identifier = await One.Calendar.create({ title: 'Team review', startMs, endMs: startMs + 3_600_000, }) const events = await One.Calendar.list(startMs - 1, startMs + 3_600_001) const event = events.find((item) => item.identifier === identifier) if (event) { const updated = await One.Calendar.update(event.identifier, event.startMs, { title: 'Team review moved', startMs: event.startMs + 3_600_000, endMs: event.endMs + 3_600_000, location: 'Room 4', }) await One.Calendar.delete(updated.identifier, updated.startMs) }}getPermissionStatus() reads the status without prompting. It returns
notDetermined, restricted, denied, writeOnly, or fullAccess.
requestPermission() requests full access and resolves to the resulting
status, including when the person denies it. Reading events requires full
access; write-only access does not permit reading even events the app created.
list(startMs, endMs, limit = 100) searches all visible calendars. Times are
Unix milliseconds. The range must increase and span at most 366 days; the
limit must be a whole number from 1 to 500. Events are sorted by start time
and include their identifier, title, start and end times, all-day flag, and
location. create({ title, startMs, endMs, allDay? }) saves to the default
writable calendar and returns the identifier. delete(identifier, startMs)
removes the occurrence at that exact start time. Pass the startMs returned
by list for a recurring event, since its occurrences share an identifier.
update(identifier, originalStartMs, changes) edits that occurrence and returns
its new fields, including the identifier and start time to use for later edits
or deletion. Pass one or more of title, startMs, endMs, allDay, or
location; omitted fields keep their current values. Pass an empty location to
clear it. Ask the person before creating, editing, or deleting an event.
To create a repeating event, pass a recurrence rule to create:
await One.Calendar.create({ title: 'Review notes', startMs, endMs: startMs + 3_600_000, recurrence: { frequency: 'weekly', interval: 2, occurrenceCount: 8 },})The frequency is daily, weekly, monthly, or yearly; interval defaults
to 1. Choose at most one end: occurrenceCount or endDateMs. Leave both out
for an ongoing series. The interval must be a whole number from 1 to 1,000;
the occurrence count must be a whole number from 1 to 10,000. list includes
the rule in each occurrence’s optional recurrence field. update and
delete change only the selected occurrence, not the whole series. Use the
occurrence’s own startMs when changing it.
Apple’s EventKit recurrence guide
describes these rules.
getRemindersPermissionStatus() reads reminders access without a prompt.
requestRemindersPermission() requests full reminders access and resolves to
the resulting status, including denial. It requires calendar.remindersUsage.
if (await One.Calendar.requestRemindersPermission() === 'fullAccess') { const identifier = await One.Calendar.createReminder({ title: 'Send the report', dueMs: Date.now() + 86_400_000, }) const reminders = await One.Calendar.listReminders() await One.Calendar.setReminderCompleted(identifier, true) const history = await One.Calendar.listReminders(100, true) await One.Calendar.deleteReminder(identifier)}listReminders(limit = 100, includeCompleted = false) reads incomplete reminders
from visible lists. Pass true to include completed reminders. Results are
ordered by due date with undated reminders last. The limit is a whole number
from 1 to 500. Each item has an identifier, title, completion flag, and
optional due time in Unix milliseconds. createReminder saves to
the default writable reminders list. Ask the person before changing or
deleting reminders.
createReminder accepts the same optional recurrence rule as events when
dueMs is supplied. A listed reminder includes its rule in recurrence.
EventKit exposes only the first incomplete reminder in a repeating set,
so completing it makes the next due reminder available. Use listReminders
again after completion to read the new occurrence.
Missing reminders purpose text rejects with E_REMINDERS_MANIFEST; missing
full access with E_REMINDERS_PERMISSION; invalid input with
E_REMINDERS_INPUT. A missing default list gives E_REMINDERS_UNAVAILABLE.
Writes use E_REMINDERS_SAVE or E_REMINDERS_DELETE, and an unknown identifier
uses E_REMINDERS_NOT_FOUND.
Missing purpose text rejects with E_CALENDAR_MANIFEST; missing full access
with E_CALENDAR_PERMISSION; invalid input with E_CALENDAR_INPUT.
An absent writable calendar gives E_CALENDAR_UNAVAILABLE. Store failures
use E_CALENDAR_SAVE or E_CALENDAR_DELETE; editing or deleting an unknown
occurrence gives E_CALENDAR_NOT_FOUND. Calendar events are implemented on iOS and Android. On Android, events run over CalendarContract with native.app.calendar.usage; single-occurrence edits become exceptions that keep sibling occurrences. Reminders stay unavailable on Android and web: denied reminder permissions and empty lists. Calls that create or update a reminder reject with Calendar.<verb> needs an iOS or Android build; reminder completion and deletion do nothing.
See Apple’s EventKit access guide for the full and write-only permission modes.
Edit this page on GitHub.