EventKit in Xamarin.iOS

iOS verfügt über zwei kalenderbezogene Anwendungen: die Kalenderanwendung und die Erinnerungsanwendung. Es ist einfach genug, zu verstehen, wie die Kalenderanwendung Kalenderdaten verwaltet, aber die Erinnerungsanwendung ist weniger offensichtlich. Erinnerungen können tatsächlich Datumsangaben zugeordnet sein, wenn sie fällig sind, wann sie abgeschlossen sind usw. Daher speichert iOS alle Kalenderdaten, unabhängig davon, ob es sich um Kalenderereignisse oder Erinnerungen handelt, an einem Ort, der als Kalenderdatenbank bezeichnet wird.

Das EventKit-Framework bietet eine Möglichkeit, auf die Kalender-, Kalenderereignisse- und Erinnerungsdaten zuzugreifen, die in der Kalenderdatenbank gespeichert werden. Der Zugriff auf die Kalender und Kalenderereignisse ist seit iOS 4 verfügbar, aber der Zugriff auf Erinnerungen ist in iOS 6 neu.

In diesem Leitfaden behandeln wir Folgendes:

  • EventKit-Grundlagen : Hier werden die grundlegenden Teile von EventKit über die Hauptklassen vorgestellt und ein Verständnis ihrer Verwendung vermittelt. Dieser Abschnitt muss gelesen werden, bevor der nächste Teil des Dokuments behandelt wird.
  • Allgemeine Aufgaben : Der Abschnitt "Allgemeine Aufgaben" soll eine Kurzübersicht zu allgemeinen Aufgaben sein, z. B. Auflisten von Kalendern, Erstellen, Speichern und Abrufen von Kalenderereignissen und Erinnerungen sowie Verwendung der integrierten Controller zum Erstellen und Ändern von Kalenderereignissen. Dieser Abschnitt muss nicht front-to-back gelesen werden, da er eine Referenz für bestimmte Aufgaben sein soll.

Alle Aufgaben in diesem Handbuch sind in der Begleitbeispielanwendung verfügbar:

Die Begleitbeispielanwendungsbildschirme

Anforderungen

EventKit wurde in iOS 4.0 eingeführt, aber der Zugriff auf Erinnerungsdaten wurde in iOS 6.0 eingeführt. Daher müssen Sie für die allgemeine EventKit-Entwicklung mindestens Version 4.0 und 6.0 für Erinnerungen als Ziel verwenden.

Darüber hinaus ist die Erinnerungsanwendung im Simulator nicht verfügbar, was bedeutet, dass Erinnerungsdaten ebenfalls nicht verfügbar sind, es sei denn, Sie fügen sie zuerst hinzu. Darüber hinaus werden Zugriffsanforderungen nur für den Benutzer auf dem tatsächlichen Gerät angezeigt. Daher wird die EventKit-Entwicklung am besten auf dem Gerät getestet.

Event Kit-Grundlagen

Bei der Arbeit mit EventKit ist es wichtig, sich mit den gängigen Klassen und deren Verwendung vertraut zu machen. Alle diese Klassen finden Sie in und EventKitEventKitUI (für ).EKEventEditController

EventStore

Die EventStore-Klasse ist die wichtigste Klasse in EventKit, da sie alle Vorgänge in EventKit ausführen muss. Es kann als persistenter Speicher oder Datenbank-Engine für alle EventKit-Daten betrachtet werden. Von EventStore aus haben Sie Zugriff auf die Kalender und Kalenderereignisse in der Kalenderanwendung sowie auf Erinnerungen in der Erinnerungsanwendung.

Da EventStore sie wie eine Datenbank-Engine ist, sollte sie langlebig sein, was bedeutet, dass sie während der Lebensdauer einer Anwendung instance so wenig wie möglich erstellt und zerstört werden sollte. In der Tat wird empfohlen, diesen Verweis für die gesamte Lebensdauer der Anwendung beizubehalten, sobald Sie eine instance einer EventStore in einer Anwendung erstellt haben, es sei denn, Sie benötigen ihn nicht erneut. Darüber hinaus sollten alle Anrufe an eine einzelne EventStore instance. Aus diesem Grund wird das Singleton-Muster empfohlen, um eine einzelne instance verfügbar zu halten.

