iOS開發通知權限

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];
    }
}

參考文檔:
本地推送

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章