场景

即时通讯中需要对离线消息进行接收,此时就需要离线推送即当应用没有退出登录的情况下,被系统或者用户杀掉进程仍然能收到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"])
                {
                    //跳转到对应的页面
                    
                }
            }
        }
    }

}

推送机制

APNS推送机制

上图可以分为三个阶段:

  1. 应用程序的服务器端把要发送的消息、目的iPhone的标识打包,发给APNS。
  2. APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。
  3. iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。

问题排查

  1. 确认是否正确上传证书到腾讯云控制台。
  2. 确认在登录成功后,是否成功上报token到腾讯云了,注意开发环境与发布环境的token不一样,删除app重新装也会导致token的变化。建议每次登录后都获取token。
  3. 确认是否正确上报了切前后台事件,应用进入后台上报applicationDidEnterBackground事件,进入前台上报applicationDidBecomeActive事件。
  4. 确认TIMCustomElem消息中的desc属性是否是空的,如果desc为空消息将发送不出。
  5. MsgRandom 等去重标记设为一样,导致被去重无法推送。
  6. 对于群消息,确认群消息接收选项是否为接收群消息提醒。
//设置群接收选项
[[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、发送接收双方的账号给技术人员排查

参考文档:

  1. https://segmentfault.com/a/1190000012019282
  2. https://blog.csdn.net/csdn100861/article/details/51508885

文章来源于腾讯云开发者社区,点击查看原文