无 UI 集成方案

服务端 API

有奖征文|投稿上云技术实践,赢取价值5000元大奖> HOT

概述

即时通信 IM 的终端用户需要随时都能够得知最新的消息,而由于移动端设备的性能与电量有限,当 App 处于后台时,为了避免维持长连接而导致的过多资源消耗,即时通信 IM 推荐您使用 Apple 提供的系统级推送通道(APNs)来进行消息通知,APNs 相比第三方推送拥有更稳定的系统级长连接,可以做到随时接受推送消息,且资源消耗大幅降低。

注意:

  • 在没有主动退出登录的情况下,应用退后台、手机锁屏、或者应用进程被用户主动杀掉三种场景下,如果想继续接收到 IM 消息提醒,可以接入即时通信 IM 离线推送。
  • 如果应用主动调用 logout 退出登录,或者多端登录被踢下线,即使接入了 IM 离线推送,也收不到离线推送消息。

集成 TUIOfflinePush 跑通离线推送功能

集成 TUIOfflinePush 组件之前,需要先向 Apple 申请 APNs 推送证书,然后 上传推送证书到 IM 控制台 。之后按照如下步骤操作即可快速接入 IM 离线推送。

  1. 集成 TUIOfflinePush 组件
  2. 配置推送参数
  3. 点击离线推送后自定义跳转
说明:

如果您想尽可能简单地接入 TUIOfflinePush 组件,您需要使用 TUICore 组件中的 TUILogin 提供的 login/logout 接口登录/登出,此时 TUIOfflinePush 组件会自动感知登录/登出事件。如果您不想使用 TUILogin 提供的接口,可参见 TUIOfflinePush 的 高级用法-自定义登录/登出

步骤1:集成 TUIOfflinePush 组件

  1. TUIOfflinePush 组件支持 cocoapods 集成,您需要在 Podfile 中添加组件依赖。

    # 防止 TUI 组件里的 *.xcassets 与您项目里面冲突。
    install! 'cocoapods', :disable_input_output_paths => true  
    
    # TUI 组件依赖了静态库,需要屏蔽如下设置,如果报错,请参见常见问题说明。
    # use_frameworks!
    
    # 集成离线推送组件
    pod 'TUIOfflinePush'

  2. 执行以下命令,安装 TUIOfflinePush 组件。

    pod install
    如果无法安装 TUIKit 最新版本,执行以下命令更新本地的 CocoaPods 仓库列表。
     pod repo update

步骤2:配置推送参数

  1. 当您 上传证书到 IM 控制台 后,IM 控制台会为您分配一个证书 ID ,见下图。
  1. 您需要在 AppDelegate 中,调用宏 TUIOfflinePushCertificateIDForAPNS 设置下证书 ID 即可。
    @implementation AppDelegate
    
    #ifdef DEBUG
    // 配置开发环境证书
    TUIOfflinePushCertificateIDForAPNS(31287)
    #else
    // 配置生产环境证书
    TUIOfflinePushCertificateIDForAPNS(31288)
    #endif
    
    @end
说明:

TUIOfflinePushCertificateIDForAPNS 是组件内置的宏定义,您只需要在 AppDelegate@implementation 中的任意位置中调用即可。

步骤3:点击离线推送后自定义跳转

  1. 点击通知栏的离线推送后,TUIOfflinePush 组件已支持推送内容的解析。
  2. 如果要实现跳转到聊天列表,您只需要在 AppDelegate 中实现 -navigateToTUIChatViewController:groupID: 跳转方法即可。
说明:

  • TUIOfflinePush 组件默认已经从离线推送中解析出当前推送的 userID 和 groupID。
  • 如果 groupID 不为空,说明当前点击的是群聊离线消息。
  • 如果 groupID 为空且 userID 不为空,说明当前点击的是单聊离线消息。
  • 您需要在 AppDelegate 的 @implementation 中实现 - navigateToTUIChatViewController:groupID: 方法。

以下是示例代码,当点击离线推送后先获取当前的会话页面,然后通过会话页面 push 到聊天页面。您可以按需实现自己的跳转逻辑。

// 统一点击跳转
// 您可以直接拷贝当前的方法名到您的 AppDelegate 中
- (void)navigateToTUIChatViewController:(NSString *)userID groupID:(NSString *)groupID
{
  // 示例: 点击推送通知后,首先跳转到会话列表页面,然后再会话列表页跳转到聊天页面
  // 1. 获取当前 app 的 tabBarController
  // 2. 获取 tabBarController 的 firstObject,也即 ConversationController
  // 3. 执行 pushToViewController: 跳转到 ChatViewController
  // 跳转到聊天页面后,支持点击左上角的返回按钮回退到主页面

    UITabBarController *tab = [self getMainController];
    if (![tab isKindOfClass: UITabBarController.class]) {
        // 正在登录中
        return;
    }
    if (tab.selectedIndex != 0) {
        [tab setSelectedIndex:0];
    }
    self.window.rootViewController = tab;
    UINavigationController *nav = (UINavigationController *)tab.selectedViewController;
    if (![nav isKindOfClass:UINavigationController.class]) {
        return;
    }

    UIViewController *vc = nav.viewControllers.firstObject;
    if (![vc isKindOfClass:NSClassFromString(@"ConversationController")]) {
        return;
    }
    if ([vc respondsToSelector:NSSelectorFromString(@"pushToChatViewController:userID:")]) {
        [vc performSelector:NSSelectorFromString(@"pushToChatViewController:userID:") withObject:groupID withObject:userID];
    }
}

