iOS-Onesignal推送实现详解

目录
  • 证书准备工作
  • APP 处理推送
    • 配置文件
    • 向系统申请通知权限
    • 注册deviceToken
    • 推送处理流程(分三种情况处理)
  • 总结(之前遇到的坑)
序言

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

一 证书准备工作
1.1 CSR 文件

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

image.png
image.png

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

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

1.2 生成带有Push Notifications功能的AppID

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

image.png

这部分是为这个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.png

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

image.png
image.png

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

image.png

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

image.png
image.png

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

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

二 APP 处理推送

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

调用流程

  • 1 应用启动
  • 2 注册配置
  • 3 注册推送
  • 4 注册deviceToken
  • 5 收到推送进行处理
2.1 APP开启远程推送
image.png
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.png
  • 判断当前用户是否开启通知权限
#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.png

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

2.4 推送处理流程

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

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

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

此时程序启动,会响应

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    // 冷启动推送回调
    [AlertUtils message:[userInfo JSONString] duration:5];
}

效果如下


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

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

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    [AlertUtils message:SS(@"程序已启动,运行在后台\n%@", [userInfo JSONString]) duration:10];
}

效果如下:

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

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

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    [AlertUtils message:SS(@"程序已启动,运行在前台\n%@", [userInfo JSONString])];
}

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

image.png

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

image.png

思考:既然当 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.png
image.png

本文为原创,如有转载,请注明原处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260