So integrieren Sie die iCloud Calendar API in Ihre App
- Autoren
- Name
- Eraldo Forgoli
- Veröffentlicht am
Inhaltsverzeichnis
Verwenden Sie eine einzige API für alle Kalender
Treten Sie unserer Warteliste für die Unified Calendar API bei, um alle Kalenderanbieter über eine einzige API zu integrieren.
In unserem vorherigen Artikel haben wir erläutert, wie Sie die Google Calendar API in Ihre App integrieren und dabei alle nötigen Schritte zur erfolgreichen Integration aufgezeigt.
Im Gegensatz zu Google Calendar ist die Integration des iCloud-Kalenders nicht so geradlinig, da es kaum Dokumentation gibt und Apple nicht genau darlegt, was Entwickler tun müssen, um iCloud Calendar in eine Anwendung einzubinden.
In diesem Artikel tauchen wir tief in die Integration der iCloud Calendar API ein – einschließlich Authentifizierung, unterstützter Funktionen, Einschränkungen und Tools, die die Integration vereinfachen.
Welche Protokolle und Standards verwendet Apple iCloud Calendar?
Apple iCloud Calendar nutzt den CalDAV-Standard (eine Erweiterung von WebDAV) für die Kalenderkommunikation.
Ereignisse werden im ICS- (iCalendar-) Format gespeichert – einem textbasierten Format für Kalenderdaten. Ihre Anwendung kann also via HTTP mit CalDAV-Anfragen und ICS-Daten mit iCloud-Kalendern kommunizieren.
Vorteil: Die Implementierung ist nicht an Apple-Geräte oder -Betriebssysteme gebunden und kann auf jedem Server unter jedem Betriebssystem eingesetzt werden.
Nachteil: iCloud stellt keine REST-API für Kalender bereit; CalDAV ist daher der einzige Weg, iCloud Calendar in Ihre App einzubinden.
Wir empfehlen eine reine Server-zu-Server-Integration – deshalb führt an CalDAV kein Weg vorbei.
Wie authentifiziert man sich bei iCloud?
Normalerweise legt man bei einer Plattform (z. B. Google Calendar) ein Entwicklerkonto an, erstellt eine App, konfiguriert Scopes, fügt Testnutzer hinzu, trägt App-Informationen ein und lässt alles genehmigen. Danach leitet man den Endnutzer über den OAuth-Dialog zur Einwilligung.
Bei Apple iCloud funktioniert das anders: iCloud bietet keinen standardisierten OAuth-Flow wie Google Calendar oder Outlook. Um den Kalender eines Nutzers zu verbinden, müssen Sie dessen Apple-ID über Basic Authentication (SSL) ansprechen. Da die meisten iCloud-Konten die Zwei-Faktor-Authentifizierung aktiviert haben, muss der Nutzer in seinen Apple-ID-Einstellungen ein app-spezifisches Passwort erstellen, statt sein Hauptpasswort zu nutzen.
Ihre Anwendung fragt also die iCloud-E-Mail/Apple-ID sowie dieses 16-stellige app-spezifische Passwort ab. Mit diesen Daten verbinden Sie sich mit dem iCloud-CalDAV-Dienst.
Beispiel, wie Ihre App E-Mail-Adresse und app-spezifisches Passwort abfragt.
Apple verlangt app-spezifische Passwörter, weil das Weitergeben des Hauptpassworts an Drittanbieter unsicher wäre.
Im HTTP-Header Ihrer Anfrage steht dann:
Authorization: Basic <app-specific-password-here>
Welche Methoden unterstützt die iCloud Calendar API?
Der iCloud-CalDAV-Dienst ist unter caldav.icloud.com
erreichbar. Nach der Authentifizierung stehen diese Operationen bereit:
Auflisten der Kalender eines Nutzers
CRUD-Operationen für Ereignisse
Abrufen einzelner Ereignisse
Weitere Details finden Sie in RFC 4791. Nachfolgend eine Zusammenfassung der wichtigsten Punkte für Ihre iCloud-Integration.
Unterstützte HTTP-Verben
HTTP-Verb | Funktion in CalDAV | iCloud-Unterstützung | Besonderheiten |
---|---|---|---|
OPTIONS | Server-Fähigkeiten ermitteln | ✅ | Gut zum Debuggen; zur Laufzeit meist nicht nötig |
PROPFIND | Principals ermitteln, calendar-home-set abrufen, Kalender auflisten, Eigenschaften lesen | ✅ | Authentifizierung erforderlich; Depth 0 oder 1 |
MKCALENDAR | Neue Kalender-Collection anlegen | ✅ | Schreibrechte erforderlich; siehe Abschnitt 5.3.1 |
REPORT | Daten abfragen (calendar-query , calendar-multiget , free-busy-query ) | ✅ | Alle drei Reports werden unterstützt |
PUT | Eine .ics -Ressource (Ereignis/Aufgabe) hochladen/ersetzen | ✅ | Komplettes VCALENDAR senden; kein PATCH |
DELETE | Ereignis oder Kalender löschen | ✅ | Mit If-Match -ETag kombinieren |
COPY / MOVE | Ereignisse zwischen Kalendern kopieren/verschieben | ✅ | Gleiche Voraussetzungen wie PUT |
GET | Eine .ics -Ressource abrufen | ✅ | Liefert text/calendar und ETag |
Eigenschaften einer Kalender-Collection
Eigenschaft | Zweck | iCloud-spezifische Hinweise |
---|---|---|
CALDAV:calendar-description | Menschlich lesbare Beschreibung | Vollständig unterstützt |
CALDAV:calendar-timezone | Standard-Zeitzone für Abfragen | Unterstützt |
CALDAV:supported-calendar-component-set | Akzeptierte Komponenten (VEVENT, VTODO) | Ereignisse und Aufgaben liegen in separaten Kalendern |
CALDAV:supported-calendar-data | Erlaubte MIME/Version (text/calendar 2.0) | Standardwert bei iCloud |
CALDAV:max-resource-size | Max. Größe pro Ereignis | iCloud-Limit ca. 20 MB |
CALDAV:min/max-date-time , max-instances , max-attendees-per-instance | Diverse Serverlimits | Einhaltung verhindert 403/507-Fehler |
Die OneCal Unified Calendar API steht kurz vor dem Start – tragen Sie sich in unsere Warteliste ein, um informiert zu werden und von Einführungsrabatten zu profitieren.
Welche Bibliotheken erleichtern die Integration?
CalDAV, ICS, XML und iCloud-Spezifika manuell umzusetzen ist aufwendig. Wir empfehlen:
Rolle im Stack | Was tsdav macht | Warum das für iCloud wichtig ist |
---|---|---|
CalDAV/WebDAV-Client | Bietet eine High-Level-TypeScript-API, die alle HTTP-Verben und XML-Operationen kapselt | Fokus auf Business-Logik statt auf rohe XML-Generierung |
Discovery-Helfer | createDAVClient() führt automatisch den iCloud-Discovery-Flow aus: Verbindung zu caldav.icloud.com , Principal ermitteln, calendar-home-set auflösen, endgültige Basis-URL speichern | Spart Boilerplate für die zweistufige Discovery |
Auth-Wrapper | Unterstützt Basic und OAuth 2 (für iCloud: { username, password, authMethod: 'Basic' } ) | Kein manuelles Base64-Kodieren der Zugangsdaten |
Typisierte CRUD-Helfer | fetchCalendars() , fetchCalendarObjects() , createCalendarObject() , updateCalendarObject() , deleteCalendarObject() liefern/akzeptieren reine JS-Objekte | Schnelle CRUD-Implementierung ohne RFC-4791-XML |
Sync-Token-Support | syncCollection() kapselt den REPORT sync-collection , verfolgt Tokens und liefert nur Änderungen/Löschungen | Effizientes Polling (iCloud hat kein Push) |
Browser + Node | Läuft in Node und im Browser dank isomorphic fetch | Nützlich bei Browser-Extensions oder SPAs |
Modernes TS-Projekt | Vollständige Typdefinitionen, tree-shakable ES-Module, minimale Abhängigkeiten | Leicht in moderne Build-Pipelines einzubinden |
tsdav
erstellt keine iCalendar-Dateien. Nutzen Sie dazu ical-generator
(oder eine andere ICS-Bibliothek) zur Erstellung der Event-Payloads.
Weitere nützliche Bibliotheken:
ical-generator
– Erstellt komplette.ics
-Dateien mitsamt Headern, UID, RRULE, Zeitzonen usw.ical.js
– Reine JavaScript-Engine (Mozilla-Projekt) zum Parsen von ICS-Antworten in JS-Objekte.
Beispiel: iCloud-Integration mit tsdav + TypeScript
In diesem Beispiel haben Sie bereits den Benutzernamen und das app-spezifische Passwort des Nutzers.
createClient
DAVClient erzeugen
import { DAVCalendar, DAVClient, DAVNamespaceShort, DAVObject } from "tsdav";
const APPLE_DAV_URL = "https://caldav.icloud.com";
function createClient({
username,
password,
}: {
username: string;
password: string;
}) {
const client = new DAVClient({
serverUrl: APPLE_DAV_URL,
credentials: {
username,
password,
},
authMethod: "Basic",
defaultAccountType: "caldav",
});
return client;
}
constants
Konstanten
export const PROD_ID = {
company: "your-company-name-here",
product: "your-product-name-here",
};
getCalendars
Alle Kalender abrufen
async getCalendars(
...params: Parameters<typeof DAVClient.prototype.fetchCalendars>
): Promise<DAVCalendar[]> {
// You can abstract this initialization into another method.
// For the sake of simplicity, we'll initialize the client on each method.
const client = createClient({
username: <email-here>,
password: <password-here>,
});
return client.fetchCalendars(...params);
}
getCalendarById
Kalender per ID abrufen
async function getCalendarById(calendarUrl: string): Promise<DAVCalendar> {
const calendars = await getCalendars();
const calendar = calendars.find((el) => el.url === calendarUrl);
if (!calendar) {
throw new Error(`Apple-Kalender mit ID ${calendarUrl} nicht gefunden`);
}
return calendar;
}
getCalendarEvents
Ereignisse eines Kalenders abrufen
async function getCalendarEvents(
calendarUrl: string,
query: GetCalendarEventsQuery = {}
) {
const client = createClient({
username: <email-here>,
password: <password-here>,
});
const calendar = await getCalendarById(calendarUrl);
const events = await client.fetchCalendarObjects({
calendar,
timeRange: query.dateRange ?? undefined,
});
return { events, nextSyncToken: calendar.syncToken };
}
getEventById
Ereignis per ID abrufen
async function getEventById(calendarUrl: string, eventId: string) {
const client = createClient({
username: <email-here>,
password: <password-here>,
});
const eventUrl = new URL(`${eventId}.ics`, calendarUrl).pathname;
const responses = await client.calendarMultiGet({
url: calendarUrl,
props: {
[`${DAVNamespaceShort.DAV}:getetag`]: {},
[`${DAVNamespaceShort.CALDAV}:calendar-data`]: {},
},
objectUrls: [eventUrl],
depth: "1",
});
if (responses.length === 0) {
throw new Error(`Keine Antwort beim Abrufen von ${eventUrl}`);
} else if (responses[0].status >= 400) {
throw new Error(
`Fehler beim Abrufen des Apple-Ereignisses. Status: ${responses[0].statusText}`
);
}
const response = responses[0];
const calendarObject: DAVObject = {
url: new URL(response.href ?? "", calendarUrl).href,
etag: `${response.props?.getetag}`,
data: response.props?.calendarData?._cdata ?? response.props?.calendarData,
};
return calendarObject;
}
createEvent
Ereignis erstellen
async function createEvent(calendarUrl: string, data: AppleEvent) {
const client = createClient({
username: <email-here>,
password: <password-here>,
});
const eventId = data.id ?? <generate-id-here>;
const calendar = ical({
prodId: PROD_ID,
method: ICalCalendarMethod.REQUEST,
});
const event = calendar.createEvent({ ...data, id: eventId });
const response = await client.createCalendarObject({
calendar: { url: calendarUrl },
filename: `${event.id()}.ics`,
iCalString: calendar.toString(),
});
if (!response.ok) {
throw new Error(
`Fehler beim Erstellen des Apple-Ereignisses: ${response.statusText}`
);
}
return { id: event.id(), eventWithExceptions };
}
updateEvent
Ereignis aktualisieren
async function updateEvent(
calendarUrl: string,
eventId: string,
data: AppleEvent
) {
const client = createClient({
username: <email-here>,
password: <password-here>,
});
const originalEventData = await getEventById(calendarUrl, eventId);
const calendar = ical({
prodId: PROD_ID,
method: ICalCalendarMethod.REQUEST,
});
for (let event of originalEventData) {
if (event.status === ICalEventStatus.CANCELLED) continue;
if (event.id === eventId) {
calendar.createEvent({ ...event, ...data, id: eventId, url: null });
} else {
calendar.createEvent({ ...event, id: eventId, url: null });
}
}
const calendarObjectUrl = new URL(`${eventId}.ics`, calendarUrl);
const response = await client.updateCalendarObject({
calendarObject: {
url: calendarObjectUrl.href,
data: calendar.toString(),
},
});
if (!response.ok) {
throw new Error(
`Fehler beim Aktualisieren des Apple-Ereignisses: ${response.statusText}`
);
}
return getEventById(calendarUrl, eventId);
}
deleteEvent
Ereignis löschen
async function deleteEvent(calendarUrl: string, eventId: string) {
const client = createClient({
username: <email-here>,
password: <password-here>,
});
const calendarObjectUrl = new URL(`${eventId}.ics`, calendarUrl);
const response = await client.deleteCalendarObject({
calendarObject: {
url: calendarObjectUrl.href,
},
});
if (!response.ok) {
throw new Error(
`Fehler beim Löschen des Apple-Ereignisses: ${response.statusText}`
);
}
return { id: eventId };
}
Welche Einschränkungen hat Apple iCloud Calendar?
Basic Auth mit app-spezifischem Passwort – Kein OAuth 2.0.
Keine Webhooks/Push-Benachrichtigungen – Es müssen Polling-Lösungen mit
sync-collection
gebaut werden.Kein PATCH – Ereignisse müssen vollständig per PUT überschrieben werden.
Keine manuelle Kontrolle über Einladungen – iCloud versendet Einladungen automatisch (Outbox/Inbox nicht verfügbar).
Gibt es einen einfacheren Weg, iCloud Calendar zu integrieren?
Die manuelle Integration von iCloud Calendar ist komplex und weicht von gängigen Kalender-Standards ab. Eine Unified Calendar API bietet:
Gut dokumentierte, getestete API nach modernen Standards
Weniger Entwicklungs- und Wartungsaufwand
Integration weiterer Kalenderanbieter (Google Calendar, Outlook) ohne Zusatzarbeit
Push-Benachrichtigungen ohne eigene Polling-Lösung
Nutzen Sie eine Unified Calendar API für die iCloud-Integration
Unsere OneCal Unified Calendar API steht kurz vor dem Start. Melden Sie sich für die Warteliste an, um sofort benachrichtigt zu werden und von Einführungsrabatten zu profitieren.