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