需求:
1 每周周一到周五的九點半,通過本地通知提醒簽到;
2 如果使用者當天九點半之前已經簽到,不再提醒;
3 如果使用者設定不提醒,則永不提醒
實作:
1 關于本地通知移步這裡
2 實作代碼
static NSNotificationName const _Nullable kCheckinNotification = @"CheckinNotification";
static NSString *const _Nullable kCheckinNotificationSwitchKey = @"kCheckinNotificationSwitchKey";
/** 設定簽到通知*/
- (void)resetCheckinNotifications{
// 使用者首次使用 預設開啟通知(相當于NSUserDefaults)
if ([NSUtil getValueForKey:kCheckinNotificationSwitchKey] == nil) {
[NSUtil saveValue:@(YES) forKey:kCheckinNotificationSwitchKey];
}
// 如果使用者關閉通知,直接傳回
if([[NSUtil getValueForKey:kCheckinNotificationSwitchKey] isEqual: @(NO)]) return;
// 取消以前的通知
[self cancelAllNotification];
// weekday 1:周日 2:周一, 3:周二 4:周三 5:周四 6:周五 7:周六
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComps = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekday fromDate:[NSDate date]];
NSDate *zeroDate = [calendar dateFromComponents:dateComps] ;
NSDate *notifyDate = [zeroDate dateByAddingTimeInterval:9.5*60*60]; // 每天9:30分通知
// 未來一周 建立5個通知:星期一到星期五 (過濾掉周末 并按周重複)
for (int i=0;i<7;i++) {
// 從明天開始
NSInteger notifyWeekday = [dateComps weekday]+i+1;
// 如果是明天到下周了,矯正weekday
if(notifyWeekday >= 8){
notifyWeekday = notifyWeekday-7;
}
// 明天是周六或周日 過濾掉
if(notifyWeekday == 7 || notifyWeekday == 1) continue;
// 計算未來通知的時間
NSDate *date= [notifyDate dateByAddingTimeInterval:(i+1)*60*60*24];
// 隻是一個時間的格式化,将日期作為通知的identifier
NSString *identifier = [NSUtil stringWithDate:date format:@"yyyy-MM-dd"];
if (@available(iOS 10.0, *)) {
// weekday 2:周一, 3:周二 4:周三 5:周四 6:周五
UNNotificationRequest *request = [self createNotificationRequestWithWeekday:notifyWeekday identifier:identifier];
// 把通知加到UNUserNotificationCenter, 到指定觸發點會被觸發
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil];
}
else{
UILocalNotification *notification = [self createLocalNotificationWithDate:date identifier:identifier];
[kApplication scheduleLocalNotification:notification];
}
}
}
/** 取消一個特定的通知*/
- (void)cancelNotificationWithIdentifier:(NSString *)identifier{
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[identifier]];
}
else{
// 擷取目前所有的本地通知
NSArray *notificaitons = [[UIApplication sharedApplication] scheduledLocalNotifications];
if (!notificaitons || notificaitons.count <= 0) { return; }
for (UILocalNotification *notify in notificaitons) {
if ([[notify.userInfo objectForKey:@"identifier"] isEqualToString:identifier]) {
[[UIApplication sharedApplication] cancelLocalNotification:notify];
break;
}
}
}
}
- (void)cancelAllNotification{
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
[[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests];
}
else{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
}
/** 取消已經推過的通知*/
- (void)removeAllDeliveredNotifications __IOS_AVAILABLE(10.0){
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
}
}
#pragma mark - 私有方法
/** 設定指定時間通知,每周重複*/
- (UILocalNotification *)createLocalNotificationWithDate:(NSDate *)date identifier:(NSString *)identifier{
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
// 1.設定觸發時間(如果要立即觸發,無需設定)
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.fireDate = date;
localNotification.repeatInterval = NSCalendarUnitWeekday;
// 2.設定通知标題
localNotification.alertBody = self.title.length ? self.title:@"簽到通知";
localNotification.alertAction = self.content.length ? self.content:@"同學,今天簽到沒?千萬不要忘了哦!";
// localNotification.applicationIconBadgeNumber = ++kApplication.applicationIconBadgeNumber;
// 3.設定通知的 傳遞的userInfo
localNotification.userInfo = @{@"kLocalNotificationID":kCheckinNotification,@"identifier":identifier};
return localNotification;
}
/** 每個星期的星期幾 9點30通知*/
- (UNNotificationRequest *)createNotificationRequestWithWeekday:(NSInteger)weekday identifier:(NSString *)identifier {
// 1.建立通知内容
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.sound = [UNNotificationSound defaultSound];
content.title = self.title.length ? self.title:@"簽到提醒";
content.body = self.content.length ? self.content:@"同學,今天簽到沒?千萬不要忘了哦!";
//content.badge = @(++kApplication.applicationIconBadgeNumber); // 不顯示角标
content.userInfo = @{@"kLocalNotificationID":kCheckinNotification,@"identifier":identifier};
// 2.觸發模式 9點30 每周重複 ()
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
dateComponents.hour = 9; // 九點
dateComponents.minute = 30;
dateComponents.weekday = weekday;
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:YES];
// 4.設定UNNotificationRequest
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
return request;
}
@end
3 使用
首次使用調用一次resetCheckinNotifications 即可
在簽到成功的方法裡判斷如果簽到的時間在今天九點半以前,調用一次resetCheckinNotifications(目的取消今天的,設定以後的通知)
注意 不能直接拿當天的日期作為identifier去取消通知(通知中心裡保留的identifier是設定通知時的那一周的日期)
4 需要再AppDelegate裡面,注冊通知,并處理接收通知的回調
5 不足:未過濾調節假日,是以節假日還會提醒
如果有什麼不對的地方,或者有什麼更好的實作方法,歡迎評論區留言指正