Erstellen eines Ereignisspeichers

Der folgende Code veranschaulicht eine effiziente Möglichkeit, eine einzelne instance der EventStore Klasse zu erstellen und statisch innerhalb einer Anwendung verfügbar zu machen:

public class App
{
    public static App Current {
            get { return current; }
    }
    private static App current;

    public EKEventStore EventStore {
            get { return eventStore; }
    }
    protected EKEventStore eventStore;

    static App ()
    {
            current = new App();
    }
    protected App () 
    {
            eventStore = new EKEventStore ( );
    }
}

Im obigen Code wird das Singleton-Muster verwendet, um eine instance des EventStore zu instanziieren, wenn die Anwendung geladen wird. Auf EventStore die kann dann global von der Anwendung aus wie folgt zugegriffen werden:

App.Current.EventStore;

Beachten Sie, dass alle Hier gezeigten Beispiele dieses Muster verwenden, sodass sie auf über EventStoreApp.Current.EventStoreverweisen.

Anfordern des Zugriffs auf Kalender- und Erinnerungsdaten

Bevor eine Anwendung über den EventStore auf Daten zugreifen kann, muss eine Anwendung zuerst zugriff auf die Kalenderereignisdaten oder Erinnerungsdaten anfordern, je nachdem, welche Daten Sie benötigen. Um dies zu erleichtern, macht die eine Methode namens RequestAccess verfügbar, die EventStore beim Aufruf dem Benutzer eine Warnungsansicht anzeigt, die ihm mitteilt, dass die Anwendung entweder Zugriff auf die Kalenderdaten oder Erinnerungsdaten anfordert, je nachdem, welche EKEntityType an sie übergeben werden. Da er eine Warnungsansicht auslöst, ist der Aufruf asynchron und ruft einen Vervollständigungshandler auf, der als ein NSAction (oder Lambda) an ihn übergeben wird, der zwei Parameter empfängt: einen booleschen Wert darüber, ob der Zugriff gewährt wurde oder nicht, und ein NSError, der, wenn not-null keine Fehlerinformationen in der Anforderung enthält. Der folgende Code fordert beispielsweise den Zugriff auf Kalenderereignisdaten an und zeigt eine Warnungsansicht an, wenn die Anforderung nicht erteilt wurde.

App.Current.EventStore.RequestAccess (EKEntityType.Event, 
    (bool granted, NSError e) => {
            if (granted)
                    //do something here
            else
                    new UIAlertView ( "Access Denied", 
"User Denied Access to Calendar Data", null,
"ok", null).Show ();
            } );

Sobald die Anforderung erteilt wurde, wird sie gespeichert, solange die Anwendung auf dem Gerät installiert ist und keine Warnung für den Benutzer angezeigt wird. Der Zugriff wird jedoch nur auf den Typ der Ressource gewährt, entweder Kalenderereignisse oder Erinnerungen. Wenn eine Anwendung Zugriff auf beide benötigt, sollte sie beides anfordern.

Da die Berechtigung gespeichert wird, ist es relativ günstig, die Anforderung jedes Mal zu stellen. Daher empfiehlt es sich, immer den Zugriff anzufordern, bevor sie einen Vorgang ausführen.

Da der Vervollständigungshandler außerdem in einem separaten Thread (nicht ui) aufgerufen wird, sollten alle Aktualisierungen der Benutzeroberfläche im Vervollständigungshandler über InvokeOnMainThreadaufgerufen werden, andernfalls wird eine Ausnahme ausgelöst, und wenn nicht abgefangen wird, stürzt die Anwendung ab.

EKEntityType

EKEntityType ist eine Enumeration, die den Typ des Elements oder der EventKit Daten beschreibt. Es verfügt über zwei Werte: Event und Erinnerung. Es wird in einer Reihe von Methoden verwendet, einschließlich EventStore.RequestAccess , um zu ermitteln EventKit , welche Art von Daten zugriff oder abgerufen werden sollen.

EKCalendar

EKCalendar stellt einen Kalender dar, der eine Gruppe von Kalenderereignissen enthält. Kalender können an vielen verschiedenen Orten gespeichert werden, z. B. lokal, in iCloud, an einem Drittanbieterstandort wie einem Exchange Server oder Google usw. Viele Male EKCalendar wird verwendet, um zu sagenEventKit, wo nach Ereignissen gesucht werden soll oder wo sie gespeichert werden sollen.

