SerendipityEx

关注成长,记录生活

iOS:关于iOS的推送

苹果的在iOS 10 中将通知相关的API统一成了UserNotifications.framework。在新的UserNotifications.framework中,苹果还增加了撤回单条通知,更新已展示同比,中途修改通知内容,在通知中展示图片、视频,自定义通知UI等一系列新功能。

iOS 10中使用远程推送

Project -> Project Setting - > Capabilities, 打开 Push Notifications 开关。

注册通知

注册通知在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0); 方法里。

iOS 10使用- (void)requestAuthorizationWithOptions:(UNAuthorizationOptions)options completionHandler:(void (^)(BOOL granted, NSError *__nullable error))completionHandler; 方法来注册通知。

导入 #import <UserNotifications/UserNotifications.h>

// 使用 UNUserNotificationCenter 来管理通知
UNUserNotificationCenter *uncenter = [UNUserNotificationCenter currentNotificationCenter];
// 监听回调事件
[uncenter setDelegate:self];
[uncenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert+UNAuthorizationOptionBadge+UNAuthorizationOptionSound)
                        completionHandler:^(BOOL granted, NSError * _Nullable error) {
                            [[UIApplication sharedApplication] registerForRemoteNotifications];
                            NSLog(@"%@" , granted ? @"授权成功" : @"授权失败");
                        }];
// 获取当前的通知授权状态, UNNotificationSettings
[uncenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
    NSLog(@"%s\nline:%@\n-----\n%@\n\n", __func__, @(__LINE__), settings);
    if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
        NSLog(@"未选择");
    } else if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
        NSLog(@"未授权");
    } else if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
        NSLog(@"已授权");
    }
}];

上面的方法只在ios 10中有效, 所以要想兼容之前的版本,还是需要适配

- (void)registerForRemoteNotification {
    // iOS10 兼容
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
        // 使用 UNUserNotificationCenter 来管理通知
        UNUserNotificationCenter *uncenter = [UNUserNotificationCenter currentNotificationCenter];
        // 监听回调事件
        [uncenter setDelegate:self];
        [uncenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert+UNAuthorizationOptionBadge+UNAuthorizationOptionSound)
                                completionHandler:^(BOOL granted, NSError * _Nullable error) {
                                    [[UIApplication sharedApplication] registerForRemoteNotifications];
                                    NSLog(@"%@" , granted ? @"授权成功" : @"授权失败");
                                }];
        // 获取当前的通知授权状态, UNNotificationSettings
        [uncenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            NSLog(@"%s\nline:%@\n-----\n%@\n\n", __func__, @(__LINE__), settings);
            if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
                NSLog(@"未选择");
            } else if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
                NSLog(@"未授权");
            } else if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
                NSLog(@"已授权");
            }
        }];
    }
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
        UIUserNotificationType types = UIUserNotificationTypeAlert |
        UIUserNotificationTypeBadge |
        UIUserNotificationTypeSound;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else {
        UIRemoteNotificationType types = UIRemoteNotificationTypeBadge |
        UIRemoteNotificationTypeAlert |
        UIRemoteNotificationTypeSound;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
    }
#pragma clang diagnostic pop
}

注册结果的回调还是AppDelegate的代理方法。

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
    NSString *dt = [token stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    NSString *dn = [dt stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    TheRuntime.pushToken = [dn stringByReplacingOccurrencesOfString:@" " withString:@""];
    DDLog(@"deviceToken____: %@",TheRuntime.pushToken);
}

//查看推送功能是否失败
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSString *error_str = [NSString stringWithFormat: @"%@", error];
    DDLog(@"Token Error: %@",error_str);
}

响应通知

iOS 10 之前版本

iOS 10之前的版本中,当应用是被通知打开的时候,可以通过 application:didFinishLaunchingWithOptions:方法的 launchOptions 参数所使用的 dictionary 访问到数据:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    . . .
    if ([[UIDevice currentDevice].systemVersion floatValue] < 10.0) {
        NSDictionary *notificationPayload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
		if (notificationPayload) {
			NSLog(@"%@",notificationPayload);
		} 
    }
    return YES;
}

如果当通知到达的时候,你的应用已经在运行,通过 application:didReceiveRemoteNotification:fetchCompletionHandler: 方法的 userInfo 参数所使用 dictionary 访问到数据:

 //  Required for iOS 7+
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    //处理远程推送内容
    NSLog(@"iOS7及以上系统,收到通知:%@", userInfo);
}

iOS10 以上需要使用下面代理方法来获得 userInfo

//  在前台收到推送内容, 执行的方法
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    NSDictionary *userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        //TODO:处理远程推送内容
        NSLog(@"%@", userInfo);
    }
    // 需要执行这个方法,选择是否提醒用户,有 Badge、Sound、Alert 三种类型可以选择设置
    completionHandler(UNNotificationPresentationOptionAlert);
}

// 在后台和启动之前收到推送内容, 点击推送内容后,执行的方法
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)())completionHandler {
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        //TODO:处理远程推送内容
        NSLog(@"%@", userInfo);
    }
    completionHandler();
}

最后附上2篇参考文章:

活久见的重构 - iOS 10 UserNotifications 框架解析

Developing Push Notifications for iOS 10