本文主要內容是如何一步一步使用EventKit
在iOS設備中添加日曆,並在日曆中添加事件和提醒事項。 git
源代碼Githubgithub
EKAlarm
類用於提供操做系統日曆通知的相關接口,通知時間既能夠是絕對時間,也能夠是相對時間。spa
實例化方法操作系統
//絕對時間 + (EKAlarm *)alarmWithAbsoluteDate:(NSDate *)date; //相對時間 + (EKAlarm *)alarmWithRelativeOffset:(NSTimeInterval)offset;
屬性相關類code
EKStructuredLocation
通知的位置屬性,包括標題title
,地理位置geoLocation
和半徑radius
orm
EKAlarmProximity
是一個標記爲進入或者離開的枚舉類型繼承
typedef NS_ENUM(NSInteger, EKAlarmProximity) { EKAlarmProximityNone, EKAlarmProximityEnter, //進入 EKAlarmProximityLeave //離開 };
EKAlarmType
記錄通知類型的枚舉屬性教程
typedef NS_ENUM(NSInteger, EKAlarmType) { EKAlarmTypeDisplay, //展現信息 EKAlarmTypeAudio, //播放聲音 EKAlarmTypeProcedure, //打開網址 EKAlarmTypeEmail //發郵件 };
首先,經過``能夠進行系統受權,使用下面的方法接口
//申請權限 - (void)requestAccessToEntityType:(EKEntityType)entityType completion:(EKEventStoreRequestAccessCompletionHandler)completion NS_AVAILABLE(10_9, 6_0); //獲取當前權限 + (EKAuthorizationStatus)authorizationStatusForEntityType:(EKEntityType)entityType NS_AVAILABLE(10_9, 6_0);
枚舉量包括 實例類型EKEntityType
和 實例蒙版EKEntityMask
事件
EKCalendar
和 EKEventStore
的關係能夠理解爲,一個EKEventStore
能夠包含多個EKCalendar
。
這個類的類型枚舉變量是
typedef NS_ENUM(NSInteger, EKCalendarType) { EKCalendarTypeLocal, EKCalendarTypeCalDAV, EKCalendarTypeExchange, EKCalendarTypeSubscription, EKCalendarTypeBirthday };
其中,EKCalendarTypeCalDAV
和 EKCalendarTypeExchange
是兩種郵箱帳戶的事件同步類型,EKCalendarTypeBirthday
是一個內置的生日日曆,EKCalendarTypeLocal
和設備同步,EKCalendarTypeSubscription
則是用於本地的同步類型。
EKEvent
與EKReminder
同樣繼承於EKCalendarItem
。
上面對於頭文件的分析,有助於咱們實際編寫代碼。
要點一 添加受權描述
首先須要在項目的plist文件中,加入申請系統日曆使用的描述,不然沒法發起受權請求。鍵爲NSCalendarsUsageDescription
,值爲提交請求的描述。
而後判斷當前的受權狀態
+ (BOOL)accessForEventKit:(EKEntityType)type { return [EKEventStore authorizationStatusForEntityType:type] == EKAuthorizationStatusAuthorized; }
固然,能夠增長額外的判斷,好比當狀態爲EKAuthorizationStatusDenied
的時候,能夠提醒用戶前往系統設置
打開系統日曆的受權,咱們上面這段代碼只是簡單的判斷是否擁有系統日曆的操做權限,當擁有權限時,進行業務代碼,若是尚未進行過受權,則用下滿的方法吊起受權
+ (void)accessForEventKitType:(EKEntityType)type result:(void(^)(BOOL))result { EKEventStore* store = [[EKEventStore alloc] init]; [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) { if (!granted) { NSLog(@"%@",error); } if (result) { result(granted); } }]; }
這裏是否封裝成方法均可以,我這裏寫成類方法是爲了方便讀者在任意位置粘貼代碼和調用。
受權完成之後就能夠進行業務代碼的操做了。
首先使用下面的代碼獲取系統日曆中所有的日曆
+ (NSArray*)calendarWithType:(EKEntityType)type { EKEventStore* store = [[EKEventStore alloc] init]; return [store calendarsForEntityType:type]; }
這裏一樣區分事件的種類,得到結果以下,每一個蘋果帳號的日曆內容不盡相同
"EKCalendar <0x1740a5580> {title = Birthdays; type = Birthday; allowsModify = NO; color = #8295AF;}",
"EKCalendar <0x1740a5dc0> {title = Calendar; type = CalDAV; allowsModify = YES; color = #1BADF8;}",
"EKCalendar <0x1740a56a0> {title = U65e5U5386; type = CalDAV; allowsModify = YES; color = #1BADF8;}",
"EKCalendar <0x1740a5640> {title = U5de5U4f5c; type = CalDAV; allowsModify = YES; color = #63DA38;}",
"EKCalendar <0x1740a55e0> {title = U5bb6U5ead; type = CalDAV; allowsModify = YES; color = #FFCC00;}"
EKCalendar
和 EKCalendarItem
並非雙向的可讀取關係,經過EKCalendarItem
實例能夠獲取它的EKCalendar
,但咱們沒法經過EKCalendar
獲取系統所有的EKCalendarItem
,這樣不一樣的應用之間是沒法相互操做事件的。
每個EKCalendarItem
擁有獨一無二的calendarItemIdentifier
標識,是每一個事件的id,這個字符串是應用本身分配的,保證了每一個應用能夠在添加了事件之後,針對性的進行事件修改。
你們注意到上面輸出的EKCalendar
中有一個日曆是禁止應用修改的,就是Birthdays
日曆,由於這個日曆是同步於通信錄中的聯繫人生日的特殊日曆。
EKCalendar
除了上面獲取的系統已有日曆,咱們也能夠添加本身定義的日曆
要點二 日曆的calendarIdentifier存儲
應用須要本身存儲本身添加的日曆的惟一標識,就是calendarIdentifier
,咱們這裏使用NSUserDefault
來存儲。
+ (void)createCalendar { NSUserDefaults * def = [NSUserDefaults standardUserDefaults]; NSString* calendarIdentifier = [def valueForKey:@"testCalendarIdentifier"]; EKCalendar* birthday = [store calendarWithIdentifier:calendarIdentifier]; //這裏若是calendarIdentifier爲nil,則EKCalendar也會爲nil if (!birthday) { birthday = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:store]; birthday.title = @"test日曆"; //注意calendarIdentifier自動生成的,這裏要保存下來 [def setObject:birthday.calendarIdentifier forKey:@"testCalendarIdentifier"]; [def synchronize]; NSError* error; [store saveCalendar:birthday coobjectivecit:YES error:&error]; if (error) { NSLog(@"%@",error); } } }
上面的代碼執行將沒法添加日曆,須要越過兩個坑
要點三 坑
坑一是EKCalendar
須要設置EKSource
才能夠添加,因此會獲得下面的錯誤
Error Domain=EKErrorDomain Code=14 "Calendar has no source" UserInfo={NSLocalizedDescription=Calendar has no source}
然而EKSource
並不能夠經過EventKit管理,也就是說,系統有哪些日曆帳戶,就只能用哪些,獲取的辦法以下:
+ (EKSource*)sourceWithType:(EKSourceType)type { EKEventStore* store = [[EKEventStore alloc] init]; EKSource *localSource = nil; NSLog(@"%@",store.sources); for (EKSource *source in store.sources) { if (source.sourceType == type) { localSource = source; break; } } return localSource; }
咱們經過遍歷全部的系統Source,來匹配咱們須要的Source。
這裏就引出坑二,當系統開啓或關閉了iCloud日曆功能的時候,Source會有不一樣,例如開啓iCloud日曆的時候,個人設備只有一個EKSourceTypeCalDAV
類型的叫iCloud的Source和一個Other類型的Source(每一個設備可能不盡相同),但在其餘沒有開啓的設備上,纔有EKSourceTypeLocal
類型的Source,因此上面一段代碼的Source匹配,可能要執行屢次,或者按照前後順序匹配,若是單獨只匹配一種類型,會有可能找不到可使用的Source。
找到Source之後,將其賦值給Calendar,注意EKCalendar
的這個屬性雖然不是Readonly
,但只能在初始化日曆的時候進行設置,不能再更改。
birthday.source = [[self class] sourceWithType:EKSourceTypeCalDAV]; if (!birthday.source) { birthday.source = [[self class] sourceWithType:EKSourceTypeLocal]; }
如此則可順利添加自定義的日曆。
最後一步添加事件則很簡單
+ (void)addEvent { EKEvent* event = [EKEvent eventWithEventStore:store]; event.calendar = birthday; event.title = @"個人生日"; NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-objectivec-dd-HH-objectivec"]; event.startDate = [formatter dateFromString:@"2017-11-12-00-00"]; event.endDate = [formatter dateFromString:@"2017-11-12-23-59"]; NSError* error; [store saveEvent:event span:EKSpanThisEvent error:&error]; if (error) { NSLog(@"%@",error); } NSLog(@"%@",event.eventIdentifier); }
event設置標題、日曆和起始日期便可,保存步驟中用到的EKSpanThisEvent
枚舉表示只應用於當前事件,這個枚舉的另外一個值EKSpanFutureEvents
表示應用到全部此事件,包括重複事件的將來的事件。
最後保存成功的話,獲得的eventIdentifier
,應用能夠根據須要保存在本地。
以上就是EventKit的基礎教程。