實現快捷創(chuàng)建簡單的定時重復提醒推送功能。
主要實現原理
iOS10及以上
1.獲取通知權限
iOS10及以上要先請求通知權限
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
//請求獲取通知權限(角標尿背,聲音端仰,彈框)
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge |
UNAuthorizationOptionSound |
UNAuthorizationOptionAlert)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
//獲取用戶是否同意開啟通知
NSLog(@"開啟通知成功!");
}
}];
2.創(chuàng)建通知
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = attribute[ZBNotificationAlertTitle];
// content.subtitle = @"本地通知副標題";
content.body = @"body";
//角標數量
content.badge = @1;
content.userInfo = userInfo;
//設置通知聲音
UNNotificationSound *sound = [UNNotificationSound defaultSound];
content.sound = sound;
創(chuàng)建 UNNotificationRequest :
//設置時間容器:傳人date中所有時間元素放入時間容器
NSDateComponents * components = [[NSCalendar currentCalendar]
components:NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitWeekday |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond
fromDate:date];
//設置UNCalendarNotificationTrigger
//repeats: 設置是否重復
UNCalendarNotificationTrigger * trigger = [UNCalendarNotificationTrigger
triggerWithDateMatchingComponents:components
repeats:repeat];
//設置UNNotificationRequest
//identifer:設置通知標識符或者說通知名字
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifer content:content trigger:trigger];
3.添加通知
//把通知加到UNUserNotificationCenter, 到指定觸發(fā)點會被觸發(fā)
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"通知添加失敗:%@",error);
} else {
NSLog(@"通知添加成功");
}
}];
4.重復提醒
如果repeats為YES時為重復提醒
約定在特定時間提醒時我們用時間容器來實現
NSDateComponents * components = [[NSCalendar currentCalendar]
components:NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitWeekday |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond
fromDate:date];
比如設置一個每天都提醒的推送,傳入的時間設置為:
NSDateFormatter * formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate * date = [formatter dateFromString:@"2019-01-01 08:00:00"];
則 每天8點 進行推送提醒的 時間容器 為:
NSDateComponents * components = [[NSCalendar currentCalendar]
components:NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond
fromDate:date];
每周二8點 (19年1月1號為周二) 進行推送提醒的 時間容器 為:
NSDateComponents * components = [[NSCalendar currentCalendar]
components:NSCalendarUnitWeekday |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond
fromDate:date];
每月1號8點 進行推送提醒的 時間容器 為:
NSDateComponents * components = [[NSCalendar currentCalendar]
components:NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond
fromDate:date];
每年1月1號8點 進行推送提醒的 時間容器 為:
NSDateComponents * components = [[NSCalendar currentCalendar]
components:NSCalendarUnitMonth |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond
fromDate:date];
以此類推..
如果有需求是要 周一到周五的每天8點 提醒時田藐,我的做法是用for循環(huán)創(chuàng)建5個通知:
//因為周日是一星期第一天榆俺,1代表周日,所以周一從2開始
for (NSInteger i = 2; i <= 6; i++) {
//這里時間容器創(chuàng)建和以上每周提醒的一樣坞淮,省略。
components.weekday = i;
//然后用這個components去添加通知就可以實現重復通知了
}
5.取消通知
//找到要取消的通知名字
NSMutableArray * names = [[NSMutableArray alloc]initWithObjects:notificationName, nil];
//批量取消這些通知
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:names];
iOS10以下
1.創(chuàng)建通知
UILocalNotification *localNotification = [[UILocalNotification alloc]init];
// 設置觸發(fā)時間
localNotification.fireDate = date;
// 設置時區(qū) 以當前手機運行的時區(qū)為準
localNotification.timeZone = [NSTimeZone localTimeZone];
// 設置推送 顯示的內容
localNotification.alertTitle = @"title";
localNotification.alertBody = @"body";
// 設置 角標
localNotification.applicationIconBadgeNumber = 1;
// 不設置此屬性陪捷,則默認不重復
localNotification.repeatInterval = repeatInterval;
// 設置推送的聲音
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.userInfo = userInfo;
//添加到通知
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
2.重復提醒
重復提醒通過設置 repeatInterval 就可以
value | effect |
---|---|
NSCalendarUnitDay | 每天 |
NSCalendarUnitWeekday | 每周 |
NSCalendarUnitMonth | 每月 |
NSCalendarUnitYear | 每年 |
... | ... |
等等...
同樣如果有需求是周一到周五某時提醒也用循環(huán)創(chuàng)建五個通知
for (NSInteger i = 2; i <= 6; i++) {
//同樣用NSDateComponents設置weekday來實現星期幾的提醒
//先用傳入的date創(chuàng)建時間容器回窘,然后修改weekday后再轉為NSDate
NSDateComponents * components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:date];
components.weekday = i;
NSDate * newDate = [[NSCalendar currentCalendar] dateFromComponents:components];
//吧newDate再賦值給fireDate
}
3.取消通知
//獲取所有通知
NSArray * localNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (UILocalNotification * notification in localNotifications) {
//找到和要刪除的通知同名的通知刪除
if ([notification.userInfo[@"notificationName"] hasPrefix:notificationName]) {
//刪除通知
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
注冊通知
//注冊通知
[[UIApplication sharedApplication] registerForRemoteNotifications];
快捷使用
封裝了一個可以直接使用的類:ZBLocalNotification
//提醒重復類型
typedef NS_ENUM(NSInteger, ZBLocalNotificationRepeat) {
ZBLocalNotificationRepeatNone, //不重復
ZBLocalNotificationRepeatEveryDay, //每天
ZBLocalNotificationRepeatEveryWeek, //每周
ZBLocalNotificationRepeatEveryMonth, //每月
ZBLocalNotificationRepeatEveryYear, //每年
ZBLocalNotificationRepeatEveryWorkDay //每周一到周五(工作日)
};
//標識通知屬性的key
typedef NSString * ZBLocalNotificationKey;
//標識通知聲音文件名字的key
typedef NSString * ZBLocalNotificationSoundName;
extern ZBLocalNotificationKey const ZBNotificationFireDate; //標識提醒時間
extern ZBLocalNotificationKey const ZBNotificationAlertTitle; //標識標題
extern ZBLocalNotificationKey const ZBNotificationAlertBody; //標識提醒內容
extern ZBLocalNotificationKey const ZBNotificationAlertAction; //標識按鈕
extern ZBLocalNotificationKey const ZBNotificationSoundName; //標識聲音
extern ZBLocalNotificationKey const ZBNotificationUserInfoName; //標識通知名字
extern ZBLocalNotificationKey const ZBNotificationPriority; //標識通知優(yōu)先級
extern ZBLocalNotificationKey const ZBNotificationRepeat; //標識通知重復
extern ZBLocalNotificationSoundName const ZBNotificationSoundAlarm; //標識聲音為提醒
extern ZBLocalNotificationSoundName const ZBNotificationSoundOther; //標識聲音為其他
@interface ZBLocalNotification : NSObject
/**
創(chuàng)建本地通知
@param attribute 通知的屬性
*/
+ (void)createLocalNotificationWithAttribute:(NSDictionary *)attribute;
/**
取消通知
@param notificationName 通知名字
*/
+ (void)cancelLocalNotificationWithName:(NSString *)notificationName;
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
/**
注冊通知
*/
+ (void)requestUNUserNotificationAuthorization;
#endif
@end
創(chuàng)建時間為date的每天重復提醒例子:
導入#import "ZBLocalNotification.h"
[ZBLocalNotification createLocalNotificationWithAttribute:
@{ZBNotificationUserInfoName:@"notificationName",
ZBNotificationSoundName:ZBNotificationSoundAlarm,
ZBNotificationAlertBody:@"提醒內容",
ZBNotificationAlertTitle:@"提醒標題",
ZBNotificationFireDate:date,
ZBNotificationPriority:@(0),
ZBNotificationRepeat:@(ZBLocalNotificationRepeatEveryDay)
}];
取消名字為 “notificationName” 的通知:
[ZBLocalNotification cancelLocalNotificationWithName:@"notificationName"];
通知優(yōu)先級問題
如果設置了多個推送通知,并且時間都在同一個時刻時市袖,就是同時收到多個推送通知時啡直,想要只顯示優(yōu)先級最高的一個,我是在AppDelegate里這樣處理的(希望有更好的方法能不吝賜教 :) ):
先創(chuàng)建一個userInfo容器苍碟,保存同一時間收到的通知
self.userInfos = [[NSMutableArray alloc]init];
//處理接收到的通知信息
- (void)filteredUserInfo {
if (self.userInfos.count == 0) {
return;
}
//選出你希望顯示的通知信息酒觅,以下方法是顯示優(yōu)先級高的,你可以判斷不同的條件
//排序所有收到的通知信息微峰,對比優(yōu)先級舷丹,把優(yōu)先級最高的放首位
[self.userInfos sortUsingComparator:^NSComparisonResult(NSDictionary * obj1, NSDictionary * obj2) {
if ([obj1[ZBNotificationPriority] integerValue] < [obj2[ZBNotificationPriority] integerValue]) {
return NSOrderedDescending;
}
return NSOrderedSame;
}];
//自定義展示推送內容
[self showAlarmAlertWithUserInfo:self.userInfos.firstObject];
//重置userInfo容器
[self.userInfos removeAllObjects];
}
//添加通知到userInfo容器
- (void)waitMultipleUserInfo:(NSDictionary *)userInfo {
[self.userInfos addObject:userInfo];
//創(chuàng)建信號量,設置為0
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(quene, ^{
if (self.userInfos.count == 1) {
//信號量為0時蜓肆,那么這個函數就阻塞當前線程等待timeout颜凯,時間到后繼續(xù)執(zhí)行
//0.3秒內第一次進入則等待0.3秒,0.3秒后對本時間段內提醒提取優(yōu)先級最高的一個
//就是保存在極短時間內(我這里設置為0.3s)收到的所有通知仗扬,然后進行處理
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC));
dispatch_async(dispatch_get_main_queue(), ^{
[self filteredUserInfo];
});
}
});
}
#pragma mark - localNotification
// iOS10以下 在前臺收到推送回調
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
[self waitMultipleUserInfo:notification.userInfo];
}
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#pragma mark - UNUserNotificationCenterDelegate
// iOS10 在前臺收到推送回調
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(nonnull UNNotification *)notification withCompletionHandler:(nonnull void (^)(UNNotificationPresentationOptions))completionHandler{
UNNotificationRequest *request = notification.request; // 收到推送的請求
UNNotificationContent *content = request.content; //收到推送消息的全部內容
if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
NSLog(@"iOS10 收到遠程通知");
}else{
NSLog(@"ios10 收到本地通知userInfo:%@",content.userInfo);
[self waitMultipleUserInfo:content.userInfo];
}
completionHandler(UNNotificationPresentationOptionBadge |
UNNotificationPresentationOptionSound
);
}
#endif
代碼下載
ZBLocalNotification類下載地址:
iOS本地推送封裝(定時推送症概、重復提醒)
ZBLocalNotification類下載地址:
iOS本地推送封裝(定時推送、重復提醒)
疑問
比如需求是可以自定義重復的時間:
- 每隔兩周的周二早上8點提醒
- 每隔三個月的7號早上8點提醒
這種時候的怎么實現早芭,NSDateComponents需要怎么設置彼城?
謝謝!
歡迎討論,未完待續(xù)