iOS 10以後,蘋果統一使用 UNUserNotifications
,以前的API都被標爲棄用了。(如application:didReceiveRemoteNotification:
)
註冊通知
使用UNUserNotificationCenter
需要引用頭文件
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif
檢查是否有push推送權限
// 檢查是否有push推送權限
- (void)checkCurrentNotificationStatus{
if (@available(iOS 10 , *)){
[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined){
// 未選擇
}else if (settings.authorizationStatus == UNAuthorizationStatusDenied){
// 沒權限
}else if (settings.authorizationStatus == UNAuthorizationStatusAuthorized){
// 已授權
[self requestNotification];
}
}];
}
else if (@available(iOS 8 , *))
{
UIUserNotificationSettings * setting = [[UIApplication sharedApplication] currentUserNotificationSettings];
if (setting.types == UIUserNotificationTypeNone) {
// 沒權限
}else{
// 已授權
[self requestNotification];
}
}
else{
UIRemoteNotificationType type = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (type == UIUserNotificationTypeNone)
{
// 沒權限
}
}
}
消息權限彈窗
//消息權限彈窗
- (void)showUserNotificationAlert {
//彈窗提示,是否開通通知權限
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"您需要開啓系統通知權限,纔可以正常接收消息,請到設置->通知中開啓【XXX】消息通知。" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"去設置" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSURL * url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
dispatch_async(dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
}
});
}]];
[self presentViewController:alert animated:YES completion:nil];
}
註冊消息通知
注意:iOS10以後的api
UNUserNotificationCenter
在request調用後就立馬回調deviceToken的代理方法,不會等待點擊結果,需要注意運行時序的問題,所以項目里加了一個通知方法,點擊後再上傳deviceToken
//註冊消息通知
-(void)requestNotification
{
//ios 10的實現方法出現彈窗的時候就會回調didRegisterForRemoteNotificationsWithDeviceToken,不去等待異步結果
if (@available(iOS 10, *))
{
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
// 允許推送
NSLog(@"註冊通知成功");
//點擊確認後再次上傳deviceToken
[[NSNotificationCenter defaultCenter] postNotificationName:@"requestNotificationSuccess" object:nil];
}else{
//不允許
}
}];
}
//ios 8的實現方法只有點擊了同意或不同意按鈕纔回調didRegisterForRemoteNotificationsWithDeviceToken,等待結果後纔回調
else if(@available(iOS 8 , *))
{
UIApplication * application = [UIApplication sharedApplication];
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
}
else
{
UIApplication * application = [UIApplication sharedApplication];
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
}
// 註冊獲得device Token
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
}
系統通知的回調方法
deviceToken(在註冊成功後進行回調,每次啓動都要註冊一次registerForRemoteNotifications)
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
//deviceToken
}
接收通知方法
/*
1.已棄用。iOS 3.0–10.0的版本,消息到達時被回調
2.只有在程序處於運行狀態(前臺or後臺)調用,但是你強制殺死程序之後,來了遠程推送,系統不會自動進入你的程序,這個時候application:didReceiveRemoteNotification:就不會被調用。
3.如果實現了application: didReceiveRemoteNotification: fetchCompletionHandler:則該方法不會被調用(如果沒有實現就會調用這個,屬於系統的兜底邏輯)
*/
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(@"%@",userInfo[@"url"]);
}
/*
1.當程序launch完畢之後,就會調用(>iOS7版本)
2.應用在前後臺,kill掉的狀態在收到推送都會觸發該方法(應用kill時,用戶點擊push後,appFinishLaunch中會帶着push消息,同時這個接口也會被調用)
3.即收到消息就會觸發,所以要判斷前後臺狀態
4.在ios10後如果設置代理UNUserNotificationCenterDelegate,並實現了willPresentNotification,應用在前臺時該方法會變爲只有點擊時候才觸發,收到推送的時候會觸發willPresentNotification方法來控制顯示效果,如果還實現了代理的點擊方法didReceiveNotificationResponse,那麼該方法不會觸發。
*/
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(@"%@",userInfo[@"url"]);
}
//本地推送觸發方法
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
NSLog(@"%@",notification.userInfo[@"url"]);
}
iOS10後新的api
代理方法
<UNUserNotificationCenterDelegate>
設置代理
注意:這個代理只能在application裏設置 (這也是爲什麼有一些app設置了
[UNUserNotificationCenter currentNotificationCenter].delegate
代理沒有觸發代理方法的原因)
// The delegate can only be set from an application
// 官方解釋,這個代理只能在application裏設置
// iOS10後通知前臺顯示需要設置該代理
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
設置代理後通知的顯示方法
如果沒有實現這個回調,無論接收到通知和點擊通知都會觸發
application:didReceiveRemoteNotification:fetchCompletionHandler:
方法,但實現了willPresentNotification
方法後,didReceiveRemoteNotification
只負責點擊事件,在前臺接收到PUSH後由willPresentNotification
處理
#pragma mark UNUserNotificationCenterDelegate代理方法
//當應用在前臺時,收到通知會觸發這個代理方法
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
// 前臺顯示,需要執行這個方法,選擇是否提醒用戶,有Badge、Sound、Alert三種類型可以設置, 不設置alert當APP在前臺時就沒有提示
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
點擊推送消息後回調
如果實現了這個回調,則ios10以後的機型上不會觸發
application:didReceiveRemoteNotification:fetchCompletionHandler:
方法,只會觸發下面代理方法,如果沒設置代理代碼,則去觸發didReceiveRemoteNotification方法
//點擊推送消息後回調
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{
NSLog(@"Userinfo %@",response.notification.request.content.userInfo);
}
本地PUSH
- (void)localNotification{
if (@available(iOS 10.0, *)) {
NSString *requestID = @"123hhhh";
//第一步:獲取推送通知中心
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert|UNAuthorizationOptionSound|UNAuthorizationOptionBadge)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
NSLog(@"succeeded!");
}
}];
center.delegate = self;
//第二步:設置推送內容
UNMutableNotificationContent *content = [UNMutableNotificationContent new];
content.title = @"推送中心標題";
content.subtitle = @"副標題";
content.body = @"這是UNUserNotificationCenter信息中心";
content.badge = @20;
content.categoryIdentifier = @"categoryIdentifier";
UNNotificationAction *action = [UNNotificationAction actionWithIdentifier:@"enterApp"
title:@"進入應用"
options:UNNotificationActionOptionForeground];
UNNotificationAction *clearAction = [UNNotificationAction actionWithIdentifier:@"destructive"
title:@"忽略2"
options:UNNotificationActionOptionDestructive];
UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:@"categoryIdentifier"
actions:@[action,clearAction]
intentIdentifiers:@[requestID]
options:UNNotificationCategoryOptionNone];
[center setNotificationCategories:[NSSet setWithObject:category]];
//第三步:設置推送方式
UNTimeIntervalNotificationTrigger *timeTrigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:60 repeats:YES];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestID content:content trigger:timeTrigger];
//第四步:添加推送request
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
}];
//移除推送
[center removePendingNotificationRequestsWithIdentifiers:@[requestID]];
[center removeAllDeliveredNotifications];
}
}
參考文檔:
本地推送