一.關於通知注冊:
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