iOS常用通知
1、本地推送通知:(Local Notification):
??不需要聯(lián)網(wǎng)就可以發(fā)出的通知, 常用于提醒用戶完成一些任務(wù)锹杈,如:鬧鐘撵孤,日歷待辦事項(xiàng)提醒,備注等等;
2竭望、遠(yuǎn)程推送通知:(Remote Notification)
??從遠(yuǎn)程服務(wù)器(APNs)推送給客戶端的通知(需要聯(lián)網(wǎng)), 模擬器無(wú)法調(diào)試遠(yuǎn)程推送;
??常用于解決獲取傳統(tǒng)數(shù)據(jù)的局限性邪码,能讓數(shù)據(jù)實(shí)時(shí)更新, 在聯(lián)網(wǎng)的情況下, 蘋果設(shè)備都會(huì)與APNs建立長(zhǎng)連接, 因此能保證數(shù)據(jù)傳輸速度快及保證數(shù)據(jù)的實(shí)時(shí)性...
本篇只介紹本地推送通知:
通知的授權(quán)與注冊(cè): (分iOS10.0 以后 與 之前)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 通知的授權(quán)檢查
[self checkNotificationAuthorization];
// 本地通知 + App未存活 (iOS 10.0以前)
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification.userInfo) {
// 處理收到的通知
}
return YES;
}
/**
檢查本地通知的授權(quán)
*/
- (void)checkNotificationAuthorization {
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
// 這兩個(gè)必須要寫(xiě)在上面 每次程序重新打開(kāi)時(shí)都得設(shè)置一遍...
center.delegate = self;
//添加category: iOS 10.0以后
[center setNotificationCategories:[self createNotificationCategoryActionsForNewVersion]];
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) { // 判斷是否是未選擇授權(quán)狀態(tài)
// 若未授權(quán), 則請(qǐng)求授權(quán)
[center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
NSLog(@"授權(quán)開(kāi)啟成功");
} else {
NSLog(@"授權(quán)開(kāi)啟失敗");
}
}];
}
}];
} else {
//添加category: iOS 8.0以后
UIUserNotificationCategory * category = [self adduserNotificationCategory];
UIUserNotificationSettings * setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:[NSSet setWithObject:category]];
[[UIApplication sharedApplication] registerUserNotificationSettings:setting];
}
}
添加 category (即在通知欄重壓時(shí)設(shè)置其按鈕)
通知欄的通知
//添加category: iOS 10.0以后
-(NSSet *)createNotificationCategoryActionsForNewVersion{
//注冊(cè)本地通知用到的Action
//進(jìn)入app按鈕
UNNotificationAction * localAction = [UNNotificationAction actionWithIdentifier:kCategoryActionIdentifierOpen title:@"查看通知" options:UNNotificationActionOptionForeground];
//取消按鈕
UNNotificationAction *localCancel = [UNNotificationAction actionWithIdentifier:kCategoryActionIdentifierCancel title:@"忽略" options:UNNotificationActionOptionDestructive];
//將這些action帶入category
UNNotificationCategory *localCategory = [UNNotificationCategory categoryWithIdentifier:kUNCategoryIdentifier actions:@[localAction,localCancel] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];
return [NSSet setWithObjects:localCategory,nil];
}
//添加category: iOS 8.0以后
- (UIMutableUserNotificationCategory *)adduserNotificationCategory {
//UIMutableUserNotificationAction用來(lái)添加自定義按鈕
UIMutableUserNotificationAction * responseAction = [[UIMutableUserNotificationAction alloc] init];
responseAction.identifier = kCategoryActionIdentifierOpen;
responseAction.title = @"查看通知";
responseAction.activationMode = UIUserNotificationActivationModeForeground; //點(diǎn)擊的時(shí)候啟動(dòng)程序
responseAction.authenticationRequired = YES;//需要解鎖權(quán)限
UIMutableUserNotificationAction *deleteAction = [[UIMutableUserNotificationAction alloc] init];
deleteAction.identifier = kCategoryActionIdentifierCancel;
deleteAction.title = @"忽略";
deleteAction.activationMode = UIUserNotificationActivationModeBackground; //點(diǎn)擊的時(shí)候不啟動(dòng)程序,后臺(tái)處理
deleteAction.destructive = YES; //YES為紅色咬清,NO為藍(lán)色
UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
category.identifier = kUNCategoryIdentifier;//用于將該 category 標(biāo)識(shí)的同時(shí)闭专,那一個(gè) notification 實(shí)例需要使用這個(gè) category 的 actions 也是傳入這個(gè)值給 notification 的。
//UIUserNotificationActionContextDefault:默認(rèn)添加可以添加兩個(gè)自定義按鈕
//UIUserNotificationActionContextMinimal:四個(gè)自定義按鈕
[category setActions:@[responseAction, deleteAction] forContext:UIUserNotificationActionContextDefault];
return category;
}
添加通知
??這里是點(diǎn)擊一個(gè)按鈕事件來(lái)添加通知的:
- (IBAction)addLocalNotification:(UIButton *)sender {
NSDictionary * dict = @{@"businessId": @"kLocalNotificationTest",@"title": @"本地通知測(cè)試",@"memo": @"通知發(fā)送成功", @"startTime": @"2019-10-28 10:10:10"};
NSDictionary * dict1 = @{@"businessId": @"kLocalNotificationTestOne",@"title": @"本地通知測(cè)試__One",@"memo": @"通知發(fā)送成功__One", @"startTime": @"2019-10-28 10:10:10"};
NSArray * arr = @[dict, dict1];
// 添加兩個(gè)通知
for (NSDictionary * dataDic in arr) {
NSData * data = [NSJSONSerialization dataWithJSONObject:dataDic options:NSJSONWritingPrettyPrinted error:nil];
NSString * string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self addLocalNotificationWithData:string];
}
}
/**
添加本地通知
@param dataString 通知的內(nèi)容: 字典序列化后的字符串
*/
- (void)addLocalNotificationWithData: (NSString *)dataString {
NSData * data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
NSLog(@"用戶未授權(quán)");
return;
}
UNMutableNotificationContent * content = [[UNMutableNotificationContent alloc] init];
self.badgeNum++;
content.badge = @(self.badgeNum);
content.title = dict[@"title"];
content.body = dict[@"memo"];
content.userInfo = @{@"type" : kNotificationScheduleType, @"data": dict};;
// 這個(gè)必須要加 且要和 UNNotificationCategory 的Identifier 保持一致
content.categoryIdentifier = kUNCategoryIdentifier;
UNTimeIntervalNotificationTrigger * trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5.f repeats:NO];
UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier:dict[@"businessId"] content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"添加本地通知報(bào)錯(cuò): %@", error);
}
}];
}];
} else {
if ([[UIApplication sharedApplication] currentUserNotificationSettings].types == UIUserNotificationTypeNone) {
NSLog(@"用戶未授權(quán)");
return;
}
UILocalNotification * notification = [[UILocalNotification alloc] init];
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.f];
notification.alertTitle = dict[@"title"];
notification.alertBody = dict[@"memo"];
self.badgeNum++;
notification.applicationIconBadgeNumber = self.badgeNum;
notification.soundName = UILocalNotificationDefaultSoundName;
notification.alertAction = @"查看";
notification.userInfo = @{@"type" : kNotificationScheduleType, @"data": dict};;
notification.category = kUNCategoryIdentifier;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
通知的回調(diào)處理:
??iOS10.0 后是通知代理來(lái)回調(diào)的 UNUserNotificationCenterDelegate
// App在前臺(tái)獲取通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0)){
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
}
// 點(diǎn)擊通知進(jìn)入App
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(ios(10.0)){
completionHandler();
NSDictionary * userInfo = response.notification.request.content.userInfo;
if(userInfo[@"type"] && [userInfo[@"type"] isEqualToString:kNotificationScheduleType]) {
if([response.actionIdentifier isEqualToString:kCategoryActionIdentifierCancel] || [response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) {
// 通知欄點(diǎn)擊 忽略 或 清除 時(shí)的回調(diào)
} else {
// 點(diǎn)擊 打開(kāi) 或 查看 時(shí)的回調(diào)
}
}
}
??iOS10.0 以前的通知回調(diào):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 本地通知 + App未存活
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification.userInfo) {
// 處理回調(diào)回來(lái)的通知事件
}
return YES;
}
// APP在前臺(tái)運(yùn)行中收到 本地通知 時(shí)調(diào)用, 以及App 處于后臺(tái)掛起(suspended)狀態(tài)旧烧,但未 terminated 時(shí)喻圃,點(diǎn)擊通知啟動(dòng)都是這個(gè)方法進(jìn)行響應(yīng)
// 即 App 存活
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
}
//調(diào)用過(guò)用戶注冊(cè)通知方法之后執(zhí)行(也就是調(diào)用完registerUserNotificationSettings:方法之后執(zhí)行)
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
}
// APP 將要進(jìn)入前臺(tái)時(shí)調(diào)用
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 設(shè)置App圖標(biāo)通知數(shù)量顯示
}
//iOS 8 ~ 9 ,當(dāng)點(diǎn)擊本地通知自定義的響應(yīng)按鈕(action btn)時(shí)粪滤,根據(jù)按鈕的 activeMode 模式斧拍,回調(diào)以下方法
//1. ActivationModeForeground 的 action , 會(huì)啟動(dòng) App 同時(shí)回調(diào)方法
//2. ActivationModeBackground 的 action 不啟動(dòng) App 讓 App 在 background 下回調(diào)方法
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
if ([identifier isEqualToString:@"kCategoryActionIdentifierOpen"]) {
//ActivationModeForeground 的 action , 啟動(dòng) App 讓 App 在 Foreground 下響應(yīng)
} else {
//ActivationModeBackground 的 action 不啟動(dòng) App 讓 App 在 background 下響應(yīng)
NSLog(@"%s -- %@ -- identifier %@ --- thread %@", __func__, notification, identifier, [NSThread currentThread]);
// //下面代碼用于測(cè)試,退出 App 后接收到 本地通知時(shí)杖小,點(diǎn)擊后臺(tái)action時(shí)是否執(zhí)行了這個(gè)響應(yīng)方法肆汹。實(shí)測(cè)執(zhí)行了的
// [[NSUserDefaults standardUserDefaults] setObject:@"ActivationModeBackground 的 action 不啟動(dòng) App 讓 App 在 background 下響應(yīng)" forKey:@"IGNOREKEY"];
// [[NSUserDefaults standardUserDefaults] synchronize];
}
completionHandler(); //根據(jù)Action btn 的 identifier 處理自定義事件后應(yīng)該馬上調(diào)用 completionHandler block,如果調(diào)用 completionHandler block 失敗的話,App 會(huì)立即 terminated予权。
}
移除通知 或 移除指定通知
#pragma mark -- 移除本地通知
/**
移除指定的通知
@param identifierStr 通知的唯一標(biāo)識(shí) 或 信息
*/
- (void)removeNotificationWithIdentifier:(NSString *)identifierStr {
//獲取本地通知數(shù)組 (該數(shù)組會(huì)持有需要重復(fù) fired 的 已被 copy 的 notification 對(duì)象昂勉,用于到達(dá)下次間隔時(shí)再 fire, 如果不需要重復(fù)的 notification,即 notification.repeatInterval = 0 的話扫腺,該 notification fire 之后不會(huì)被 copy 保留到這個(gè)數(shù)組里)
//本地通知最多只能有64個(gè)岗照,超過(guò)會(huì)被系統(tǒng)忽略
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[identifierStr]];
} else {
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (UILocalNotification * notification in notifications) {
NSString * businessId = notification.userInfo[@"businessId"];
if ([identifierStr isEqualToString:businessId]) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
}
/*
執(zhí)行取消本地通知的場(chǎng)景:
1. 已經(jīng)響應(yīng)過(guò)的本地通知,需要取消笆环。
2. 已經(jīng)遞交到 application 的攒至,但在 fire 之前 確定要取消的通知,需要取消躁劣。如提醒任務(wù)的取消迫吐,或更改提醒時(shí)間(此時(shí)應(yīng)該是新的一個(gè)本地通知了)
*/
}
/**
移除所有的通知
*/
- (void)removeAllNotification {
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests];
} else {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
}
因代碼是在項(xiàng)目里抽取的, 有不正之處歡迎指證...
***全部代碼:
AppDelegate.h
#import "AppDelegate.h"
#import "LocalNotification/LocalNotificationManager.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[LocalNotificationManager shareLocalNotification] checkNotificationAuthorization];
[[LocalNotificationManager shareLocalNotification] removeAllNotification];
// 本地通知 + App未存活
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification.userInfo) {
[[NSUserDefaults standardUserDefaults] setObject:notification.userInfo forKey:@"localNotificationKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
return YES;
}
// APP在前臺(tái)運(yùn)行中收到 本地通知 時(shí)調(diào)用, 以及App 處于后臺(tái)掛起(suspended)狀態(tài),但未 terminated 時(shí)账忘,點(diǎn)擊通知啟動(dòng)都是這個(gè)方法進(jìn)行響應(yīng)
// 即 App 存活
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
[[LocalNotificationManager shareLocalNotification] receiveLocalNotificationWithUserInfo:notification.userInfo];
}
//調(diào)用過(guò)用戶注冊(cè)通知方法之后執(zhí)行(也就是調(diào)用完registerUserNotificationSettings:方法之后執(zhí)行)
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
NSLog(@"%s",__func__);
}
// APP 將要進(jìn)入前臺(tái)時(shí)調(diào)用
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 設(shè)置這個(gè)后, 后導(dǎo)致通知欄里的通知, 點(diǎn)擊其中任何一個(gè)后, 其它通知都會(huì)消失...
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
[LocalNotificationManager shareLocalNotification].badgeNum = 0;
}
//iOS 8 ~ 9 志膀,當(dāng)點(diǎn)擊本地通知自定義的響應(yīng)按鈕(action btn)時(shí)熙宇,根據(jù)按鈕的 activeMode 模式,回調(diào)以下方法
//1. ActivationModeForeground 的 action , 會(huì)啟動(dòng) App 同時(shí)回調(diào)方法
//2. ActivationModeBackground 的 action 不啟動(dòng) App 讓 App 在 background 下回調(diào)方法
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
if ([identifier isEqualToString:@"kCategoryActionIdentifierOpen"]) {
//ActivationModeForeground 的 action , 啟動(dòng) App 讓 App 在 Foreground 下響應(yīng)
[[LocalNotificationManager shareLocalNotification] receiveLocalNotificationWithUserInfo:notification.userInfo];
} else {
NSInteger badgeNumber = [LocalNotificationManager shareLocalNotification].badgeNum;
badgeNumber = badgeNumber > 0 ? --badgeNumber : 0;
[LocalNotificationManager shareLocalNotification].badgeNum = badgeNumber;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badgeNumber];
//ActivationModeBackground 的 action 不啟動(dòng) App 讓 App 在 background 下響應(yīng)
NSLog(@"%s -- %@ -- identifier %@ --- thread %@", __func__, notification, identifier, [NSThread currentThread]);
// //下面代碼用于測(cè)試溉浙,退出 App 后接收到 本地通知時(shí)烫止,點(diǎn)擊后臺(tái)action時(shí)是否執(zhí)行了這個(gè)響應(yīng)方法。實(shí)測(cè)執(zhí)行了的
// [[NSUserDefaults standardUserDefaults] setObject:@"ActivationModeBackground 的 action 不啟動(dòng) App 讓 App 在 background 下響應(yīng)" forKey:@"IGNOREKEY"];
// [[NSUserDefaults standardUserDefaults] synchronize];
}
completionHandler(); //根據(jù)Action btn 的 identifier 處理自定義事件后應(yīng)該馬上調(diào)用 completionHandler block,如果調(diào)用 completionHandler block 失敗的話戳稽,App 會(huì)立即 terminated烈拒。
}
@end
// 抽取的通知管理單例
LocalNotificationManager.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^LocalNotificationManagerBlock)(NSString * userInfoString);
@interface LocalNotificationManager : NSObject
// 消息的數(shù)量
@property (nonatomic, assign, readwrite) NSInteger badgeNum;
@property (nonatomic, copy) LocalNotificationManagerBlock managerBlock;
+ (instancetype)shareLocalNotification;
/**
檢查本地通知的授權(quán)
*/
- (void)checkNotificationAuthorization;
/**
添加本地通知
@param dataString 通知的內(nèi)容: 字典序列化后的字符串
*/
- (void)addLocalNotificationWithData: (NSString *)dataString;
/**
移除指定的通知
@param identifierStr 通知的唯一標(biāo)識(shí) 或 信息
*/
- (void)removeNotificationWithIdentifier: (NSString *)identifierStr;
/**
移除所有的通知
*/
- (void)removeAllNotification;
/**
收到通知后的回調(diào)
@param block block回調(diào)
*/
- (void)handleLocalNotificationWithBlock: (LocalNotificationManagerBlock)block;
/**
收到通知后的數(shù)據(jù)處理
@param userInfo 通知攜帶的數(shù)據(jù)
*/
- (void)receiveLocalNotificationWithUserInfo: (NSDictionary *)userInfo;
@end
NS_ASSUME_NONNULL_END
LocalNotificationManager.m
#import "LocalNotificationManager.h"
#import <UserNotifications/UserNotifications.h>
#import <UIKit/UIKit.h>
static NSString * const kNotificationScheduleType = @"kNotificationScheduleType";
static NSString * const kUNCategoryIdentifier = @"kUNCategoryIdentifier";
static NSString * const kCategoryActionIdentifierOpen = @"kCategoryActionIdentifierOpen";
static NSString * const kCategoryActionIdentifierCancel = @"kCategoryActionIdentifierCancel";
@interface LocalNotificationManager()<UNUserNotificationCenterDelegate>
@end
@implementation LocalNotificationManager
+ (instancetype)shareLocalNotification {
static LocalNotificationManager * _instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[LocalNotificationManager alloc] init];
});
return _instance;
}
- (void)checkNotificationAuthorization {
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
// 這兩個(gè)必須要寫(xiě)在上面 每次程序重新打開(kāi)時(shí)都得設(shè)置一遍...
center.delegate = self;
[center setNotificationCategories:[self createNotificationCategoryActionsForNewVersion]];
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) { // 判斷是否是未選擇授權(quán)狀態(tài)
[center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
}
}];
} else {
UIUserNotificationCategory * category = [self adduserNotificationCategory];
UIUserNotificationSettings * setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:[NSSet setWithObject:category]];
[[UIApplication sharedApplication] registerUserNotificationSettings:setting];
}
}
- (void)addLocalNotificationWithData: (NSString *)dataString {
NSData * data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSTimeInterval noticInterval = [self diffNowDateWithNotificationTime:dict[@"startTime"]];
if (noticInterval <= 0) {
return;
}
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
NSLog(@"用戶未授權(quán)");
return;
}
UNMutableNotificationContent * content = [[UNMutableNotificationContent alloc] init];
self.badgeNum++;
content.badge = @(self.badgeNum);
content.title = dict[@"title"];
content.body = dict[@"memo"];
content.userInfo = @{@"type" : kNotificationScheduleType, @"data": dict};;
// 這個(gè)必須要加 且要和 UNNotificationCategory 的Identifier 保持一致
content.categoryIdentifier = kUNCategoryIdentifier;
UNTimeIntervalNotificationTrigger * trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5.f repeats:NO];
UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier:dict[@"businessId"] content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"添加本地通知報(bào)錯(cuò): %@", error);
}
}];
}];
} else {
if ([[UIApplication sharedApplication] currentUserNotificationSettings].types == UIUserNotificationTypeNone) {
NSLog(@"用戶未授權(quán)");
return;
}
UILocalNotification * notification = [[UILocalNotification alloc] init];
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.f];
notification.alertTitle = dict[@"title"];
notification.alertBody = dict[@"memo"];
self.badgeNum++;
notification.applicationIconBadgeNumber = self.badgeNum;
notification.soundName = UILocalNotificationDefaultSoundName;
notification.alertAction = @"查看";
notification.userInfo = @{@"type" : kNotificationScheduleType, @"data": dict};;
notification.category = kUNCategoryIdentifier; // 與下面創(chuàng)建的category 的identifier必須保持一致
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
//添加category: iOS 10.0以后
-(NSSet *)createNotificationCategoryActionsForNewVersion{
//注冊(cè)本地通知用到的Action
//進(jìn)入app按鈕
UNNotificationAction * localAction = [UNNotificationAction actionWithIdentifier:kCategoryActionIdentifierOpen title:@"查看通知" options:UNNotificationActionOptionForeground];
//取消按鈕
UNNotificationAction *localCancel = [UNNotificationAction actionWithIdentifier:kCategoryActionIdentifierCancel title:@"忽略" options:UNNotificationActionOptionDestructive];
//將這些action帶入category
UNNotificationCategory *localCategory = [UNNotificationCategory categoryWithIdentifier:kUNCategoryIdentifier actions:@[localAction,localCancel] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];
return [NSSet setWithObjects:localCategory,nil];
}
//添加category: iOS 8.0以后
- (UIMutableUserNotificationCategory *)adduserNotificationCategory {
//UIMutableUserNotificationAction用來(lái)添加自定義按鈕
UIMutableUserNotificationAction * responseAction = [[UIMutableUserNotificationAction alloc] init];
responseAction.identifier = kCategoryActionIdentifierOpen;
responseAction.title = @"查看通知";
responseAction.activationMode = UIUserNotificationActivationModeForeground; //點(diǎn)擊的時(shí)候啟動(dòng)程序
responseAction.authenticationRequired = YES;//需要解鎖權(quán)限
UIMutableUserNotificationAction *deleteAction = [[UIMutableUserNotificationAction alloc] init];
deleteAction.identifier = kCategoryActionIdentifierCancel;
deleteAction.title = @"忽略";
deleteAction.activationMode = UIUserNotificationActivationModeBackground; //點(diǎn)擊的時(shí)候不啟動(dòng)程序,后臺(tái)處理
deleteAction.destructive = YES; //YES為紅色广鳍,NO為藍(lán)色
UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
category.identifier = kUNCategoryIdentifier;//用于將該 category 標(biāo)識(shí)的同時(shí),那一個(gè) notification 實(shí)例需要使用這個(gè) category 的 actions 也是傳入這個(gè)值給 notification 的吓妆。
//UIUserNotificationActionContextDefault:默認(rèn)添加可以添加兩個(gè)自定義按鈕
//UIUserNotificationActionContextMinimal:四個(gè)自定義按鈕
[category setActions:@[responseAction, deleteAction] forContext:UIUserNotificationActionContextDefault];
return category;
}
#pragma mark -- UNUserNotificationCenterDelegate
// App在前臺(tái)獲取通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0)){
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
}
// 點(diǎn)擊通知進(jìn)入App
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(ios(10.0)){
completionHandler();
NSDictionary * userInfo = response.notification.request.content.userInfo;
if(userInfo[@"type"] && [userInfo[@"type"] isEqualToString:kNotificationScheduleType]) {
if([response.actionIdentifier isEqualToString:kCategoryActionIdentifierCancel] || [response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) {
self.badgeNum = self.badgeNum > 0 ? --self.badgeNum : 0;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:self.badgeNum];
} else {
[self receiveLocalNotificationWithUserInfo:userInfo[@"data"]];
}
}
}
#pragma mark -- 移除本地通知
- (void)removeNotificationWithIdentifier:(NSString *)identifierStr {
//獲取本地通知數(shù)組 (該數(shù)組會(huì)持有需要重復(fù) fired 的 已被 copy 的 notification 對(duì)象赊时,用于到達(dá)下次間隔時(shí)再 fire, 如果不需要重復(fù)的 notification,即 notification.repeatInterval = 0 的話行拢,該 notification fire 之后不會(huì)被 copy 保留到這個(gè)數(shù)組里)
//本地通知最多只能有64個(gè)祖秒,超過(guò)會(huì)被系統(tǒng)忽略
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[identifierStr]];
} else {
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
for (UILocalNotification * notification in notifications) {
NSString * businessId = notification.userInfo[@"businessId"];
if ([identifierStr isEqualToString:businessId]) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
}
//刪除指定通知
// [[UIApplication sharedApplication] cancelLocalNotification:notifications[0]];
//刪除所有通知
// [[UIApplication sharedApplication] cancelAllLocalNotifications];
/*
執(zhí)行取消本地通知的場(chǎng)景:
1. 已經(jīng)響應(yīng)過(guò)的本地通知,需要取消舟奠。
2. 已經(jīng)遞交到 application 的竭缝,但在 fire 之前 確定要取消的通知,需要取消沼瘫。如提醒任務(wù)的取消抬纸,或更改提醒時(shí)間(此時(shí)應(yīng)該是新的一個(gè)本地通知了)
*/
}
- (void)removeAllNotification {
self.badgeNum = 0;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests];
} else {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
}
#pragma mark -- 處理收到的通知
- (void)handleLocalNotificationWithBlock:(LocalNotificationManagerBlock)block {
NSDictionary * dict = [[NSUserDefaults standardUserDefaults] objectForKey:@"localNotificationKey"];
if (dict) {
[self receiveLocalNotificationWithUserInfo:dict];
}
self.managerBlock = block;
}
- (void)receiveLocalNotificationWithUserInfo:(NSDictionary *)userInfo {
if (!userInfo) {
[self showInfo:@"消息失敗"];
return;
}
self.badgeNum = self.badgeNum > 0 ? --self.badgeNum : 0;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:self.badgeNum];
NSData * data = [NSJSONSerialization dataWithJSONObject:userInfo options:NSJSONWritingPrettyPrinted error:nil];
NSString * string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self showInfo:string];
}
// 通知消息的顯示
- (void)showInfo:(NSString *)infoStr {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:infoStr preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:NULL]];
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
}
// 獲取當(dāng)前時(shí)間與指定時(shí)間之間的時(shí)間戳
- (CGFloat)diffNowDateWithNotificationTime: (NSString *)timeStr {
NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];
[formatter setTimeZone:timeZone];
NSDate * noticDate = [formatter dateFromString:timeStr];
NSTimeInterval noticInterval = [noticDate timeIntervalSince1970] * 1;
NSTimeInterval nowInterval = [[NSDate date] timeIntervalSince1970] * 1;
return noticInterval - nowInterval;
}
@end
添加通加的數(shù)據(jù)格式:
- (IBAction)addLocalNotification:(UIButton *)sender {
NSDictionary * dict = @{@"businessId": @"kLocalNotificationTest",@"title": @"本地通知測(cè)試",@"memo": @"通知發(fā)送成功", @"startTime": @"2019-10-28 10:10:10"};
NSDictionary * dict1 = @{@"businessId": @"kLocalNotificationTestOne",@"title": @"本地通知測(cè)試__One",@"memo": @"通知發(fā)送成功__One", @"startTime": @"2019-10-28 10:10:10"};
NSArray * arr = @[dict, dict1];
for (NSDictionary * dataDic in arr) {
NSData * data = [NSJSONSerialization dataWithJSONObject:dataDic options:NSJSONWritingPrettyPrinted error:nil];
NSString * string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[[LocalNotificationManager shareLocalNotification] addLocalNotificationWithData:string];
}
}