EKEventEditController

EKEventEditController befindet sich im Namespace und ist ein integrierter Controller, der EventKitUI zum Bearbeiten oder Erstellen von Kalenderereignissen verwendet werden kann. Ähnlich wie bei den integrierten Kameracontrollern übernimmt EKEventEditController das schwere Heben für Sie bei der Anzeige der Benutzeroberfläche und der Handhabung des Speicherns.

EKEvent

EKEvent stellt ein Kalenderereignis dar. Sowohl als EKReminder auch EKEvent erben von EKCalendarItem und verfügen über Felder wie Title, Notesusw.

EKReminder

EKReminder stellt ein Erinnerungselement dar.

EKSpan

EKSpan ist eine Enumeration, die die Spanne von Ereignissen beim Ändern von Ereignissen beschreibt, die sich wiederholen können, und verfügt über zwei Werte: ThisEvent und FutureEvents. ThisEvent bedeutet, dass Änderungen nur für das bestimmte Ereignis in der Reihe auftreten, auf das verwiesen wird, während FutureEvents sich dies auf dieses Ereignis und alle zukünftigen Wiederholungen auswirkt.

Aufgaben

Aus Gründen der Benutzerfreundlichkeit wurde die EventKit-Nutzung in allgemeine Aufgaben unterteilt, die in den folgenden Abschnitten beschrieben werden.

Auflisten von Kalendern

Um die Kalender aufzulisten, die der Benutzer auf dem Gerät konfiguriert hat, rufen GetCalendars Sie den Kalender auf EventStore , und übergeben Sie den Typ der Kalender (entweder Erinnerungen oder Ereignisse), die Sie erhalten möchten:

EKCalendar[] calendars = 
App.Current.EventStore.GetCalendars ( EKEntityType.Event );

Hinzufügen oder Ändern eines Ereignisses mithilfe des integrierten Controllers

Der EKEventEditViewController übernimmt einen Großteil der Aufgaben, wenn Sie ein Ereignis mit derselben Benutzeroberfläche erstellen oder bearbeiten möchten, die dem Benutzer bei verwendung der Kalenderanwendung angezeigt wird:

Die Benutzeroberfläche, die dem Benutzer angezeigt wird, wenn er die Kalenderanwendung verwendet.

Um sie zu verwenden, sollten Sie sie als Variable auf Klassenebene deklarieren, damit sie keinen Müll sammelt, wenn sie innerhalb einer Methode deklariert ist:

public class HomeController : DialogViewController
{
        protected CreateEventEditViewDelegate eventControllerDelegate;
        ...
}

Dann, um es zu starten: Instanziieren Sie es, geben Sie ihm einen Verweis auf , EventStoreverbinden Sie einen EKEventEditViewDelegate-Delegaten mit ihm, und zeigen Sie sie dann mit PresentViewController:

EventKitUI.EKEventEditViewController eventController = 
        new EventKitUI.EKEventEditViewController ();

// set the controller's event store - it needs to know where/how to save the event
eventController.EventStore = App.Current.EventStore;

// wire up a delegate to handle events from the controller
eventControllerDelegate = new CreateEventEditViewDelegate ( eventController );
eventController.EditViewDelegate = eventControllerDelegate;

// show the event controller
PresentViewController ( eventController, true, null );

Optional können Sie, wenn Sie das Ereignis vorab auffüllen möchten, entweder ein brandneues Ereignis erstellen (wie unten gezeigt), oder Sie können ein gespeichertes Ereignis abrufen:

EKEvent newEvent = EKEvent.FromStore ( App.Current.EventStore );
// set the alarm for 10 minutes from now
newEvent.AddAlarm ( EKAlarm.FromDate ( DateTime.Now.AddMinutes ( 10 ) ) );
// make the event start 20 minutes from now and last 30 minutes
newEvent.StartDate = DateTime.Now.AddMinutes ( 20 );
newEvent.EndDate = DateTime.Now.AddMinutes ( 50 );
newEvent.Title = "Get outside and exercise!";
newEvent.Notes = "This is your reminder to go and exercise for 30 minutes.”;

