一 了解EventKit框架。
EventKit框架使你能访问用户的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
检查授权状态:
//授权状态:EKAuthorizationStatusNotDetermined 用户还没授权过。EKAuthorizationStatusAuthorized用户已经允许授权。
EKAuthorizationStatus eventStatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
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周重复。每周的二,三,四重复。结束重复时间为:20220321 。EKRecurrenceRule里的数据打印出来是:FREQ=WEEKLY;INTERVAL=5;UNTIL=20220321T155959Z;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.eventStore defaultCalendarForNewEvents]];
NSError *error = nil;
BOOL successDelete = [self.eventStore removeEvent:event span:EKSpanFutureEvents commit:NO error:&error];
if(!successDelete) {
NSLog(@"删除本条事件失败");
} else {
NSLog(@"删除本条事件成功,%@",error);
}
//一次提交所有操作到事件库
NSError*error = nil;
BOOL commitSuccess = [self.eventStore commit:&error];
if(!commitSuccess) {
NSLog(@"一次性提交删除事件是失败");
} else {
NSLog(@"成功一次性提交删除事件,%@", error);
}
注意添加和删除时方法里都有一个 commit:(BOOL)commit 参数。yes:表示立即把此次操作提交到系统事件库,NO表示此时不提交。如果一次性操作的事件数比较少的话,可以每次都传YES,实时更新事件数据库。如果一次性操作的事件较多的话,可以每次传NO,最后再执行一次提交所有更改到数据库,把原来的更改全部提交到数据库,不管是添加还是删除。
读取提醒事项
//日历,iCloud家庭,工作,订阅,生日
//来查找所有的reminders
NSPredicate *pre = [self.eventStore predicateForRemindersInCalendars:only3A];
/异步方法。
[self.eventStore fetchRemindersMatchingPredicate:pre completion:^(NSArray *_Nullable reminders) {
//异步查找出提醒事项数组reminders,这里可根据需求进一步进行对数组的操作
}
reminders 数组里存的是EKReminder对象。
列举EKReminder 的一些属性:
title:标题
notes:备注
priority:优先级(NSUInteger)0无级别,1级别高---9级别低(1-4高,5中等,6-9低)
completed:是否已完成
completionDate:完成时间
alarms:提醒数组(数组里是EKAlarm对象, 可以获得跟闹钟相关的数据,如具体时间,偏移秒数...)
添加一条提醒事项
EKAlarm *alarm = [EKAlarm alarmWithAbsoluteDate:[now dateByAddingTimeInterval:30]];
EKReminder *reminder = [EKReminder reminderWithEventStore:es];
reminder.title = @"提醒的标题";
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setTimeZone:[NSTimeZone systemTimeZone]];
NSInteger flags = NSYearCalendarUnit | NSMonthCalendarUnit |NSDayCalendarUnit |NSHourCalendarUnit | NSMinuteCalendarUnit |NSSecondCalendarUnit;
reminder.startDateComponents = [cal components:flags fromDate:[now dateByAddingTimeInterval:30]];//开始时间
reminder.dueDateComponents = [cal components:flags fromDate:[now dateByAddingTimeInterval:30]]; //结束时间
reminder.completionDate = [now dateByAddingTimeInterval:30];
[reminder setCalendar:[self.eventStore defaultCalendarForNewReminders]];
reminder.priority = 1; //优先级
[reminder addAlarm:alarm];
NSError *err = nil;
if([self.eventStore saveReminder:reminder commit:YES error:&err]){
NSLog(@"创建成功!");
} else {
NSLog(@"创建失败%@",err);
}
//记得commit。
删除提醒事项
[reminderArray enumerateObjectsUsingBlock:^(id_Nonnull obj, NSUInteger idx, BOOL *_Nonnullstop) {
EKReminder *reminder = (EKReminder*)obj;
/*如果你有不止一个EKReminder需要删除,好的做法是不要一个一个的提交,而是全部删除,在最后一次性提交。这个也适用于增加新的事件到存储器中*/
NSError *error = nil;
BOOL success = [self.eventStore removeReminder:reminder commit:NO error:&error];
if(!success) {
NSLog(@"删除错误");
} else {
NSLog(@"本次删除成功");
}
}];
//一次性全部提交修改
NSError *commitErr = nil;
BOOL commitSuccess = [self.eventStore commit:&commitErr];
if(!commitSuccess) {
NSLog(@"提交到事件库错误");
} else {
NSLog(@"成功一次性全部提交到事件库");
}