iOS本地推送通知的简单封装(定时提醒、重复提醒)

iOS本地推送通知的简单封装(定时提醒、重复提醒)

  • 主要实现原理
    • iOS10及以上
      • 1.获取通知权限
      • 2.创建通知
      • 3.添加通知
      • 4.重复提醒
      • 5.取消通知
    • iOS10以下
      • 1.创建通知
      • 2.重复提醒
      • 3.取消通知
    • 注册通知
  • 快捷使用
  • 通知优先级问题
  • 代码下载
  • 疑问
  • 谢谢!

实现快捷创建简单的定时重复提醒推送功能。

主要实现原理

iOS10及以上

1.获取通知权限

iOS10及以上要先请求通知权限

UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
    //请求获取通知权限(角标,声音,弹框)
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge |
                                             UNAuthorizationOptionSound |
                                             UNAuthorizationOptionAlert)
                          completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            //获取用户是否同意开启通知
            NSLog(@"开启通知成功!");

        }
    }];
    

2.创建通知

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;
    

创建 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, 到指定触发点会被触发
[[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循环创建5个通知:

//因为周日是一星期第一天,1代表周日,所以周一从2开始
for (NSInteger i = 2; i <= 6; i++) {
//这里时间容器创建和以上每周提醒的一样,省略。
        components.weekday = i;
        
//然后用这个components去添加通知就可以实现重复通知了
}

5.取消通知

//找到要取消的通知名字
NSMutableArray * names = [[NSMutableArray alloc]initWithObjects:notificationName, nil];
//批量取消这些通知
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:names];

iOS10以下

1.创建通知

UILocalNotification *localNotification = [[UILocalNotification alloc]init];
    
    // 设置触发时间
    localNotification.fireDate = date;
    // 设置时区  以当前手机运行的时区为准
    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 每年

等等…
同样如果有需求是周一到周五某时提醒也用循环创建五个通知

for (NSInteger i = 2; i <= 6; i++) {
//同样用NSDateComponents设置weekday来实现星期几的提醒
//先用传入的date创建时间容器,然后修改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;		//标识通知优先级
extern ZBLocalNotificationKey const ZBNotificationRepeat;		//标识通知重复
extern ZBLocalNotificationSoundName const ZBNotificationSoundAlarm;	//标识声音为提醒
extern ZBLocalNotificationSoundName const ZBNotificationSoundOther;	//标识声音为其他

@interface ZBLocalNotification : NSObject

/**
 创建本地通知

 @param attribute 通知的属性
 */
+ (void)createLocalNotificationWithAttribute:(NSDictionary *)attribute;

/**
 取消通知

 @param notificationName 通知名字
 */
+ (void)cancelLocalNotificationWithName:(NSString *)notificationName;

#ifdef NSFoundationVersionNumber_iOS_9_x_Max

/**
 注册通知
 */
+ (void)requestUNUserNotificationAuthorization;

#endif

@end

创建时间为date的每天重复提醒例子:
导入#import "ZBLocalNotification.h"

[ZBLocalNotification createLocalNotificationWithAttribute:
                                @{ZBNotificationUserInfoName:@"notificationName",
                                  ZBNotificationSoundName:ZBNotificationSoundAlarm,
                                  ZBNotificationAlertBody:@"提醒内容",
                                  ZBNotificationAlertTitle:@"提醒标题",
                                  ZBNotificationFireDate:date,
                                  ZBNotificationPriority:@(0),
                                  ZBNotificationRepeat:@(ZBLocalNotificationRepeatEveryDay)
                                  }];
                                  

取消名字为 “notificationName” 的通知:

[ZBLocalNotification cancelLocalNotificationWithName:@"notificationName"];

通知优先级问题

如果设置了多个推送通知,并且时间都在同一个时刻时,就是同时收到多个推送通知时,想要只显示优先级最高的一个,我是在AppDelegate里这样处理的(希望有更好的方法能不吝赐教 ? ):
先创建一个userInfo容器,保存同一时间收到的通知
self.userInfos = [[NSMutableArray alloc]init];

//处理接收到的通知信息
- (void)filteredUserInfo {
    if (self.userInfos.count == 0) {
        return;
    }
    //选出你希望显示的通知信息,以下方法是显示优先级高的,你可以判断不同的条件
    //排序所有收到的通知信息,对比优先级,把优先级最高的放首位
    [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];
    //创建信号量,设置为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,时间到后继续执行
        	//0.3秒内第一次进入则等待0.3秒,0.3秒后对本时间段内提醒提取优先级最高的一个
        	//就是保存在极短时间内(我这里设置为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本地推送封装(定时推送、重复提醒)
·iOS本地推送封装(定时推送、重复提醒)

疑问

比如需求是可以自定义重复的时间:

  • 每隔两周的周二早上8点提醒
  • 每隔三个月的7号早上8点提醒

这种时候的怎么实现,NSDateComponents需要怎么设置?

谢谢!

欢迎讨论,未完待续


你可能感兴趣的:(总结)