使用 EventKit 向系統日曆中添加事件

使用 EventKit 向系統日曆中添加事件

本文主要內容是如何一步一步使用EventKit在iOS設備中添加日曆,並在日曆中添加事件和提醒事項。 git

源代碼Githubgithub

類和屬性

EKAlarm 提醒操做類

EKAlarm類用於提供操做系統日曆通知的相關接口,通知時間既能夠是絕對時間,也能夠是相對時間。spa

實例化方法操作系統

//絕對時間
+ (EKAlarm *)alarmWithAbsoluteDate:(NSDate *)date;
//相對時間
+ (EKAlarm *)alarmWithRelativeOffset:(NSTimeInterval)offset;

屬性相關類code

EKStructuredLocation 通知的位置屬性,包括標題title,地理位置geoLocation和半徑radiusorm

EKAlarmProximity 是一個標記爲進入或者離開的枚舉類型繼承

typedef NS_ENUM(NSInteger, EKAlarmProximity) {
    EKAlarmProximityNone,
    EKAlarmProximityEnter, //進入
    EKAlarmProximityLeave  //離開
};

EKAlarmType 記錄通知類型的枚舉屬性教程

typedef NS_ENUM(NSInteger, EKAlarmType) {
    EKAlarmTypeDisplay,     //展現信息
    EKAlarmTypeAudio,       //播放聲音
    EKAlarmTypeProcedure,   //打開網址
    EKAlarmTypeEmail        //發郵件
};

EKEventStore 事件管理類

首先,經過``能夠進行系統受權,使用下面的方法接口

//申請權限
- (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 日曆操做類

EKCalendarEKEventStore 的關係能夠理解爲,一個EKEventStore能夠包含多個EKCalendar

這個類的類型枚舉變量是

typedef NS_ENUM(NSInteger, EKCalendarType) {
   EKCalendarTypeLocal,
   EKCalendarTypeCalDAV,
   EKCalendarTypeExchange,
   EKCalendarTypeSubscription,
   EKCalendarTypeBirthday
};

其中,EKCalendarTypeCalDAVEKCalendarTypeExchange 是兩種郵箱帳戶的事件同步類型,EKCalendarTypeBirthday是一個內置的生日日曆,EKCalendarTypeLocal和設備同步,EKCalendarTypeSubscription則是用於本地的同步類型。

EKEvent 事件操做類 與 EKReminder 提醒操做類

EKEventEKReminder同樣繼承於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;}"

EKCalendarEKCalendarItem 並非雙向的可讀取關係,經過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的基礎教程。

相關文章
相關標籤/搜索