A modern, pure Kotlin CalDAV and iCalendar library for JVM and Android applications.
iCalDAV provides comprehensive support for calendar data interchange and synchronization. It implements the core iCalendar specification (RFC 5545) along with CalDAV (RFC 4791), WebDAV Sync (RFC 6578), and modern extensions for rich event data.
Existing Java/Kotlin calendar libraries fall into two categories:
-
Low-level parsers (like ical4j) - Excellent RFC compliance but require significant work to build sync engines, handle server quirks, or integrate with Android.
-
Connector libraries (like ical4j-connector) - Built on Apache HttpClient, which was removed from Android in API 23 (2015). No incremental sync support.
iCalDAV bridges this gap by providing:
- Modern HTTP stack using OkHttp, native to Android
- Complete sync engine with delta tracking, conflict resolution, and state management
- Server compatibility layer tested against iCloud, Google Calendar, Fastmail, and others
- Kotlin-first API with coroutines, sealed results, and data classes
Libraries in this space operate at different abstraction levels:
- Parser libraries (ical4j, biweekly) - Parse and generate iCalendar content only
- Protocol libraries (dav4jvm) - Handle WebDAV/CalDAV transport, but no parsing or sync logic
- Solution libraries (iCalDAV) - Full stack: parsing + protocol + sync engine
| Feature | iCalDAV | dav4jvm* | ical4j | ical4j-connector | biweekly |
|---|---|---|---|---|---|
| Abstraction Level | Solution | Protocol | Parser | Protocol | Parser |
| RFC 5545 Parsing | Yes (via ical4j) | No | Yes | Yes | Yes |
| RFC 4791 CalDAV | Yes | Yes | No | Yes | No |
| RFC 6578 Sync | Yes | No | No | No | No |
| RFC 7986 Extensions | Yes | N/A | Yes | No | Partial |
| RFC 9073 Rich Events | Yes | N/A | Yes | No | No |
| RFC 9074 VALARM | Yes | N/A | Yes | No | No |
| CardDAV Support | No | Yes | No | Yes | No |
| Android Compatible | Yes | Yes | Yes | No** | Yes |
| Kotlin Coroutines | Yes | Yes | No | No | No |
| Sync State Management | Yes | No | No | No | No |
| ICS Subscriptions | Yes | No | No | No | No |
*dav4jvm is the protocol layer powering DAVx⁵, the popular Android CalDAV/CardDAV sync app
**ical4j-connector uses Apache HttpClient, removed from Android API 23+
- iCalendar Parsing and Generation - Full RFC 5545 support for VEVENT, VTODO, VALARM, VFREEBUSY
- Recurrence Rule Expansion - RRULE, RDATE, EXDATE with comprehensive timezone handling
- CalDAV Client - Calendar discovery, CRUD operations, ETag-based synchronization
- WebDAV Sync - Incremental synchronization with sync-token (RFC 6578)
- ICS Subscriptions - webcal:// URL support with HTTP caching and refresh intervals
- Conflict Resolution - Pluggable strategies for handling sync conflicts
| Extension | RFC | Description |
|---|---|---|
| Color, Images | RFC 7986 | Event colors, thumbnail images, conference URLs |
| Enhanced Alarms | RFC 9074 | Alarm UIDs, acknowledgment, proximity triggers |
| Rich Locations | RFC 9073 | Structured venues with coordinates and addresses |
| Participants | RFC 9073 | Extended attendee information with roles |
| Availability | RFC 7953 | Calendly-style booking availability |
| Relationships | RFC 9253 | Event linking with LINK and enhanced RELATED-TO |
| Module | Description | Dependencies |
|---|---|---|
icalendar-core |
ICS parsing, generation, RRULE expansion | ical4j |
webdav-core |
WebDAV protocol, XML handling | OkHttp |
caldav-core |
CalDAV client, calendar discovery | webdav-core, icalendar-core |
caldav-sync |
Sync engine with conflict resolution | caldav-core |
ics-subscription |
ICS/webcal subscription client | icalendar-core, OkHttp |
dependencies {
// Core iCalendar parsing (required)
implementation("io.github.icaldav:icalendar-core:1.0.0")
// CalDAV client (includes webdav-core)
implementation("io.github.icaldav:caldav-core:1.0.0")
// Sync engine (optional)
implementation("io.github.icaldav:caldav-sync:1.0.0")
// ICS subscriptions (optional)
implementation("io.github.icaldav:ics-subscription:1.0.0")
}implementation 'io.github.icaldav:icalendar-core:1.0.0'
implementation 'io.github.icaldav:caldav-core:1.0.0'import com.icalendar.core.parser.ICalParser
val icsContent = """
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
UID:event-123
DTSTART:20241215T100000Z
DTEND:20241215T110000Z
SUMMARY:Team Meeting
END:VEVENT
END:VCALENDAR
""".trimIndent()
val result = ICalParser.parse(icsContent)
when (result) {
is ParseResult.Success -> {
result.events.forEach { event ->
println("${event.summary} at ${event.dtStart}")
}
}
is ParseResult.Error -> println("Parse error: ${result.message}")
}import com.icalendar.core.generator.ICalGenerator
import com.icalendar.core.model.*
val event = ICalEvent(
uid = "event-123",
importId = "event-123",
summary = "Team Meeting",
dtStart = ICalDateTime.now(),
dtEnd = ICalDateTime.now().plusHours(1),
status = EventStatus.CONFIRMED,
transparency = Transparency.OPAQUE,
// ... other properties
)
val icsContent = ICalGenerator.generate(listOf(event))import com.icalendar.core.recurrence.RRuleExpander
import com.icalendar.core.model.RRule
import com.icalendar.core.model.Frequency
val rrule = RRule(
freq = Frequency.WEEKLY,
interval = 1,
byDay = listOf(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY),
count = 10
)
val instances = RRuleExpander.expand(
rule = rrule,
start = event.dtStart,
rangeEnd = event.dtStart.plusMonths(3),
maxInstances = 100
)import com.icalendar.caldav.client.CalDavClient
import com.icalendar.caldav.discovery.CalDavDiscovery
// Discover calendars
val discovery = CalDavDiscovery(httpClient)
val calendars = discovery.discoverCalendars(
serverUrl = "https://caldav.example.com",
username = "user",
password = "pass"
)
// Fetch events from a calendar
val client = CalDavClient(httpClient)
val result = client.fetchEvents(calendars.first().url)
when (result) {
is DavResult.Success -> result.data.forEach { println(it.event.summary) }
is DavResult.HttpError -> println("HTTP ${result.code}: ${result.message}")
is DavResult.NetworkError -> println("Network error: ${result.exception}")
is DavResult.ParseError -> println("Parse error: ${result.message}")
}import com.icalendar.sync.engine.SyncEngine
import com.icalendar.sync.model.*
val syncEngine = SyncEngine(calDavClient)
val report = syncEngine.sync(
calendarUrl = "https://caldav.example.com/calendar/",
previousState = SyncState.initial(calendarUrl),
localProvider = myLocalProvider,
handler = mySyncHandler,
callback = object : SyncCallback {
override fun onConflict(conflict: SyncConflict): ConflictResolution {
return ConflictResolution.USE_REMOTE
}
}
)
println("Synced: ${report.upserted.size} added, ${report.deleted.size} deleted")Tested and verified with:
| Server | Discovery | CRUD | Sync | Notes |
|---|---|---|---|---|
| Google Calendar | Yes | Yes | Yes | OAuth 2.0 required |
| Apple iCloud | Yes | Yes | Yes | App-specific password required |
| Fastmail | Yes | Yes | Yes | Full RFC compliance |
| Microsoft 365 | Yes | Yes | Yes | Via Outlook CalDAV |
| Nextcloud | Yes | Yes | Yes | Self-hosted |
| Radicale | Yes | Yes | Yes | Lightweight Python server |
| DAViCal | Yes | Yes | Yes | PostgreSQL backend |
| Baikal | Yes | Yes | Yes | PHP-based |
| RFC | Name | Module | Status |
|---|---|---|---|
| RFC 5545 | iCalendar | icalendar-core | Full |
| RFC 4791 | CalDAV | caldav-core | Full |
| RFC 6578 | WebDAV Sync | caldav-sync | Full |
| RFC 4918 | WebDAV | webdav-core | Partial |
| RFC 3744 | WebDAV ACL | webdav-core | Partial |
| RFC | Name | Status |
|---|---|---|
| RFC 7986 | iCalendar Extensions | Full (COLOR, IMAGE, CONFERENCE) |
| RFC 9074 | VALARM Extensions | Full (UID, ACKNOWLEDGED, PROXIMITY) |
| RFC 9073 | Event Publishing | Full (VLOCATION, PARTICIPANT) |
| RFC 7953 | VAVAILABILITY | Full |
| RFC 9253 | Relationships | Full (LINK, enhanced RELATED-TO) |
| Dependency | Version | Purpose |
|---|---|---|
| ical4j | 4.2.2 | iCalendar parsing (RFC 5545) |
| OkHttp | 4.12.0 | HTTP client |
| Kotlin | 1.9.22 | Language runtime |
| kotlinx-coroutines | 1.7.3 | Async operations |
| SLF4J | 2.0.12 | Logging facade |
- JDK 17 or higher
- Android API 26+ (for Android projects)
- CONTRIBUTING.md - Contribution guidelines
Contributions are welcome. Please read our Contributing Guide before submitting pull requests.
For reporting security vulnerabilities, please see our Security Policy.
Copyright 2025 iCalDAV Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- ical4j - Foundation for iCalendar parsing
- OkHttp - HTTP client
- CalConnect - Calendar standards organization