本地通知使用总结
一.关于通知注册:
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