本地通知使用总结

时间:2022-03-31 19:37:32

一.关于通知注册:

ios8之前:registerForRemoteNotificationTypes:

ios8之后:registerUserNotificationSettings

 

二.关于提醒角标

    1.本地推送UILocalNotification的applicationIconBadgeNumber属性只会影响角标的显示,不会影响通知栏的通知处理。

       1)当applicationIconBadgeNumber>0时,角标会随applicationIconBadgeNumber而变化。

       2)当applicationIconBadgeNumber=0时,角标维持推送前状态不变。

       3)当applicationIconBadgeNumber<0时,角标置0不显示。

    2.远程推送的badge字段,只会影响角标的显示,不会影响通知栏的通知处理。

      1)当badge>0时,角标会随badge而变化。

      2)当badge=0时,角标维持不变。

      3)当badge<0时,角标维持不变。

    3.UIApplication的applicationIconBadgeNumber属性既会影响角标的显示,又会影响通知栏通知的处理。

      1)当applicationIconBadgeNumber>0时,角标会随之变化,通知栏通知不变。

      2)当applicationIconBadgeNumber=0时,角标变为0不显示,通知栏通知清空。

       3)当applicationIconBadgeNumber<0时,角标变为0不显示,通知栏通知清空。

 

三.关于重复:

   1. UILocalNotification.repeatInterval:repeatInterval的下限应该是NSCalendarUnitMinute,即每分钟重复发送一次通知。如果设置为NSCalendarUnitSecond,那么消息不会重复,每秒发送一次通知,iOS系统当然不会容许这样的存在了。这里比较不好的一点是NSCalendarUnit是个枚举类型,该值不能自定义,例如你不能塞个10.0给它从而希望它每十秒重复一次。所以如果你想每20分钟发送一次通知,一小时内发送3次,那么只能同时设定三个通知了。

   2.若想设置复杂的重复通知,比如只在每周的周一、周三重复,则只能设置两个通知,分别进行周重复提醒。

 

四.关于userInfo:userInfo可以携带用户自定义的关于通知的信息,通常可以用来作为不同通知的区分标志

 

五.关于接收通知:

1. 如果此时应用程序还在运行(无论是在前台还是在后台)则会调用-(void)application:(UIApplication *)applicationdidReceiveLocalNotification:(UILocalNotification *)notification(如果是远程通知则通过application:(UIApplication *)applicationdidReceiveLocalNotification:(UILocalNotification *)notification)方法接收消息参数。参数中可以拿到notification对象,只要读取userInfo属性区分不同的通知即可。

2. 如果应用程序已经完全退出此时会调用- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法:

    1)通过点击通知栏通知进入:此时可以访问launchOptions中键为UIApplicationLaunchOptionsLocalNotificationKey的对象,这个对象就是发送的通知,由此对象再去访问userInfo。

   2)通过点击图标进入:可以通过[[UIApplication sharedApplication] scheduledLocalNotifications]获取全部的调度通知,并通过userinfo进行区分

 

六:关于覆盖安装:

    如果我们的应用程序给系统发送的本地通知是周期性的,那么即使把程序删了重装,之前的本地通知在重装时依然存在,没有从系统中移除



#import "AppDelegate.h"
#import "ViewController.h"
#import "HomeViewController.h"
#import "KCMainViewController.h"

#define NotificationID @"NotificationID"
NSString * const NotificationCategoryIdent = @"ACTIONABLE";
NSString * const NotificationActionOneIdent = @"ACTION_ONE";
NSString * const NotificationActionTwoIdent = @"ACTION_TWO";


@implementation AppDelegate

#pragma mark 用户打开app,分为点击图标打开与点击通知栏通知打开方式
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

//程序开启时取消之前注册的通知
//1.通过点击通知栏通知开启app
// UILocalNotification *notification=[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
// if(notification!=nil){
// NSDictionary *dic = [notification userInfo];
// NSString *Identifer = [dic objectForKey:@"id"];
// if ([Identifer isEqualToString:NotificationID]) {
// [self cancelLocation:notification];
// }
//
// }
//
// //2.通过点击图标开启app
// else {
// [self cancelLocationWithIdentifier:NotificationID];
// }

[self cancelLocationWithIdentifier:NotificationID];

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

ViewController *vc = [[ViewController alloc] init];
self.window.rootViewController = vc;

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];



UIUserNotificationType types = (UIUserNotificationTypeAlert|
UIUserNotificationTypeSound|
UIUserNotificationTypeBadge);

NSSet *categories = [self addNotiActionCategories];


//注册通知。ios8之后的方式
if ([[UIApplication sharedApplication]currentUserNotificationSettings].types!=UIUserNotificationTypeNone) {

}else{
[[UIApplication sharedApplication]registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:types categories:categories]];

}
return YES;

}

#pragma mark 调用过用户注册通知方法之后执行(也就是调用完registerUserNotificationSettings:方法之后执行)
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
if (notificationSettings.types!=UIUserNotificationTypeNone) {

[self addLocalNotification];
}
}



#pragma mark 当应用在前台,或者后台运行时收到通知后的处理接口
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{

//获取通知的userInfo
NSString *receiveUseInfoID = notification.userInfo[@"id"];

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"失败" message:@"失败" preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *actCancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){

}];

UIAlertAction *actDetail = [UIAlertAction actionWithTitle:receiveUseInfoID style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

}];

[alertController addAction:actCancel];
[alertController addAction:actDetail];
[[self getCurrentVC] presentViewController:alertController animated:YES completion:nil];
}


#pragma mark 当应用未在前台,收到本地通知后,左划通知,显示按钮对应的点击动作处理接口
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler {
if ([identifier isEqualToString:NotificationActionOneIdent]) {

NSLog(@"You chose action 1.");
}
else if ([identifier isEqualToString:NotificationActionTwoIdent]) {

NSLog(@"You chose action 2.");
}
if (completionHandler) {

completionHandler();
}
}


#pragma mark 当应用未在前台,收到远程通知后,左划通知 通知滑动后的动作选项处理接口
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler {

if ([identifier isEqualToString:NotificationActionOneIdent]) {

NSLog(@"You chose action 1.");
}
else if ([identifier isEqualToString:NotificationActionTwoIdent]) {

NSLog(@"You chose action 2.");
}
if (completionHandler) {

completionHandler();
}
}


#pragma mark 进入前台后设置消息信息,只在由后台进入前台时调用,重新开启app时不会调用
-(void)applicationWillEnterForeground:(UIApplication *)application{
// NSInteger num =[UIApplication sharedApplication].applicationIconBadgeNumber;
// [[UIApplication sharedApplication]setApplicationIconBadgeNumber:0];//进入前台取消应用消息图标
}

#pragma mark 进入前台后设置消息信息,由后台进入前台以及重新开启app时均会调用
- (void)applicationDidBecomeActive:(UIApplication *)application{

[[UIApplication sharedApplication]setApplicationIconBadgeNumber:0];//进入前台取消应用消息图标,同时清空通知栏通知

}

#pragma mark 程序即将退出时注册通知
-(void)applicationWillTerminate:(UIApplication *)application{
[self addLocalNotification];
}


#pragma mark - 私有方法
#pragma mark 添加本地通知

-(void)addLocalNotification{

NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:60 * 60 * 7];
[self addNormalLocationWithIdentifier:NotificationID WithFireDate:fireDate WithRepeatInterval:NSCalendarUnitWeekday];
}

//注册通知
-(void)addNormalLocationWithIdentifier:(NSString *)Identifier WithFireDate:(NSDate *)fireDate WithRepeatInterval:(NSCalendarUnit)repeatInterval{

UILocalNotification *notification=[[UILocalNotification alloc]init];
//设置调用时间
notification.fireDate=fireDate;//通知触发的时间,10s以后
notification.repeatInterval=repeatInterval ;//通知重复次数,枚举类型,除枚举类型外的其它值不会引起重复通知,为0时亦不会重复
[notification setCategory:NotificationCategoryIdent];
//notification.repeatCalendar=[NSCalendar currentCalendar];//当前日历,使用前最好设置时区等信息以便能够自动同步时间

//设置通知属性
notification.alertBody=@"你好你好,是否立即体验?"; //通知主体
notification.applicationIconBadgeNumber=4;//应用程序图标右上角显示的消息数
notification.alertAction=@"打开应用"; //待机界面的滑动动作提示
notification.alertLaunchImage=@"Default";//通过点击通知打开应用时的启动图片,这里使用程序启动图片
//notification.soundName=UILocalNotificationDefaultSoundName;//收到通知时播放的声音,默认消息声音
notification.soundName=@"msg.caf";//通知声音(需要真机才能听到声音)

//设置用户信息
NSMutableDictionary *aUserInfo = [[NSMutableDictionary alloc] init];
aUserInfo[@"id"] = Identifier;
aUserInfo[@"sequence"] = [NSNumber numberWithInt:-1];
notification.userInfo = aUserInfo;

//按调度调用通知
[[UIApplication sharedApplication] scheduleLocalNotification:notification];

//立即调用通知
//[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}


//注册只在某些日期按周重复的通知
-(void)addRepeatLocationWithWeekDate:(NSArray *)dateArray WithIdentifier:(NSString *)identifier{

NSInteger todayWeekDay = [self weekdayWithDate:[NSDate date]];

for (NSString * dateStr in dateArray) {
NSInteger dateNum = [dateStr integerValue];
NSInteger dateSeq;
dateSeq = (dateNum + 7 -todayWeekDay)%7;
if (!dateSeq) {
dateSeq = 7;
}

NSDate *date = [[NSDate date] dateByAddingTimeInterval:(24*3600*dateSeq)];
[self addNormalLocationWithIdentifier:identifier WithFireDate:date WithRepeatInterval:NSCalendarUnitWeekday];
}
}

//注册有小睡nap分钟的通知
-(void)addNapLocationWithIdentifier:(NSString *)identifier WithFireDate:(NSDate *)fireDate WithRepeatInterval:(NSCalendarUnit)repeatInterval WithNap:(NSInteger)nap{


//若nap为0,则注册一次通知,相当于不重复,否则重复三次
NSInteger times;
if (nap > 0) {
times = 3;
} else {
times = 1;
}

for (int i = 0; i < times; i++) {
[self addNormalLocationWithIdentifier:identifier WithFireDate:[fireDate dateByAddingTimeInterval:i * nap * 60] WithRepeatInterval:repeatInterval];
}
}

#pragma mark 移除本地通知,在不需要此通知时记得移除


//移除指定通知
-(void)cancelLocation:(UILocalNotification *)noti{
[[UIApplication sharedApplication] cancelLocalNotification:noti];
}


//移除特定id的通知
-(void)cancelLocationWithIdentifier:(NSString *)identifier{

for (UILocalNotification *noti in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
NSString *notiID = noti.userInfo[@"id"];
if ([notiID isEqualToString:identifier]) {

[[UIApplication sharedApplication] cancelLocalNotification:noti];
}
}
}

//移除全部通知
-(void)cancelAllLocation{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}

#pragma mark 添加通知动作action
-(NSSet *)addNotiActionCategories{
UIMutableUserNotificationAction *action1;
action1 = [[UIMutableUserNotificationAction alloc] init];
[action1 setActivationMode:UIUserNotificationActivationModeBackground];
[action1 setTitle:@"Action 1"];
[action1 setIdentifier:NotificationActionOneIdent];
[action1 setDestructive:NO];
[action1 setAuthenticationRequired:NO];

UIMutableUserNotificationAction *action2;
action2 = [[UIMutableUserNotificationAction alloc] init];
[action2 setActivationMode:UIUserNotificationActivationModeBackground];
[action2 setTitle:@"Action 2"];
[action2 setIdentifier:NotificationActionTwoIdent];
[action2 setDestructive:NO];
[action2 setAuthenticationRequired:NO];

UIMutableUserNotificationCategory *actionCategory;
actionCategory = [[UIMutableUserNotificationCategory alloc] init];
[actionCategory setIdentifier:NotificationCategoryIdent];
[actionCategory setActions:@[action1, action2]
forContext:UIUserNotificationActionContextDefault];

NSSet *categories = [NSSet setWithObject:actionCategory];
return categories;
}


#pragma mark 返回周几
-(int)weekdayWithDate:(NSDate *)date{ //返回周几
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:NSCalendarUnitWeekday fromDate:date];
int weekday = [components weekday];
return weekday-1==0?7:weekday-1;
}

#pragma mark 获取窗口当前展示VC
- (UIViewController *)getCurrentVC
{
UIViewController *result = nil;

UIWindow * window = [[UIApplication sharedApplication] keyWindow];
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}

UIView *frontView = [[window subviews] objectAtIndex:0];
id nextResponder = [frontView nextResponder];

if ([nextResponder isKindOfClass:[UIViewController class]])
result = nextResponder;
else
result = window.rootViewController;

return result;
}

@end