APP开发平台 > Blog > iOS-Onesignal推送实现详解

Onesignal 的实现也是基于APNS实现的,Onesignal 集成了多种类型的推送,包括Mobile PushWeb PushIn-AppEmail等,并且同时支持 iOS 和 Android,是一款非常方便的第三方推送平台。

一 证书准备工作
1.1 CSR 文件

首先我们要通过证书助手生成一个Certificate Signing Request(也就是CSR)的请求文件。

image

image

继续之后选择保存位置,点击保存
这时该位置上会有一个CertificateSigningRequest.certSigningRequest的请求文件,也就是我们说的CSR文件。

注意:在选择从证书颁发机构请求证书时,钥匙串中最好选择所有项目,要不然创建出来的CSR证书可能会无效。

1.2 生成带有Push Notifications功能的AppID

1.2.1 创建好 AppID 后,给该AppID的Push Notifications配置CSR:

image

这部分是为这个APP ID配置push notifications,一个SSL Certificate可以让你手机上的notification server连接到Apple Push Notification Service(APNS)
可以看到配置部分有两个:

  • Development SSL Certificate:开发推送证书配置,开发环境可以收到推送。

  • Production SSL Certificate:推送证书配置,线上环境可以收到推送。

1.2.2 点击Create Certificate,然后上传1.1步骤生成的CSR文件即可

image

1.2.3 下载推送证书,加到自己电脑上的钥匙串里

image

image

1.2.4 双击证书,会自动添加到钥匙串中去

image

找到自己的APP(后面的名字为当时设定的bundleID),右键导出p12文件,填上密码,保存。

image

image

生成的这个p12文件,通常是给推送平台配置(自己的推送平台,或第三方推送平台,友盟等),以便他们能够发送推送通知到APNS。

这样,证书配置方面的事情就做完了。

二 APP 处理推送

iOS处理生命周期和推送都在AppDelegate里面,AppDelegate继承自UIResponder,遵守UIApplicationDelegate协议,其中跟推送相关的方法都在UIApplicationDelegate协议中。包含本地推送和远程推送。

调用流程

  • 1 应用启动

  • 2 注册配置

  • 3 注册推送

  • 4 注册deviceToken

  • 5 收到推送进行处理

2.1 APP开启远程推送

image

2.2 向系统申请通知权限
  • AppDelegate.m

#import <UserNotifications/UserNotifications.h>- (void)requirePushPermission {
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
        UIUserNotificationType allNotificationTypes =
        (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
        UIUserNotificationSettings *settings =
        [UIUserNotificationSettings settingsForTypes:allNotificationTypes
                                          categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications]; //注册获得device Token
    } else {
        // iOS 10 or later
        if (@available(iOS 10.0, *)) {
            [UNUserNotificationCenter currentNotificationCenter].delegate = self;
            UNAuthorizationOptions authOptions =
            UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
            [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions
                                                                                completionHandler:^(BOOL granted, NSError *_Nullable error){
                                                                                }];
            [[UIApplication sharedApplication] registerForRemoteNotifications]; //注册获得device Token
        }
    }}

image

  • 判断当前用户是否开启通知权限

  • #import <UserNotifications/UserNotifications.h>//检查是否APP当前是否打开了推送通知+ (bool)isEnablePush {

    UIUserNotificationSettings *setting = [[UIApplication sharedApplication] currentUserNotificationSettings];
    if (UIUserNotificationTypeNone == setting.types) {
        return NO;
    }
    return YES;}
2.3 注册deviceToken

系统会在下面的回调方法中将deviceToken回调给我们

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {

  // deviceToken}

运行结果

image

我们可以在这个方法里面将deviceToken发送给自己或者第三方推送的后台

2.4 推送处理流程

处理推送必须是通过点击通知进入,收到通知,点应用进入不会触发通知处理的方法。

我们一共分为三种情况,以下分别做解释处理

2.4.1 程序未启动,收到通知,系统展示通知栏,点击进入

此时程序启动,会响应

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {

    // 冷启动推送回调
    [AlertUtils message:[userInfo JSONString] duration:5];}

效果如下


2.4.2 程序已启动,在后台,收到通知,系统展示通知栏,点击进入

此时程序已经启动,运行在后台,会响应

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {

    [AlertUtils message:SS(@"程序已启动,运行在后台\n%@", [userInfo JSONString]) duration:10];}

效果如下:

image

2.4.3 程序已启动,在前台,收到通知,系统不展示通知栏

此时程序已启动,运行在前台,会响应

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {

    [AlertUtils message:SS(@"程序已启动,运行在前台\n%@", [userInfo JSONString])];}

当通知来的时候,该方法会马上调用,效果如下:

image

当用户点击顶部推送消息时,该方法会再次调用,效果如下:

image

思考:既然当 APP 运行在前台时,该方法会调用两次,并且在用户点击推送消息时,我们不应该对推送消息做处理,如何区别是第一次来通知调用该方法还是用户点击推送消息回调该方法呢?

解决思路:当APP 在前台时,来推送消息时,先判断当前本地是否已经存在该推送消息,如果不存在,则不处理,将该推送消息转成字符串存储在本地。当用户点击推送,该方法会再次调用,这个时候再判断本地是否存在该推送消息,这个时候已经存在了,则处理该推送消息。

实例代码如下

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {

    [PushHandler handlePush:userInfo];}#pragma mark - dealwith push data/// 处理来自远程的推送内容+ (void)handlePush:(NSDictionary *)payLoad {
    if (payLoad == nil) {
        return;
    }

    NSDictionary *aps = [payLoad valueForKey:@"aps"];
    if (aps == nil) {
        return;
    }

    UIApplication *application = [UIApplication sharedApplication];

    // 当前 APP 在前台
    if (application.applicationState == UIApplicationStateActive) { //活动状态下使用消息提示再提示一下,让用户可以点击
        // 备注:这边比较特殊,当 APP 在前台时,当推送来的时候,会来到这个方法,当点击推送弹窗后,这个方法会再次调用,即这个方法会调用两次,走两次 push 操作.
        NSLog(@"payLoad=%@",payLoad);
        NSDictionary *pushContentJson = (NSDictionary *)[CTX.cacheHandler.fileStore objectForKey:kOneSignalPushContent];
        if (NullDict(pushContentJson)) {  // 存储该推送消息
            [CTX.cacheHandler.fileStore setObject:payLoad forKey:kOneSignalPushContent];
        } else {
            NSString *savePushContentJsonStr = [pushContentJson JSONString];
            NSString *curPushContentJsonStr = [payLoad JSONString];
            if ([savePushContentJsonStr isEq:curPushContentJsonStr]) {  // 两次内容一样的时候才执行
                [self handlePushAction:payLoad];  // 处理推送消息
            } else {
                [CTX.cacheHandler.fileStore setObject:payLoad forKey:kOneSignalPushContent];
            }
        }
    } else {
        [self handlePushAction:payLoad];  // 处理推送消息
    }}

总结(之前遇到的坑)

  • 1.不管 APP 处于哪一种状态,当推送消息来的时候,方法application:didReceiveRemoteNotification:fetchCompletionHandler:都会调用。

  • 2.当 APP 在前台时,方法application:didReceiveRemoteNotification:fetchCompletionHandler:会调用两次,这个时候要区分是第一次来推送消息还是用户点击了推送消息。

  • 3.在选择从证书颁发机构请求证书时,钥匙串中最好选择所有项目,要不然创建出来的CSR证书可能会无效。

  • 4.iOS开发无法导出p12证书的问题解决办法 - 把证书拖到登录里就行了

image


https://documentation.onesignal.com/docs/ios-push-opt-in-prompt
转载自简书:iOS-Onesignal推送实现详解


2022-05-24 来源:APICloud

Onesignal iOS-Onesignal

An efficient app outsourcing platform that guarantees timely delivery!

Submit Requirements