Adicionar programaticamente evento personalizado no calendário do iPhone

181

Existe alguma maneira de adicionar um evento do iCal ao calendário do iPhone a partir do aplicativo personalizado?

Vadim
fonte

Respostas:

166

Com base na documentação da Apple , isso mudou um pouco a partir do iOS 6.0.

1) Você deve solicitar acesso ao calendário do usuário através de "requestAccessToEntityType: conclusão:" e executar a manipulação de eventos dentro de um bloco.

2) Você precisa confirmar seu evento agora ou passar o parâmetro "commit" para sua chamada de salvar / remover

Todo o resto permanece o mesmo...

Adicione a estrutura EventKit e #import <EventKit/EventKit.h>ao seu código.

No meu exemplo, eu tenho uma propriedade de instância NSString * savedEventId.

Para adicionar um evento:

    EKEventStore *store = [EKEventStore new];
    [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
        if (!granted) { return; }
        EKEvent *event = [EKEvent eventWithEventStore:store];
        event.title = @"Event Title";
        event.startDate = [NSDate date]; //today
        event.endDate = [event.startDate dateByAddingTimeInterval:60*60];  //set 1 hour meeting
        event.calendar = [store defaultCalendarForNewEvents];
        NSError *err = nil;
        [store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
        self.savedEventId = event.eventIdentifier;  //save the event id if you want to access this later
    }];

Remova o evento:

    EKEventStore* store = [EKEventStore new];
    [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
        if (!granted) { return; }
        EKEvent* eventToRemove = [store eventWithIdentifier:self.savedEventId];
        if (eventToRemove) {
            NSError* error = nil;
            [store removeEvent:eventToRemove span:EKSpanThisEvent commit:YES error:&error];
        }
    }];

Isso adiciona eventos ao seu calendário padrão. Se você tiver vários calendários, descobrirá qual deles é

Versão Swift

Você precisa importar a estrutura EventKit

import EventKit

Adicionar Evento

let store = EKEventStore()
store.requestAccessToEntityType(.Event) {(granted, error) in
    if !granted { return }
    var event = EKEvent(eventStore: store)
    event.title = "Event Title"
    event.startDate = NSDate() //today
    event.endDate = event.startDate.dateByAddingTimeInterval(60*60) //1 hour long meeting
    event.calendar = store.defaultCalendarForNewEvents
    do {
        try store.saveEvent(event, span: .ThisEvent, commit: true)
        self.savedEventId = event.eventIdentifier //save event id to access this particular event later
    } catch {
        // Display error to user
    }
}

Remover evento

let store = EKEventStore()
store.requestAccessToEntityType(EKEntityTypeEvent) {(granted, error) in
    if !granted { return }
    let eventToRemove = store.eventWithIdentifier(self.savedEventId)
    if eventToRemove != nil {
        do {
            try store.removeEvent(eventToRemove, span: .ThisEvent, commit: true)
        } catch {
            // Display error to user
        }
    }
}
William T.
fonte
6
não funciona para mim, tudo vai w / o erros, mas nenhum evento no calendário
Boris Gafurov
Tudo está armazenando no objeto ekevent, mas não armazenando dentro do calendário hlp me
1
@William T: Posso apresentar a tela Adicionar evento do aplicativo Calendário (usando o esquema de URL) e passar as informações do evento para que, quando a tela Adicionar evento aparecer, ele tenha dados pré-preenchidos. O usuário só precisa pressionar o botão Adicionar evento. No seu exemplo de evento adicionado sem nenhuma indicação ao usuário.
Ans
1
se tudo parece funcionar, mas nenhum calendário aparece, verifique se os calendários do Cloud VS Local são o problema. Se você tiver uma mistura de calendários locais e em nuvem, os calendários em nuvem poderão forçar os calendários locais a ficarem ocultos.
zonabi
2
@ReddyBasha ao adicionar o evento, você precisa salvar o eventIdentifier e armazená-lo para uso futuro. Você deve usar esse ID de evento ao removê-lo.
William T.
154

Você pode fazer isso usando a estrutura do Kit de Eventos no OS 4.0.

Clique com o botão direito do mouse no grupo FrameWorks no Navegador de grupos e arquivos à esquerda da janela. Selecione 'Adicionar' e depois 'FrameWorks existente' e depois 'EventKit.Framework'.

Então você deve poder adicionar eventos com código como este:

#import "EventTestViewController.h"
#import <EventKit/EventKit.h>

@implementation EventTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    EKEventStore *eventStore = [[EKEventStore alloc] init];

    EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
    event.title     = @"EVENT TITLE";

    event.startDate = [[NSDate alloc] init];
    event.endDate   = [[NSDate alloc] initWithTimeInterval:600 sinceDate:event.startDate];

    [event setCalendar:[eventStore defaultCalendarForNewEvents]];
    NSError *err;
    [eventStore saveEvent:event span:EKSpanThisEvent error:&err];       
}

@end
De madeira
fonte
18
Obrigado por postar isso. Apenas um lembrete para todos que lêem isso: tome cuidado para observar vazamentos de memória. Há alguns nesse exemplo de código. Além disso, as práticas recomendadas determinariam que você verifique o valor de 'err' após saveEvent: span: error e manipule as coisas adequadamente.
David Carney
Você sabe como adicionar um evento de recorrência? como um evento para todas as segundas-feiras?
Jay Vachhani
5
Adicionar evento de recorrência programaticamente: consulte developer.apple.com/library/ios/#documentation/EventKit/… . Outra opção é usar os controladores de exibição padrão fornecidos pela estrutura para adicionar / editar eventos (como o aplicativo Calendar At-A-Glance bit.ly/cJq4Bh ). Para esta opção, consulte developer.apple.com/library/ios/#documentation/EventKitUI/…
DenTheMan
Para adicionar estruturas no XCode 4, consulte esta pergunta do SO: stackoverflow.com/questions/3352664/…
Nate
1
4.0? não vai voar em 6, veja a resposta acima
Boris Gafurov 2/13
13

Sim, ainda não há API para isso (2.1). Mas parecia que na WWDC muitas pessoas já estavam interessadas na funcionalidade (inclusive eu) e a recomendação era ir ao site abaixo e criar uma solicitação de recurso para isso. Se houver interesse suficiente, eles podem mudar o ICal.framework para o SDK público.

https://developer.apple.com/bugreporter/

Keremk
fonte
5
resposta está desatualizado, considere remover este
Jasper
12

O acesso ao calendário está sendo adicionado no iPhone OS 4.0 :


Agora, os aplicativos de acesso ao calendário podem criar e editar eventos diretamente no aplicativo Calendário com o Kit de Eventos.
Crie eventos recorrentes, configure os horários de início e término e atribua-os a qualquer calendário no dispositivo.

Chris S
fonte
1
seu link está quebrado agora.
Adil Soomro
5

Você pode adicionar o evento usando a API de eventos como Tristan descrita e também pode adicionar um evento do Google Agenda que aparece no calendário do iOS.

usando o cliente Objective-C da API do Google

  - (void)addAnEvent {
  // Make a new event, and show it to the user to edit
  GTLCalendarEvent *newEvent = [GTLCalendarEvent object];
  newEvent.summary = @"Sample Added Event";
  newEvent.descriptionProperty = @"Description of sample added event";

  // We'll set the start time to now, and the end time to an hour from now,
  // with a reminder 10 minutes before
  NSDate *anHourFromNow = [NSDate dateWithTimeIntervalSinceNow:60*60];
  GTLDateTime *startDateTime = [GTLDateTime dateTimeWithDate:[NSDate date]
                                                    timeZone:[NSTimeZone systemTimeZone]];
  GTLDateTime *endDateTime = [GTLDateTime dateTimeWithDate:anHourFromNow
                                                  timeZone:[NSTimeZone systemTimeZone]];

  newEvent.start = [GTLCalendarEventDateTime object];
  newEvent.start.dateTime = startDateTime;

  newEvent.end = [GTLCalendarEventDateTime object];
  newEvent.end.dateTime = endDateTime;

  GTLCalendarEventReminder *reminder = [GTLCalendarEventReminder object];
  reminder.minutes = [NSNumber numberWithInteger:10];
  reminder.method = @"email";

  newEvent.reminders = [GTLCalendarEventReminders object];
  newEvent.reminders.overrides = [NSArray arrayWithObject:reminder];
  newEvent.reminders.useDefault = [NSNumber numberWithBool:NO];

  // Display the event edit dialog
  EditEventWindowController *controller = [[[EditEventWindowController alloc] init] autorelease];
  [controller runModalForWindow:[self window]
                          event:newEvent
              completionHandler:^(NSInteger returnCode, GTLCalendarEvent *event) {
                // Callback
                if (returnCode == NSOKButton) {
                  [self addEvent:event];
                }
              }];
}
Iggy
fonte
5

Implementação do Swift 4.0:

use a importação no topo da página import EventKit

então

@IBAction func addtoCalendarClicked(sender: AnyObject) {

    let eventStore = EKEventStore()

    eventStore.requestAccess( to: EKEntityType.event, completion:{(granted, error) in

        if (granted) && (error == nil) {
            print("granted \(granted)")
            print("error \(error)")

            let event = EKEvent(eventStore: eventStore)

            event.title = "Event Title"
            event.startDate = Date()
            event.endDate = Date()
            event.notes = "Event Details Here"
            event.calendar = eventStore.defaultCalendarForNewEvents

            var event_id = ""
            do {
                try eventStore.save(event, span: .thisEvent)
                event_id = event.eventIdentifier
            }
            catch let error as NSError {
                print("json error: \(error.localizedDescription)")
            }

            if(event_id != ""){
                print("event added !")
            }
        }
    })
}
Dashrath
fonte
u poderia me ajudar com o google calendar sobre a mesma resposta @Dashrath
Dilip Tiwari
4

Atualização para o swift 4 para resposta do Dashrath

import UIKit
import EventKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let eventStore = EKEventStore()

        eventStore.requestAccess( to: EKEntityType.event, completion:{(granted, error) in

            if (granted) && (error == nil) {


                let event = EKEvent(eventStore: eventStore)

                event.title = "My Event"
                event.startDate = Date(timeIntervalSinceNow: TimeInterval())
                event.endDate = Date(timeIntervalSinceNow: TimeInterval())
                event.notes = "Yeah!!!"
                event.calendar = eventStore.defaultCalendarForNewEvents

                var event_id = ""
                do{
                    try eventStore.save(event, span: .thisEvent)
                    event_id = event.eventIdentifier
                }
                catch let error as NSError {
                    print("json error: \(error.localizedDescription)")
                }

                if(event_id != ""){
                    print("event added !")
                }
            }
        })
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

também não se esqueça de adicionar permissão para uso do calendário imagem para configuração privada

luhuiya
fonte
2

Código de trabalho no Swift-4.2

import UIKit
import EventKit
import EventKitUI

class yourViewController: UIViewController{

    let eventStore = EKEventStore()

    func addEventToCalendar() {

    eventStore.requestAccess( to: EKEntityType.event, completion:{(granted, error) in
        DispatchQueue.main.async {
            if (granted) && (error == nil) {
                let event = EKEvent(eventStore: self.eventStore)
                event.title = self.headerDescription
                event.startDate = self.parse(self.requestDetails.value(forKey: "session_time") as? String ?? "")
                event.endDate = self.parse(self.requestDetails.value(forKey: "session_end_time") as? String ?? "")
                let eventController = EKEventEditViewController()
                eventController.event = event
                eventController.eventStore = self.eventStore
                eventController.editViewDelegate = self
                self.present(eventController, animated: true, completion: nil)

            }
        }


       })
    }

}

Agora teremos a tela do evento e aqui você também pode modificar suas configurações:

insira a descrição da imagem aqui

Agora adicione o método delegado para lidar com Cancelar e adicione a ação do botão de evento da tela de eventos:

    extension viewController: EKEventEditViewDelegate {

    func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
        controller.dismiss(animated: true, completion: nil)

    }
}

Nota: Não esqueça de adicionar a chave NSCalendarsUsageDescription no info plist.

Alok
fonte
1

Lembre-se de definir o endDate para o evento criado, é obrigatório.

Caso contrário, falhará (quase silenciosamente) com este erro:

"Error Domain=EKErrorDomain Code=3 "No end date has been set." UserInfo={NSLocalizedDescription=No end date has been set.}"

O código de trabalho completo para mim é:

EKEventStore *store = [EKEventStore new];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
    if (!granted) { return; }
    EKEvent *calendarEvent = [EKEvent eventWithEventStore:store];
    calendarEvent.title = [NSString stringWithFormat:@"CEmprendedor: %@", _event.name];
    calendarEvent.startDate = _event.date;
    // 5 hours of duration, we must add the duration of the event to the API
    NSDate *endDate = [_event.date dateByAddingTimeInterval:60*60*5];
    calendarEvent.endDate = endDate;
    calendarEvent.calendar = [store defaultCalendarForNewEvents];
    NSError *err = nil;
    [store saveEvent:calendarEvent span:EKSpanThisEvent commit:YES error:&err];
    self.savedEventId = calendarEvent.eventIdentifier;  //saving the calendar event id to possibly deleted them
}];
halbano
fonte
1
E lembre-se também de que a data de término deve ser igual ou maior que a data de início. Caso contrário, você receberá outro erro.
Temperamental
0

A ideia do Google é boa, mas tem problemas.

Posso abrir com êxito uma tela de evento do calendário do Google - mas apenas na versão principal da área de trabalho e ela não é exibida corretamente no iPhone Safari. O calendário móvel do Google, que é exibido corretamente no Safari, parece não funcionar com a API para adicionar eventos.

No momento, não vejo uma boa saída dessa.

xgretsch
fonte
0

Simples .... use a biblioteca tapku .... você pode pesquisar no google essa palavra e usá-la ... seu código aberto ... aproveitar ..... não há necessidade de corrigir esses códigos ....

Rajesh_Bangalore
fonte
Can Tapku Biblioteca sincronizar calendário com eventos de aplicativos de calendário
coder1010
Tudo o que sei é que a biblioteca Tapku é um controle de componente de calendário que possui uma opção chamada Fonte de dados. Portanto, é sua lógica escrever a fonte de onde você está buscando ... Happy Coding :)
Rajesh_Bangalore