device_calendar_plus
A modern, maintained Flutter plugin for reading and writing device calendar events on Android and iOS.
0.8.0
8.0K downloads/mo
#3239 most downloaded on pub.dev
bullet-to/device_calendar_plus
What this package is like to depend on
Last release 1 months ago
23 Jul 2026
Ships fairly regularly
a new release about every 6 weeks
Nearly every release is documented
notes for 17 of 17 stable releases
Nothing withdrawn
no release was ever pulled
9 months old
17 releases · first in 2025
17 releases in the last 12 months
see the full history below
Release timeline
17 releases · Nov 2025 to Jul 2026Releases
latest 17-
0.8.023 Jul 2026Release notes
Open source →Per-event color lands, plus one rename to swallow.
Added
Event.colorHex— the event's custom color as#RRGGBB, with a parsedEvent.colorgetter (read-only, mirrorsCalendar.colorHex). Android reads it fromEVENT_COLOR;nullwhen the event just uses its calendar's color, and alwaysnullon iOS (EventKit has no per-event colors). No write support (#117).
Changed
- Breaking:
WeeklyRecurrence'swkstfield and constructor parameter are renamed toweekStart, matching the spelled-out naming of the other recurrence fields. The emitted RRULE is unchanged (stillWKST=). UpdateWeeklyRecurrence(wkst: …)call sites and.wkstreads toweekStart.
Ships
device_calendar_plus0.8.0 anddevice_calendar_plus_android0.7.1. The platform interface and iOS packages are unchanged.Release notes
Open source →Added
Event.colorHex— the event's custom color as#RRGGBB, with a parsedEvent.colorgetter (read-only, mirrorsCalendar.colorHex). Android reads the event's custom color (EVENT_COLOR),nullwhen the event uses its calendar's color; iOS always reportsnull(EventKit has no per-event color). No write support (#117).
Changed
- Breaking:
WeeklyRecurrence'swkstfield and constructor parameter are renamed toweekStart, matching the spelled-out naming of the other recurrence fields (daysOfWeek,daysOfMonth,setPositions, …). The emitted RRULE is unchanged (still uses theWKST=token). UpdateWeeklyRecurrence(wkst: …)call sites and.wkstreads toweekStart.
-
0.7.117 Jun 2026Release notes
Open source →Docs + packaging polish. No code or behaviour changes.
Changed
- Added the
devicepub.dev topic (droppedfederatedto stay within the five-topic limit).
Docs
- Slimmed the README to an overview plus a getting-started snippet, with the worked examples moved into focused topic guides under
doc/. - Trimmed the public API doc comments to the consumer-facing contract and removed native-API implementation details.
Release notes
Open source →Changed
- Add the
devicepub.dev topic (droppedfederatedto stay within the five-topic limit).
Docs
- Slimmed the README to an overview plus a getting-started snippet, and moved
the worked examples into focused topic guides under
doc/. Trimmed the API doc comments to the consumer-facing contract and removed native-API implementation details. No code or behavior changes.
- Added the
-
0.7.017 Jun 2026Release notes
Open source →Feature release. App-facing API is additive;
device_calendar_plus_platform_interfacehas breaking signature changes for platform implementers.Added
- Write-only access —
requestPermissions(level: CalendarAccessLevel.writeOnly)for the gentler add-only prompt (#89). - Automatic permissions —
DeviceCalendar.instance.autoPermissions = AutoPermissionMode.asNeeded | .full; methods request access on first use (#90). - Optional
calendarId— omit it oncreateEventto write to the default calendar (#88). - Event reminders —
reminders: List<Duration>on create,Patch<List<Duration>>on update,Event.remindersread back; minute-granular relative offsets (#87).
Fixed
- Android: honest
permissionDenied(not "no writable calendar") when a default can't be resolved (#112); tighter denial reporting (#108). - Docs: iOS write-only re-prompts and upgrades in-app (#109).
All four packages bumped 0.6.0 → 0.7.0 in lockstep.
Release notes
Open source →Added
- Write-only calendar access.
requestPermissions(level: CalendarAccessLevel.writeOnly)asks for the gentler add-only prompt and a grant reportsCalendarPermissionStatus.writeOnly. On iOS this is not a permanent ceiling — a later full request re-prompts and upgrades the app in-app (#89). - Automatic permission handling. Set
DeviceCalendar.instance.autoPermissionstoAutoPermissionMode.asNeededor.fulland methods request the access they need on first use instead of throwing when permission is undetermined (#90). createEvent'scalendarIdis now optional — omit it to write to the platform's default calendar (iOSdefaultCalendarForNewEvents, Android the primary or first writable calendar). Resolving the default on Android reads the calendar list, so that path needs full access (#88).- Event reminders.
createEventtakesreminders: List<Duration>,updateEventtakesPatch<List<Duration>>, andEvent.remindersis read back. Relative before-start offsets, normalized to whole minutes on both platforms (#87).
- Write-only access —
-
0.6.016 Jun 2026Release notes
Open source →Changed
- Breaking:
updateRecurring()now takesstart: DateTimeinstead ofstartTime: EventTimeOfDay.startis the anchored occurrence's new start; the whole scope translates by the wall-clock delta, so a single call can move the time and the day together — a nightshift 11 PM → 1 AM (crosses midnight) or a weekly meeting Monday → Tuesday. The delta is measured in the event's timezone, so it is DST-safe. (#103, thanks @SuperKrallan) - Breaking:
EventTimeOfDayis removed. - Breaking: all-day events now accept
start(only its date is used) instead of throwing.
Added
updateRecurring()translates implicit-day rules for free: aWeeklyRecurrence()/MonthlyRecurrence()with no pinned day follows the anchor when you move the day.
Behaviour
- Moving the day of a rule that pins it explicitly (
daysOfWeek,daysOfMonth, positional) without also passing arecurrenceRulethrowsDeviceCalendarException(invalidArguments). Moving one day of a multi-day rule is genuinely ambiguous (Mon of Mon/Wed/Fri → Tue could mean Tue/Wed/Fri or Tue/Thu/Sat), so the API hands the decision back to you. Time-only, duration-only and whole-week shifts never throw.
- Breaking:
-
0.5.215 Jun 2026Release notes
Open source →Changed
- No-op updates are now valid instead of throwing.
updateEvent,updateRecurringandupdateCalendarreturn without a platform write when no fields are provided, so "save with no edits" is a harmless no-op rather than anArgumentError(#95).updateRecurringreturns the targeted scope's event id.updateRecurring'sdurationnow accepts zero (an instantaneous event); only a negative duration is rejected.
Fixed
- Recurrence parsing accepts a negative
BYMONTHDAY(e.g.-1for the last day of the month) instead of rejecting the rule (#91) - Turning a recurring occurrence non-recurring with
thisAndFollowing+Patch.clear()now splits the series on iOS instead of collapsing the whole series into one event (#93) — see thedevice_calendar_plus_ioschangelog listEventsreturns every event across spans longer than ~4 years without dropping or duplicating recurring instances (iOS, #94), and includes zero-duration events sitting exactly on the query start (Android, #416) — see the platform changelogscreateCalendarfails with a clear error on iOS sources that can't hold calendars, instead of an opaque failure (#96) — see thedevice_calendar_plus_ioschangelog- iOS EventKit operations run off the main thread, preventing UI stalls on
large calendars (#79) — see the
device_calendar_plus_ioschangelog
Docs
- Documented
listEventsper-instance expansion and theeventId@timestampinstanceId format (#97)
- No-op updates are now valid instead of throwing.
-
0.5.115 Jun 2026Release notes
Open source →- iOS: fix showEventModal(edit: true) crash (#77)
- Docs: clarify showEventModal view modal is not read-only
Release notes
Open source →Fixed
- iOS:
showEventModal(edit: true)no longer crashes (#77) — see thedevice_calendar_plus_ios0.5.1 changelog
Docs
- Clarified
showEventModaldocs: the view modal (edit: false) is not read-only — on both iOS and Android the native screen lets the user edit the event, and those edits are saved directly by the OS
-
0.5.011 Jun 2026Release notes
Open source →Changed
- Breaking:
updateRecurring()is redesigned around series semantics (#69). Times are now expressed asstartTime(EventTimeOfDay) plusdurationinstead of absolutestartDate/endDate, so every occurrence keeps its own date — changing a series' time no longer re-anchors the series to the occurrence you happened to edit (#68, thanks @SuperKrallan). The recurrence rule is now aPatch<RecurrenceRule>:Patch.setreplaces it,Patch.clearcollapses the series into a single event. Returns the event ID of the affected scope. - Breaking:
EventSpan.thisInstanceis gone —EventSpanis now justallEventsandthisAndFollowing. Single occurrences are handled byupdateEvent/deleteEventwith an instance ID (below). - Breaking:
updateEvent()with an instance ID (eventId@timestamp) edits only that occurrence, detaching it from the series; a bare event ID on a recurring event updates the whole series. - Breaking:
deleteEvent()with an instance ID removes only that occurrence; a bare event ID deletes the event (the whole series when recurring).
Added
EventTimeOfDay— small validating hour/minute value class used byupdateRecurring().
Fixed
- Occurrence edits with a
startDatepast the occurrence's untouched end are rejected withinvalidArgumentson iOS too, matching Android, instead of saving an inverted event. - Android: events with no status read back as
EventStatus.noneinstead ofEventStatus.tentative— thanks @mauriziopinotti (#70). - Android: all Calendar Provider work runs on a background thread; large calendars could ANR — thanks @mauriziopinotti (#73).
- Breaking:
-
0.4.025 May 2026Release notes
Open source →Added
updateRecurring()— update a recurring event with a span choice:EventSpan.allEvents(whole series),thisAndFollowing(this occurrence and every later one), orthisInstance(only this occurrence). Can change or remove the recurrence rule. Resolves the long-standing limitation thatupdateEvent()could not edit recurrence. Based on @SuperKrallan (#36)deleteRecurring()— delete part of a recurring event with a span choice:EventSpan.allEvents(whole series),thisAndFollowing(this occurrence and every later one), orthisInstance(only this occurrence). Now supported on both iOS and Android (Android uses EXDATE on the master rather than a cancelled exception event). Based on @SuperKrallan (#43)EventSpanenum for choosing the scope of a recurring-event operation, shared byupdateRecurring()anddeleteRecurring()urlparameter onupdateEvent()— based on @SuperKrallan (#38)editparameter onshowEventModal()— whentrue, opens the native editor directly (EKEventEditViewControlleron iOS,ACTION_EDITon Android) instead of the read-only viewer. Based on @xonaman (#45)Calendar.colorgetter — derived FlutterColor?parsed fromcolorHex, saving consumers from writing the same hex-parsing helper. Based on @xonaman (#46)
Changed
- Breaking:
updateEvent()description,locationandurlnow take aPatch<String>instead of aString.nullleaves the field unchanged,Patch.set(value)assigns a value,Patch.clear()removes it — clearing an optional field was previously impossible.
Fixed
- Missing
availabilityparameter in platform interface test mock — based on @SuperKrallan (#39)
-
0.3.520 Apr 2026Release notes
Open source →Added
listSources()to discover calendar accounts/sources — based on @magic-fit (#14)- Source selection on
createCalendar— iOS viaCreateCalendarOptionsIos(sourceId:), Android via optionalaccountType supportsCalendarCreationonCalendarSourceavailabilityparameter onupdateEvent()— thanks @SuperKrallan (#29)urlfield on events (iOS:EKEvent.url, Android:CUSTOM_APP_URI) — thanks @magic-fit (#32)showCreateEventModal()with optional pre-fill (title, dates, location, description)- Read-only
attendeeson events (name, email, role, status)
Fixed
- Android: all-day events appearing in wrong day's query in non-UTC timezones (#20)
- Android:
hasPermissions()now works from background services without an Activity (#31) - Android: calendar/event queries use application context for background compatibility — thanks @vitalii-vov (#26)
- Android:
notDeterminedpermission status correctly distinguished fromdenied— thanks @Albert221 (#12) - iOS: calendar source lookup fallback when default source is unavailable — thanks @zaqwery (#13)
- iOS:
createCalendardefault fallback now picks iCloud over Gmail CalDAV (#33)
-
0.3.408 Feb 2026 -
0.3.321 Dec 2025Release notes
Open source →Fixed
- Fixed parsing of
instanceIdfor events with@in their event ID (e.g., Google Calendar IDs like[email protected])
- Fixed parsing of
-
0.3.219 Dec 2025Release notes
Open source →Added
- Android:
CreateCalendarOptionsAndroidfor specifying custom account name when creating calendars createCalendar()now accepts optionalplatformOptionsparameter for platform-specific configuration
- Android:
-
0.3.107 Nov 2025Release notes
Open source →Fixed
showEventModal()now properly awaits until the modal is dismissed (iOS and Android)
-
0.3.005 Nov 2025Release notes
Open source →Changed
- BREAKING:
deleteEvent()now requires named parametereventIdand always deletes entire series for recurring events - BREAKING:
updateEvent()now uses named parametereventId(renamed frominstanceId) and always updates entire series for recurring events - BREAKING: Removed
deleteAllInstancesandupdateAllInstancesparameters - operations on recurring events now always affect the entire series - Renamed
getEvent()andshowEventModal()parameter frominstanceIdtoidto clarify that both event IDs and instance IDs are accepted
Removed
- BREAKING:
NOT_SUPPORTEDerror code (no longer needed)
- BREAKING:
-
0.2.005 Nov 2025Release notes
Open source →Added
openAppSettings()method to guide users to system settings when permissions are denied- Testing status documentation in README
Removed
- BREAKING:
getPlatformVersion()method (unused boilerplate)
Changed
- Updated all platform packages to 0.2.0
-
0.1.104 Nov 2025 -
0.1.004 Nov 2025Release notes
Open source →Initial release.
Added
- Calendar permissions management (request/check)
- List device calendars with metadata (name, color, read-only status, primary flag)
- Query events by date range with optional calendar filtering
- Get single event by ID with support for recurring event instances
- Create events with full metadata support
- Update events including single-instance and all-instance updates for recurring events
- Delete events (single or all instances)
- Show native event modal
- All-day event support with floating date behavior
- Timezone handling for timed events
- Typed exception model with
DeviceCalendarExceptionandDeviceCalendarErrorenum - Federated plugin architecture (Android + iOS)
- Support for Android API 24+ (target/compile 35)
- Support for iOS 13+