场景
即时通讯中需要对离线消息进行接收,此时就需要离线推送即当应用没有退出登录的情况下,被系统或者用户杀掉进程仍然能收到IMSDK消息提醒。云通讯iOS客户端采用的是APNs推送服务,以下提供整个处理流程及参考代码。
处理流程
1.申请APNs证书可参考文档:Apple 推送证书申请
2.上传证书到腾讯云控制台
注意:上传证书名最好使用全英文(尤其不能使用括号等特殊字符)。
上传证书生效时间为 10 分钟左右。
上传证书需要设置密码,无密码收不到推送。
注意生产环境的选择,发布 AppStore 的证书需要设置为生产环境,否则无法收到推送。
上传的 p12 证书必须是自己申请的真实有效的证书。
3.客户端实现APNs推送
客户端实现步骤
1. 向苹果后台请求DeviceToken
//在IM登录之后注册通知
- (void)registNotification
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
}
}
2. 上传Token到腾讯云
//在通知的回调中上传的token
-(void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
DebugLog(@"didRegisterForRemoteNotificationsWithDeviceToken:%ld", (unsigned long)deviceToken.length);
NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
[[TIMManager sharedInstance] log:TIM_LOG_INFO tag:@"SetToken" msg:[NSString svtringWithFormat:@"My Token is :%@", token]];
TIMTokenParam *param = [[TIMTokenParam alloc] init];
//注意区分证书环境
#if kAppStoreVersion
// AppStore版本
#if DEBUG
param.busiId = 2383;
#else
param.busiId = 2382;
#endif
#else
//企业证书id
param.busiId = 4496;
#endif
[param setToken:deviceToken];
//调用IM API 上传Token到腾讯云
[[TIMManager sharedInstance] setToken:param succ:^{
NSLog(@"-----> 上传token成功 ");
} fail:^(int code, NSString *msg) {
NSLog(@"-----> 上传token失败 ");
}];
}
3. App进入后台时上报切后台事件
//App进入后台 上报事件
- (void)applicationDidEnterBackground:(UIApplication *)application {
__block UIBackgroundTaskIdentifier bgTaskID;
bgTaskID = [application beginBackgroundTaskWithExpirationHandler:^ {
//不管有没有完成,结束 background_task 任务
[application endBackgroundTask: bgTaskID];
bgTaskID = UIBackgroundTaskInvalid;
}];
//获取未读计数
int unReadCount = 0;
NSArray *convs = [[TIMManager sharedInstance] getConversationList];
for (TIMConversation *conv in convs) {
if([conv getType] == TIM_SYSTEM){
continue;
}
unReadCount += [conv getUnReadMessageNum];
}
[UIApplication sharedApplication].applicationIconBadgeNumber = unReadCount;
//doBackground
TIMBackgroundParam *param = [[TIMBackgroundParam alloc] init];
[param setC2cUnread:unReadCount];
[[TIMManager sharedInstance] doBackground:param succ:^() {
NSLog(@"doBackgroud Succ");
} fail:^(int code, NSString * err) {
NSLog(@"Fail: %d->%@", code, err);
}];
}
4. App进入前台时上报切前台事件
//App进入前台
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[TIMManager sharedInstance] doForeground:^() {
NSLog(@"doForegroud Succ");
} fail:^(int code, NSString * err) {
NSLog(@"Fail: %d->%@", code, err);
}];
}
5. 离线消息处理
// 处理推送消息
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
DebugLog(@"userinfo:%@",userInfo);
DebugLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
//当APP在前台运行时,不做处理
if( [UIApplication sharedApplication].applicationState == UIApplicationStateActive){
}else if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive) {
//当APP在后台运行时,当有通知栏消息时,点击它,就会执行下面的方法跳转到相应的页面
if ([[TIMManager sharedInstance] getLoginStatus])
{
for (NSString *tfStr in userInfo)
{
if ([tfStr isEqualToString:@"careline"])
{
//跳转到对应的页面
}
}
}
}
}
推送机制
上图可以分为三个阶段:
- 应用程序的服务器端把要发送的消息、目的iPhone的标识打包,发给APNS。
- APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。
- iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。
问题排查
- 确认是否正确上传证书到腾讯云控制台。
- 确认在登录成功后,是否成功上报token到腾讯云了,注意开发环境与发布环境的token不一样,删除app重新装也会导致token的变化。建议每次登录后都获取token。
- 确认是否正确上报了切前后台事件,应用进入后台上报applicationDidEnterBackground事件,进入前台上报applicationDidBecomeActive事件。
- 确认TIMCustomElem消息中的desc属性是否是空的,如果desc为空消息将发送不出。
- MsgRandom 等去重标记设为一样,导致被去重无法推送。
- 对于群消息,确认群消息接收选项是否为接收群消息提醒。
//设置群接收选项
[[TIMGroupManager sharedInstance] ModifyReciveMessageOpt:@"TGID1JYSZEAEQ" opt:TIM_GROUP_RECEIVE_MESSAGE succ:^() {
NSLog(@"modify receive group message option succ");
}fail:^(int code, NSString* err) {
NSLog(@"failed code: %d %@", code, err);
}];
7.对于更换证书的情况下新证书得在上传一个小时后生效
8.以上排查不出问题可提供sdkappid、证书id、发送接收双方的账号给技术人员排查
参考文档: