最近公司项目要求做同步系统提醒事项和日历事件到app里。自己在的过程中做了一些总结,希望帮助要做此类功能的朋友或者想学习该功能的同学。有错误之处还请大家指出改正,一起进步。
我主要说的是获取日历和提醒的具体内容的方法,以及某些属性的含义。后续在会写新建,删除,修改日历和提醒的方法。其实增删查改并不太难。主要是详情里的数据结构比较复杂,不容易搞懂尤其是日历,因为日历可以设置多种选项,提醒则简单很多。
一:了解EventKit框架。
Event Kit框架使你能访问用户的Calendar(日历)和Reminder(提醒事项)信息。虽然二者在手机上是两个独立的app,但他们使用相同的库(EKEventStore)处理数据,该库管理所有event数据。该框架除了允许检索用户已经存在的calendar和reminder数据外,还允许创建新的事件和提醒。
二:连接到EKEventStore
EKEventStore 就像一个数据库,日历事件和提醒事项的数据全都在EKEventStore里存着,增删查改全都用其实例对象来管理。
日历事件:
<1.>在项目里导入EventKit框架和EventKitUI框架。
<2.>EKEventStore *eventStore=[[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskEvent];一个EKEventStore对象需要一段明显的时间来初始化和释放。因此,你不应该为每个事件相关的任务都初始化和释放一个单独的event store。取而代之的,在你的应用加载时,初始化一个event store,并且重复使用它。
EKEntityType枚举 包含EKEntityTypeEvent(日历事件)和EKEntityTypeReminder(提醒事项)两种。可以在EKEventStore初始化时直接指定类型。也可以直接allocinit。
<3.>请求app授权。
iOS10之后,要用到某个权限必须在info.plist里指明,否则会引起崩溃和审核失败。添加权限字符串访问日历:NSCalendarsUsageDescription 访问提醒事项:NSRemindersUsageDescription
检查授权状态:
//检测日历事件
EKAuthorizationStatus eventStatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
授权状态:EKAuthorizationStatusNotDetermined 用户还没授权过。EKAuthorizationStatusAuthorized用户已经允许授权。
if(eventStatus ==EKAuthorizationStatusNotDetermined){
//用户尚未授权,提示用户授权。下边的requestAccessToEntityType:方法可以调出系统授权弹窗
}else if(eventStatus ==EKAuthorizationStatusAuthorized){
//用户已经允许授权。作相应处理,比如查询日历里今天的所有事件..
}
下边的requestAccessToEntityType调出系统的日历事件(EKEntityTypeEvent)权限弹窗
<4.>检索系统日历事件 ()
NSArray*tempA=[self.eventStore calendarsForEntityType:EKEntityTypeEvent];该方法可以得到所有的日历类型。
比如:家庭,工作,生日,中国节假日等等。你如果需要家庭,工作,iPhone日历,只需for循环挑选出需要的类型的日历放到一个数组里,然后将该数组传给谓词方法里NSPredicate*predicate = [self.eventStorepredicateForEventsWithStartDate:startTodayDate endDate:endTodayDate calendars:typesArray];
NSArray *eventArray = [self.eventStoreeventsMatchingPredicate:predicate];表示 找出从startTodayDate今天的开始时间到今天的结束时间endTodayDate时间范围的所有typesArray里类型的日历事件。开始和结束时间不是写死的,自己需要时间段的时间传对应的值即可。
<5>.事件EKEvent各个属性含义。
eventArray数组是刚才checkTodayEvent方法里返回的事件数组。数组里存的是EKEvent类型数据。EKEvent里属性可在EKEvent.h里查看。下边列举一些:
EKEvent *event =eventArray[i];
title:事件的标题
notes:事件备注
eventIdentifier:唯一标识符区分某个事件.
startDate:开始时间
endDate: 结束时间 (特殊情况:日历里结束日期可以设置的比开始日期小。根据实际需求做对应处理。)
alarms:闹钟数组,如果event.alarms.count >0 表示设置了多个闹钟。该数组由EKAlarm组成。
<6> 闹钟EKAlarm各属性含义
EKEvent里可以设置多个提醒,alarms数组
EKAlarm*firssAlert = event.alarms.firstObject;//取出第一个闹钟
//计算出定制的第一个闹钟的具体触发时间。也就是最先提醒的那个闹钟的具体时间
NSDate*detailAlertDate =[event.startDate dateByAddingTimeInterval:firssAlert.relativeOffset];
relativeOffset=0.表示到event.startDate时提醒。- 60表示提前一分钟提醒。
<7>.重复EKRecurrenceRule规则属性含义。
重复结束于:用属性EKRecurrenceEnd表示。EKRecurrenceEnd*recurrenceEnd =rule.recurrenceEnd;
重复类型:
每5周重复。每周的二,三,四重复。结束重复时间为:20170321 。EKRecurrenceRule里的数据打印出来是:FREQ=WEEKLY;INTERVAL=5;UNTIL=20170321T155959Z;BYDAY=TU,WE,TH;WKST=SU
每4个月重复。每月的18,19,20,24,对应:FREQ=MONTHLY;INTERVAL=4;BYMONTHDAY=18,19,20,24, 相信大家也可以知道其他重复规则的打印内容了,跟着套路走就看懂了。
<8.>受邀人EKParticipant。里边包含了受邀人的账号姓名状态等等。
<9.>位置EKStructuredLocation。事件里添加的位置。可以获取到经纬度等相关信息。
添加事件到系统日历
添加方法:- (BOOL)saveEvent:(EKEvent*)event span:(EKSpan)span error:(NSError**)error;
EKAlarm *alarm = [EKAlarm alarmWithAbsoluteDate:[now dateByAddingTimeInterval:30]];//现在开始30秒后提醒
EKEvent *event = [EKEvent eventWithEventStore:self.eventStore];
event.title = @"事件标题";//标题
event.startDate = now;//开始时间
event.endDate = [now dateByAddingTimeInterval:30];//结束时间
[event setAllDay:YES];//设置全天
[event addAlarm:alarm];//添加一个闹钟
[event setCalendar:[self.eventStore defaultCalendarForNewEvents]];//默认日历类型
//保存事件
[self.eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:nil];
NSError *err = nil;
if([self.eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&err]){
NSLog(@"创建事件到系统日历成功!");
}else{
NSLog(@"创建失败%@",err);
}
//span:设置跨度。 EKSpanThisEvent:表示只影响当前事件。 EKSpanFutureEvents 表示影响当前和以后的所有事件。比如某条重复任务修改后保存时,传EKSpanThisEvent表示值修改这一条重复事件。传EKSpanFutureEvents表示修改这一条和以后的所有重复事件。删除事件时,分别表示删除这一条;删除这一条和以后的所有。
删除系统日历事件
删除方法:- (BOOL)removeEvent:(EKEvent*)event span:(EKSpan)span commit:(BOOL)commit error:(NSError**)error;
EKEvent*event = self.eventArray[ i ];
[event setCalendar:[self.eventStoredefaultCalendarForNewEvents]];
NSError*error =nil;
BOOL successDelete=[self.eventStoreremoveEvent:eventspan:EKSpanFutureEvents commit:NOerror:&error];
if(!successDelete) {
NSLog(@"删除本条事件失败");
}else{
NSLog(@"删除本条事件成功,%@",error);
}
//一次提交所有操作到事件库
NSError*error =nil;
BOOL commitSuccess= [self.eventStorecommit:&error];
if(!commitSuccess) {
NSLog(@"一次性提交删除事件是失败");
}else{
NSLog(@"成功一次性提交删除事件,%@",error);
}
// 注意添加和删除时方法里都有一个 commit:(BOOL)commit 参数。yes:表示立即把此次操作提交到系统事件库,NO表示此时不提交。如果一次性操作的事件数比较少的话,可以每次都传YES,实时更新事件数据库。如果一次性操作的事件较多的话,可以每次传NO,最后再执行一次提交所有更改到数据库,把原来的更改全部提交到数据库,不管是添加还是删除。
未完待续...