Wenn Sie die Benutzeroberfläche vorab auffüllen möchten, stellen Sie sicher, dass Sie die Event-Eigenschaft auf dem Controller festlegen:

eventController.Event = newEvent;

Informationen zur Verwendung eines vorhandenen Ereignisses finden Sie im Abschnitt Abrufen eines Ereignisses nach ID weiter unten.

Der Delegat sollte die Completed Methode überschreiben, die vom Controller aufgerufen wird, wenn der Benutzer mit dem Dialogfeld fertig ist:

protected class CreateEventEditViewDelegate : EventKitUI.EKEventEditViewDelegate
{
        // we need to keep a reference to the controller so we can dismiss it
        protected EventKitUI.EKEventEditViewController eventController;

        public CreateEventEditViewDelegate (EventKitUI.EKEventEditViewController eventController)
        {
                // save our controller reference
                this.eventController = eventController;
        }

        // completed is called when a user eith
        public override void Completed (EventKitUI.EKEventEditViewController controller, EKEventEditViewAction action)
        {
                eventController.DismissViewController (true, null);
                }
        }
}

Optional können Sie im Delegaten die Aktion in der Completed -Methode überprüfen, um das Ereignis zu ändern und neu zu speichern, oder andere Dinge tun, wenn es abgebrochen wird uswetera:

public override void Completed (EventKitUI.EKEventEditViewController controller, EKEventEditViewAction action)
{
        eventController.DismissViewController (true, null);

        switch ( action ) {

        case EKEventEditViewAction.Canceled:
                break;
        case EKEventEditViewAction.Deleted:
                break;
        case EKEventEditViewAction.Saved:
                // if you wanted to modify the event you could do so here,
// and then save:
                //App.Current.EventStore.SaveEvent ( controller.Event, )
                break;
        }
}

Programmgesteuertes Erstellen eines Ereignisses

Um ein Ereignis im Code zu erstellen, verwenden Sie die FromStore Factory-Methode für die EKEvent -Klasse, und legen Sie alle Daten darauf fest:

EKEvent newEvent = EKEvent.FromStore ( App.Current.EventStore );
// set the alarm for 10 minutes from now
newEvent.AddAlarm ( EKAlarm.FromDate ( DateTime.Now.AddMinutes ( 10 ) ) );
// make the event start 20 minutes from now and last 30 minutes
newEvent.StartDate = DateTime.Now.AddMinutes ( 20 );
newEvent.EndDate = DateTime.Now.AddMinutes ( 50 );
newEvent.Title = "Get outside and do some exercise!";
newEvent.Notes = "This is your motivational event to go and do 30 minutes of exercise. Super important. Do this.";

Sie müssen den Kalender festlegen, in dem das Ereignis gespeichert werden soll. Wenn Sie jedoch keine Einstellung haben, können Sie die Standardeinstellung verwenden:

newEvent.Calendar = App.Current.EventStore.DefaultCalendarForNewEvents;

Um das Ereignis zu speichern, rufen Sie die SaveEvent-Methode für auf EventStore:

NSError e;
App.Current.EventStore.SaveEvent ( newEvent, EKSpan.ThisEvent, out e );

Nach dem Speichern wird die EventIdentifier-Eigenschaft mit einem eindeutigen Bezeichner aktualisiert, der später zum Abrufen des Ereignisses verwendet werden kann:

Console.WriteLine ("Event Saved, ID: " + newEvent.CalendarItemIdentifier);

EventIdentifier ist eine Zeichenfolgenformatierte GUID.

Programmgesteuertes Erstellen einer Erinnerung

Das Erstellen einer Erinnerung im Code ist mit dem Erstellen eines Kalenderereignisses identisch:

EKReminder reminder = EKReminder.Create ( App.Current.EventStore );
reminder.Title = "Do something awesome!";
reminder.Calendar = App.Current.EventStore.DefaultCalendarForNewReminders;

Rufen Sie zum Speichern die SaveReminder-Methode für auf EventStore:

NSError e;
App.Current.EventStore.SaveReminder ( reminder, true, out e );

Abrufen eines Ereignisses nach ID

