最近公司項(xiàng)目要求做同步系統(tǒng)提醒事項(xiàng)和日歷事件到app里。自己在的過程中做了一些總結(jié),希望幫助要做此類功能的朋友或者想學(xué)習(xí)該功能的同學(xué)。有錯誤之處還請大家指出改正,一起進(jìn)步。
我主要說的是獲取日歷和提醒的具體內(nèi)容的方法,以及某些屬性的含義。后續(xù)在會寫新建,刪除,修改日歷和提醒的方法。其實(shí)增刪查改并不太難。主要是詳情里的數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜,不容易搞懂尤其是日歷,因?yàn)槿諝v可以設(shè)置多種選項(xiàng),提醒則簡單很多。
一:了解EventKit框架。
Event Kit框架使你能訪問用戶的Calendar(日歷)和Reminder(提醒事項(xiàng))信息。雖然二者在手機(jī)上是兩個獨(dú)立的app,但他們使用相同的庫(EKEventStore)處理數(shù)據(jù),該庫管理所有event數(shù)據(jù)。該框架除了允許檢索用戶已經(jīng)存在的calendar和reminder數(shù)據(jù)外,還允許創(chuàng)建新的事件和提醒。
二:連接到EKEventStore
EKEventStore 就像一個數(shù)據(jù)庫,日歷事件和提醒事項(xiàng)的數(shù)據(jù)全都在EKEventStore里存著,增刪查改全都用其實(shí)例對象來管理。
日歷事件:
<1.>在項(xiàng)目里導(dǎo)入EventKit框架和EventKitUI框架。
<2.>EKEventStore *eventStore=[[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskEvent];一個EKEventStore對象需要一段明顯的時間來初始化和釋放。因此,你不應(yīng)該為每個事件相關(guān)的任務(wù)都初始化和釋放一個單獨(dú)的event store。取而代之的,在你的應(yīng)用加載時,初始化一個event store,并且重復(fù)使用它。
? ? EKEntityType枚舉 包含EKEntityTypeEvent(日歷事件)和EKEntityTypeReminder(提醒事項(xiàng))兩種。可以在EKEventStore初始化時直接指定類型。也可以直接allocinit。
<3.>請求app授權(quán)。
iOS10之后,要用到某個權(quán)限必須在info.plist里指明,否則會引起崩潰和審核失敗。添加權(quán)限字符串訪問日歷:NSCalendarsUsageDescription 訪問提醒事項(xiàng):NSRemindersUsageDescription
檢查授權(quán)狀態(tài):
//檢測日歷事件
EKAuthorizationStatus ?eventStatus = [EKEventStore ?authorizationStatusForEntityType:EKEntityTypeEvent];
授權(quán)狀態(tài):EKAuthorizationStatusNotDetermined 用戶還沒授權(quán)過。EKAuthorizationStatusAuthorized用戶已經(jīng)允許授權(quán)。
if(eventStatus ==EKAuthorizationStatusNotDetermined){
//用戶尚未授權(quán),提示用戶授權(quán)。下邊的requestAccessToEntityType:方法可以調(diào)出系統(tǒng)授權(quán)彈窗
}else if(eventStatus ==EKAuthorizationStatusAuthorized){
//用戶已經(jīng)允許授權(quán)。作相應(yīng)處理,比如查詢?nèi)諝v里今天的所有事件..
}
? ? 下邊的requestAccessToEntityType調(diào)出系統(tǒng)的日歷事件(EKEntityTypeEvent)權(quán)限彈窗
<4.>檢索系統(tǒng)日歷事件 ()
NSArray*tempA=[self.eventStore calendarsForEntityType:EKEntityTypeEvent];該方法可以得到所有的日歷類型。
比如:家庭,工作,生日,中國節(jié)假日等等。你如果需要家庭,工作,iPhone日歷,只需for循環(huán)挑選出需要的類型的日歷放到一個數(shù)組里,然后將該數(shù)組傳給謂詞方法里NSPredicate*predicate = [self.eventStorepredicateForEventsWithStartDate:startTodayDate endDate:endTodayDate calendars:typesArray];
NSArray *eventArray = [self.eventStoreeventsMatchingPredicate:predicate];表示 找出從startTodayDate今天的開始時間到今天的結(jié)束時間endTodayDate時間范圍的所有typesArray里類型的日歷事件。開始和結(jié)束時間不是寫死的,自己需要時間段的時間傳對應(yīng)的值即可。
<5>.事件EKEvent各個屬性含義。
eventArray數(shù)組是剛才checkTodayEvent方法里返回的事件數(shù)組。數(shù)組里存的是EKEvent類型數(shù)據(jù)。EKEvent里屬性可在EKEvent.h里查看。下邊列舉一些:
EKEvent *event =eventArray[i];
title:事件的標(biāo)題?
notes:事件備注?
eventIdentifier:唯一標(biāo)識符區(qū)分某個事件.
startDate:開始時間?
endDate: 結(jié)束時間 (特殊情況:日歷里結(jié)束日期可以設(shè)置的比開始日期小。根據(jù)實(shí)際需求做對應(yīng)處理。)
alarms:鬧鐘數(shù)組,如果event.alarms.count >0 表示設(shè)置了多個鬧鐘。該數(shù)組由EKAlarm組成。
<6> 鬧鐘EKAlarm各屬性含義
? EKEvent里可以設(shè)置多個提醒,alarms數(shù)組
? EKAlarm*firssAlert = event.alarms.firstObject;//取出第一個鬧鐘
? ?//計算出定制的第一個鬧鐘的具體觸發(fā)時間。也就是最先提醒的那個鬧鐘的具體時間
? ?NSDate*detailAlertDate =[event.startDate dateByAddingTimeInterval:firssAlert.relativeOffset];
? ?relativeOffset=0.表示到event.startDate時提醒。- 60表示提前一分鐘提醒。
<7>.重復(fù)EKRecurrenceRule規(guī)則屬性含義。
重復(fù)結(jié)束于:用屬性EKRecurrenceEnd表示。EKRecurrenceEnd*recurrenceEnd =rule.recurrenceEnd;
重復(fù)類型:
? 每5周重復(fù)。每周的二,三,四重復(fù)。結(jié)束重復(fù)時間為:20170321 。EKRecurrenceRule里的數(shù)據(jù)打印出來是:FREQ=WEEKLY;INTERVAL=5;UNTIL=20170321T155959Z;BYDAY=TU,WE,TH;WKST=SU
? 每4個月重復(fù)。每月的18,19,20,24,對應(yīng):FREQ=MONTHLY;INTERVAL=4;BYMONTHDAY=18,19,20,24, 相信大家也可以知道其他重復(fù)規(guī)則的打印內(nèi)容了,跟著套路走就看懂了。
<8.>受邀人EKParticipant。里邊包含了受邀人的賬號姓名狀態(tài)等等。
<9.>位置EKStructuredLocation。事件里添加的位置。可以獲取到經(jīng)緯度等相關(guān)信息。
添加事件到系統(tǒng)日歷
添加方法:- (BOOL)saveEvent:(EKEvent*)event span:(EKSpan)span error:(NSError**)error;
EKAlarm *alarm = [EKAlarm alarmWithAbsoluteDate:[now dateByAddingTimeInterval:30]];//現(xiàn)在開始30秒后提醒
EKEvent *event = [EKEvent eventWithEventStore:self.eventStore];
event.title = @"事件標(biāo)題";//標(biāo)題
event.startDate = now;//開始時間
event.endDate = [now dateByAddingTimeInterval:30];//結(jié)束時間
[event setAllDay:YES];//設(shè)置全天
[event addAlarm:alarm];//添加一個鬧鐘
[event setCalendar:[self.eventStore defaultCalendarForNewEvents]];//默認(rèn)日歷類型
//保存事件
[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(@"創(chuàng)建事件到系統(tǒng)日歷成功!");
}else{
NSLog(@"創(chuàng)建失敗%@",err);
}
//span:設(shè)置跨度。 EKSpanThisEvent:表示只影響當(dāng)前事件。? EKSpanFutureEvents 表示影響當(dāng)前和以后的所有事件。比如某條重復(fù)任務(wù)修改后保存時,傳EKSpanThisEvent表示值修改這一條重復(fù)事件。傳EKSpanFutureEvents表示修改這一條和以后的所有重復(fù)事件。刪除事件時,分別表示刪除這一條;刪除這一條和以后的所有。
刪除系統(tǒng)日歷事件
刪除方法:- (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 參數(shù)。yes:表示立即把此次操作提交到系統(tǒng)事件庫,NO表示此時不提交。如果一次性操作的事件數(shù)比較少的話,可以每次都傳YES,實(shí)時更新事件數(shù)據(jù)庫。如果一次性操作的事件較多的話,可以每次傳NO,最后再執(zhí)行一次提交所有更改到數(shù)據(jù)庫,把原來的更改全部提交到數(shù)據(jù)庫,不管是添加還是刪除。
未完待續(xù)...