高级用法

1. 自定义登录/登出

TUIOfflinePush 默认使用了 TUICore 组件中的 TUILogin 提供的 login/logout 接口。如果您想自己实现 App/IM 的登录,不依赖 TUILogin,您需要在完成登录/登出操作后,手动调用 registerServiceunregisterService 接口。

说明:

如果您使用了 TUILogin 的登录/登出,无需再调用上述两个接口。

// 您登录完成后的回调
- (void)onLoginSuccess
{
    // 调用 TUIOfflinePush 组件的登录
    [TUIOfflinePushManager.shareManager registerService];
}

// 您登出成功后的回调
- (void)onLogoutSuccess
{
    // 调用 TUIOfflinePush 的登出
    [TUIOfflinePushManager.shareManager unregisterService];
}

2. 自定义离线内容解析

TUIOfflinePush 默认参与解析了离线推送的内容,并通过 - navigateToTUIChatViewController:groupID: 接口回调给业务层自定义跳转。

如果您想自定义解析离线推送的内容,或者查看收到的离线推送,可以在您的 AppDelegate 中实现 - processTUIOfflinePushNotification: 方法。

说明:

关于方法的返回值

  • 如果返回 YES,那么组件将不再执行默认解析逻辑,完全交由业务层自行处理
  • 如果返回 NO,组件会继续执行默认解析逻辑,继续回调 - navigateToTUIChatViewController:groupID: 方法。

// 统一收到离线推送
- (BOOL)processTUIOfflinePushNotification:(NSDictionary *)userInfo
{
    // 自定义解析收到的 userInfo
    NSLog(@">>> 您可以在此处自定义解析, %@", userInfo);

    // 如果您不想执行 TUIOfflinePush 默认的解析逻辑,直接返回 YES
    // 如果您只是想查看推送的内容,依然依赖 TUIOfflinePush 的默认解析及统一跳转逻辑,直接返回 NO
    return NO;
}

常见问题

普通消息为什么收不到离线推送?

  • 首先,请检查下 App 的运行环境和证书的环境是否一致,如果不一致,收不到离线推送。
  • 其次,检查下 App 和证书的环境是否为生产环境。如果是开发环境,向苹果申请 deviceToken 可能会失败,生产环境暂时没有发现这个问题,请切换到生产环境测试。

自定义消息为什么收不到离线推送?

自定义消息的离线推送和普通消息不太一样,自定义消息的内容我们无法解析,不能确定推送的内容,所以默认不推送,如果您有推送需求,需要您在 sendMessage 的时候设置 offlinePushInfodesc字段,推送的时候会默认展示 desc 信息。

如何关闭离线推送消息的接收?

如果您想关闭离线推送消息的接收,可以通过设置 setAPNS 接口的 config 参数为 nil 来实现。该功能从5.6.1200 版本开始支持。

收不到推送,且后台报错 bad devicetoken。

Apple 的 deviceToken 与当前编译环境有关。如果 登录 IMSDK 后上传 deviceToken 到腾讯云 所使用的证书 ID 和 token 不一致,就会报错。

  • 如果使用的是 Release 环境编译,则 - application:didRegisterForRemoteNotificationsWithDeviceToken: 回调返回的是发布环境的 token,此时 businessID 需要设置生产环境的 证书 ID
  • 如果使用的是 Debug 环境编译,则- application:didRegisterForRemoteNotificationsWithDeviceToken: 回调返回的是开发环境的 token,此时 businessID 需要设置开发环境的 证书 ID
    V2TIMAPNSConfig *confg = [[V2TIMAPNSConfig alloc] init];
    /* 用户自己到苹果注册开发者证书,在开发者帐号中下载并生成证书(p12 文件),将生成的 p12 文件传到腾讯证书管理控制台,控制台会自动生成一个证书 ID,将证书 ID 传入以下 busiId 参数中。*/
    //推送证书 ID
    confg.businessID = sdkBusiId;
    confg.token = self.deviceToken;
    [[V2TIMManager sharedInstance] setAPNS:confg succ:^{
         NSLog(@"%s, succ, %@", __func__, supportTPNS ? @"TPNS": @"APNS");
    } fail:^(int code, NSString *msg) {
         NSLog(@"%s, fail, %d, %@", __func__, code, msg);
    }];

iOS 开发环境下,注册偶现不返回 deviceToken 或提示 APNs 请求 token 失败?

此问题现象是由于 APNs 服务不稳定导致的,可尝试通过以下方式解决:

  1. 给手机插入 SIM 卡后使用4G网络测试。
  2. 卸载重装、重启 App、关机重启后测试。
  3. 打生产环境的包测试。
  4. 更换其它 iOS 系统的手机测试。

交流与反馈

欢迎加入 QQ 群进行技术交流和反馈问题。

目录