Um ein Ereignis mit der ID abzurufen, verwenden Sie die EventFromIdentifier-Methode für die EventStore , und übergeben Sie es, das EventIdentifier aus dem Ereignis abgerufen wurde:

EKEvent mySavedEvent = App.Current.EventStore.EventFromIdentifier ( newEvent.EventIdentifier );

Für Ereignisse gibt es zwei weitere Bezeichnereigenschaften, ist aber EventIdentifier die einzige, die dafür funktioniert.

Abrufen einer Erinnerung nach ID

Um eine Erinnerung abzurufen, verwenden Sie die GetCalendarItem-Methode für die EventStore , und übergeben Sie sie an CalendarItemIdentifier:

EKCalendarItem myReminder = App.Current.EventStore.GetCalendarItem ( reminder.CalendarItemIdentifier );

Da GetCalendarItem ein EKCalendarItemzurückgibt, muss es in EKReminder umgewandelt werden, wenn Sie auf Erinnerungsdaten zugreifen oder die instance als später EKReminder verwenden müssen.

Verwenden Sie die Verwendung GetCalendarItem nicht für Kalenderereignisse, da dies zum Zeitpunkt des Schreibens nicht funktioniert.

Löschen eines Ereignisses

Um ein Kalenderereignis zu löschen, rufen Sie RemoveEvent auf, EventStore und übergeben Sie einen Verweis auf das Ereignis und die entsprechende EKSpan:

NSError e;
App.Current.EventStore.RemoveEvent ( mySavedEvent, EKSpan.ThisEvent, true, out e);

Beachten Sie jedoch, dass nach dem Löschen eines Ereignisses der Ereignisverweis lautet null.

Löschen einer Erinnerung

Um eine Erinnerung zu löschen, rufen Sie RemoveReminder auf, EventStore und übergeben Sie einen Verweis auf die Erinnerung:

NSError e;
App.Current.EventStore.RemoveReminder ( myReminder as EKReminder, true, out e);

Beachten Sie, dass im obigen Code eine Umwandlung in EKRemindervorhanden ist, da GetCalendarItem sie zum Abrufen verwendet wurde.

Suchen nach Ereignissen

Um nach Kalenderereignissen zu suchen, müssen Sie ein NSPredicate-Objekt über die PredicateForEvents-Methode für erstellen EventStore. Ein NSPredicate ist ein Abfragedatenobjekt, das iOS verwendet, um Übereinstimmungen zu finden:

DateTime startDate = DateTime.Now.AddDays ( -7 );
DateTime endDate = DateTime.Now;
// the third parameter is calendars we want to look in, to use all calendars, we pass null
NSPredicate query = App.Current.EventStore.PredicateForEvents ( startDate, endDate, null );

Nachdem Sie die NSPredicateerstellt haben, verwenden Sie die EventMatching-Methode für EventStore:

// execute the query
EKCalendarItem[] events = App.Current.EventStore.EventsMatching ( query );

Beachten Sie, dass Abfragen synchron sind (blockieren) und je nach Abfrage lange dauern können, sodass Sie einen neuen Thread oder eine neue Aufgabe starten möchten, um dies zu tun.

Suchen nach Erinnerungen

Die Suche nach Erinnerungen ähnelt Ereignissen. Es erfordert ein Prädikat, aber der Aufruf ist bereits asynchron, sodass Sie sich keine Gedanken über das Blockieren des Threads machen müssen:

// create our NSPredicate which we'll use for the query
NSPredicate query = App.Current.EventStore.PredicateForReminders ( null );

// execute the query
App.Current.EventStore.FetchReminders (
        query, ( EKReminder[] items ) => {
                // do someting with the items
        } );

Zusammenfassung

Dieses Dokument gab einen Überblick über die wichtigen Teile des EventKit-Frameworks und eine Reihe der am häufigsten verwendeten Aufgaben. Das EventKit-Framework ist jedoch sehr umfangreich und leistungsfähig und enthält Features, die hier nicht eingeführt wurden, z. B. Batchupdates, Konfigurieren von Alarmen, Konfigurieren von Wiederholungen für Ereignisse, Registrieren und Lauschen auf Änderungen in der Kalenderdatenbank, Festlegen von GeoFences und mehr. Weitere Informationen finden Sie unter Apples Programmierhandbuch für Kalender und Erinnerungen.