EventKit no Xamarin.iOS
O iOS tem dois aplicativos relacionados ao calendário integrados: o Aplicativo de Calendário e o Aplicativo de Lembretes. É simples o suficiente para entender como o Aplicativo de Calendário gerencia dados de calendário, mas o Aplicativo de Lembretes é menos óbvio. Os lembretes podem realmente ter datas associadas a eles em termos de quando são devidos, quando são concluídos, etc. Como tal, o iOS armazena todos os dados do calendário, sejam eventos de calendário ou lembretes, em um local, chamado Banco de Dados de Calendário.
A estrutura do EventKit fornece uma maneira de acessar os dados de Calendários, Eventos de Calendário e Lembretes que o Banco de Dados de Calendário armazena. O acesso aos calendários e eventos do calendário está disponível desde o iOS 4, mas o acesso aos lembretes é novo no iOS 6.
Neste guia, abordaremos:
- Noções básicas do EventKit – Isso introduzirá as peças fundamentais do EventKit por meio das classes principais e fornecerá uma compreensão de seu uso. Esta seção é leitura obrigatória antes de abordar a próxima parte do documento.
- Tarefas comuns – A seção de tarefas comuns destina-se a ser uma referência rápida sobre como fazer coisas comuns, como enumerar calendários, criar, salvar e recuperar eventos e lembretes de calendário, bem como usar os controladores internos para criar e modificar eventos de calendário. Esta seção não precisa ser lida de frente para trás, pois deve ser uma referência para tarefas específicas.
Todas as tarefas neste guia estão disponíveis no aplicativo de exemplo complementar:
Requisitos
O EventKit foi introduzido no iOS 4.0, mas o acesso aos dados dos Lembretes foi introduzido no iOS 6.0. Como tal, para fazer o desenvolvimento geral do EventKit, você precisará direcionar pelo menos a versão 4.0 e 6.0 para lembretes.
Além disso, o aplicativo Lembretes não está disponível no simulador, o que significa que os dados dos lembretes também não estarão disponíveis, a menos que você os adicione primeiro. Além disso, as solicitações de acesso só são mostradas ao usuário no dispositivo real. Como tal, o desenvolvimento do EventKit é melhor testado no dispositivo.
Noções básicas do kit de eventos
Ao trabalhar com o EventKit, é importante ter uma compreensão das classes comuns e seu uso. Todas essas classes podem ser encontradas no EventKit
e EventKitUI
(para o EKEventEditController
).
EventStore
A classe EventStore é a classe mais importante no EventKit porque é necessária para executar quaisquer operações no EventKit. Ele pode ser considerado como o armazenamento persistente, ou mecanismo de banco de dados, para todos os dados do EventKit. A partir de EventStore
você tem acesso aos calendários e eventos de calendário no Aplicativo de Calendário, bem como lembretes no Aplicativo de Lembretes.
Como EventStore
é como um mecanismo de banco de dados, ele deve ser de longa duração, o que significa que ele deve ser criado e destruído o mínimo possível durante o tempo de vida de uma instância de aplicativo. Na verdade, é recomendável que, depois de criar uma instância de um EventStore
em um aplicativo, você mantenha essa referência por toda a vida útil do aplicativo, a menos que tenha certeza de que não precisará dela novamente. Além disso, todas as chamadas devem ir para uma única EventStore
instância. Por esse motivo, o padrão Singleton é recomendado para manter uma única instância disponível.
Criando um repositório de eventos
O código a seguir ilustra uma maneira eficiente de criar uma única instância da EventStore
classe e disponibilizá-la estaticamente de dentro de um aplicativo:
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 ( );
}
}
O código acima usa o padrão Singleton para instanciar uma instância do EventStore
quando o aplicativo é carregado. O EventStore
pode então ser acessado globalmente de dentro do aplicativo da seguinte maneira:
App.Current.EventStore;
Observe que todos os exemplos aqui usam esse padrão, então eles fazem referência à EventStore
via App.Current.EventStore
.
Solicitando acesso a dados de calendário e lembrete
Antes de ter permissão para acessar quaisquer dados por meio do EventStore, um aplicativo deve primeiro solicitar acesso aos dados de eventos do calendário ou aos dados de lembretes, dependendo de qual deles você precisa. Para facilitar isso, o EventStore
expõe um método chamado RequestAccess
que, quando chamado, mostrará uma exibição de alerta para o usuário informando que o aplicativo está solicitando acesso aos dados do calendário ou aos dados do lembrete, dependendo do que EKEntityType
é passado para ele. Como gera uma exibição de alerta, a chamada é assíncrona e chamará um manipulador de conclusão passado como um NSAction
(ou Lambda) para ele, que receberá dois parâmetros: um booleano de se o acesso foi concedido ou não e um NSError
, que, se não-nulo, conterá qualquer informação de erro na solicitação. Por exemplo, o código a seguir solicitará acesso aos dados de eventos do calendário e mostrará uma exibição de alerta se a solicitação não tiver sido concedida.
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 ();
} );
Uma vez que a solicitação tenha sido concedida, ela será lembrada desde que o aplicativo esteja instalado no dispositivo e não aparecerá um alerta para o usuário. No entanto, o acesso é dado apenas ao tipo de recurso, eventos de calendário ou lembretes concedidos. Se um aplicativo precisar de acesso a ambos, ele deve solicitar ambos.
Como a permissão é lembrada, é relativamente barato fazer a solicitação todas as vezes, por isso é uma boa ideia sempre solicitar acesso antes de executar uma operação.
Além disso, como o manipulador de conclusão é chamado em um thread separado (não-interface do usuário), quaisquer atualizações para a interface do usuário no manipulador de conclusão devem ser chamadas via InvokeOnMainThread
, caso contrário, uma exceção será lançada e, se não for capturada, o aplicativo falhará.
EKEntityType
EKEntityType
é uma enumeração que descreve o tipo de EventKit
item ou dados. Ele tem dois valores: Event
e Lembrete. Ele é usado em vários métodos, inclusive EventStore.RequestAccess
para dizer EventKit
que tipo de dados obter acesso ou recuperar.
EKCalendar
EKCalendar representa um calendário, que contém um grupo de eventos de calendário. Os calendários podem ser armazenados em muitos lugares diferentes, como localmente, no iCloud, em um local de provedor de terceiros 3rd, como um Exchange Server ou Google, etc. Muitas vezes EKCalendar
é usado para dizer EventKit
onde procurar eventos, ou onde salvá-los.
EKEventEditController
EKEventEditController pode ser encontrado no EventKitUI
namespace e é um controlador interno que pode ser usado para editar ou criar eventos de calendário. Muito parecido com os controladores de câmera integrados, EKEventEditController
faz o trabalho pesado para você na exibição da interface do usuário e manipulação de economia.
EKEvent
EKEvent representa um evento de calendário. Ambos EKEvent
e EKReminder
herdam de EKCalendarItem
e têm campos como Title
, Notes
e assim por diante.
EKReminder
EKReminder representa um item de lembrete.
EKSpan
EKSpan é uma enumeração que descreve a extensão de eventos ao modificar eventos que podem ocorrer novamente e tem dois valores: ThisEvent e FutureEvents. ThisEvent
significa que quaisquer alterações ocorrerão apenas no evento específico da série que está sendo referenciada, enquanto FutureEvents
afetarão esse evento e todas as recorrências futuras.
Tarefas
Para facilitar o uso, o uso do EventKit foi dividido em tarefas comuns, descritas nas seções a seguir.
Enumerar calendários
Para enumerar os calendários que o usuário configurou no dispositivo, chame GetCalendars
o EventStore
e passe o tipo de calendários (lembretes ou eventos) que você deseja receber:
EKCalendar[] calendars =
App.Current.EventStore.GetCalendars ( EKEntityType.Event );
Adicionar ou modificar um evento usando o controlador interno
O EKEventEditViewController faz muito do trabalho pesado para você se você quiser criar ou editar um evento com a mesma interface do usuário que é apresentada ao usuário ao usar o aplicativo de calendário:
Para usá-lo, convém declará-lo como uma variável de nível de classe para que ele não seja coletado de lixo se for declarado dentro de um método:
public class HomeController : DialogViewController
{
protected CreateEventEditViewDelegate eventControllerDelegate;
...
}
Em seguida, para iniciá-lo: instancie-o, dê-lhe uma referência ao EventStore
, conecte um delegado EKEventEditViewDelegate a ele e, em seguida, exiba-o usando 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 );
Opcionalmente, se você quiser preencher previamente o evento, poderá criar um novo evento (conforme mostrado abaixo) ou recuperar um evento salvo:
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.”;
Se você deseja preencher previamente a interface do usuário, certifique-se de definir a propriedade Event no controlador:
eventController.Event = newEvent;
Para usar um evento existente, consulte a seção Recuperar um evento por ID mais adiante.
O delegado deve substituir o Completed
método, que é chamado pelo controlador quando o usuário termina de usar a caixa de diálogo:
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);
}
}
}
Opcionalmente, no delegado, você pode marcar a Completed
Ação no método para modificar o evento e salvar novamente, ou fazer outras coisas, se for cancelado, etc:
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;
}
}
Criando um evento programaticamente
Para criar um evento no código, use o método de fábrica FromStore na EKEvent
classe e defina todos os dados nela:
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.";
Você deve definir o calendário no qual deseja salvar o evento, mas se não tiver preferência, poderá usar o padrão:
newEvent.Calendar = App.Current.EventStore.DefaultCalendarForNewEvents;
Para salvar o evento, chame EventStore
o método SaveEvent no :
NSError e;
App.Current.EventStore.SaveEvent ( newEvent, EKSpan.ThisEvent, out e );
Depois de salva, a propriedade EventIdentifier será atualizada com um identificador exclusivo que pode ser usado posteriormente para recuperar o evento:
Console.WriteLine ("Event Saved, ID: " + newEvent.CalendarItemIdentifier);
EventIdentifier
é um GUID formatado em cadeia de caracteres.
Criar um lembrete programaticamente
Criar um lembrete no código é o mesmo que criar um evento de calendário:
EKReminder reminder = EKReminder.Create ( App.Current.EventStore );
reminder.Title = "Do something awesome!";
reminder.Calendar = App.Current.EventStore.DefaultCalendarForNewReminders;
Para salvar, chame o método SaveReminder no EventStore
:
NSError e;
App.Current.EventStore.SaveReminder ( reminder, true, out e );
Recuperando um evento por ID
Para recuperar um evento por sua ID, use o método EventFromIdentifier no EventStore
e passe-o para o EventIdentifier
que foi retirado do evento:
EKEvent mySavedEvent = App.Current.EventStore.EventFromIdentifier ( newEvent.EventIdentifier );
Para eventos, há duas outras propriedades de identificador, mas EventIdentifier
é a única que funciona para isso.
Recuperando um lembrete por ID
Para recuperar um lembrete, use o método GetCalendarItem no EventStore
e passe-lhe o CalendarItemIdentifier:
EKCalendarItem myReminder = App.Current.EventStore.GetCalendarItem ( reminder.CalendarItemIdentifier );
Porque GetCalendarItem
retorna um EKCalendarItem
, ele deve ser convertido para EKReminder
se você precisar acessar dados de lembrete ou usar a instância como um EKReminder
posterior.
Não use GetCalendarItem
para eventos do calendário, pois no momento em que escrevo, ele não funciona.
Excluindo um evento
Para excluir um evento de calendário, chame RemoveEvent em seu EventStore
e passe uma referência ao evento e o apropriado EKSpan
:
NSError e;
App.Current.EventStore.RemoveEvent ( mySavedEvent, EKSpan.ThisEvent, true, out e);
No entanto, depois que um evento for excluído, a referência do evento será null
.
Excluindo um lembrete
Para excluir um lembrete, chame EventStore
RemoveReminder no e passe uma referência para o lembrete:
NSError e;
App.Current.EventStore.RemoveReminder ( myReminder as EKReminder, true, out e);
Observe que no código acima há um cast para EKReminder
, porque GetCalendarItem
foi usado para recuperá-lo
Procurando Eventos
Para procurar eventos de calendário, você deve criar um objeto NSPredicate por meio do método PredicateForEvents no EventStore
. An NSPredicate
é um objeto de dados de consulta que o iOS usa para localizar correspondências:
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 );
Depois de criar o NSPredicate
, use o método EventsMatching no EventStore
:
// execute the query
EKCalendarItem[] events = App.Current.EventStore.EventsMatching ( query );
Observe que as consultas são síncronas (bloqueio) e podem levar muito tempo, dependendo da consulta, portanto, convém criar um novo thread ou tarefa para fazê-lo.
Procurando lembretes
A busca por lembretes é semelhante a eventos; Ele requer um predicado, mas a chamada já é assíncrona, então você não precisa se preocupar em bloquear o thread:
// 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
} );
Resumo
Este documento forneceu uma visão geral das partes importantes da estrutura do EventKit e de várias das tarefas mais comuns. No entanto, a estrutura do EventKit é muito grande e poderosa, e inclui recursos que não foram introduzidos aqui, como: atualizações em lote, configuração de alarmes, configuração de recorrência em eventos, registro e escuta de alterações no banco de dados de calendário, configuração de GeoFences e muito mais. Para obter mais informações, consulte o Guia de Programação de Calendário e Lembretes da Apple.