如何理解即时通讯业务中的实时消息、本地通知和远程推送(Android)?

客户端弹出通知栏通知时并不一定都是远程推送。本文描述了 IM 连接状态、应用程序存活状态、本地通知、远程推送(Push)之间的关系。

SDK 与融云服务器的 IM 连接状态

为了区分实时消息和远程推送,我们需要先理解 IM 连接的几种状态:

  • 连接成功:应用程序调用 SDK 的连接方法后,SDK 与融云服务器建立一个长连接,用于消息的发送与接收,称之为 IM 连接通道。SDK 通过通过 IM 连接通道接收消息后会触发消息监听中的方法。

  • 无连接:如果 IM 连接通道 断开,则即时通讯实时消息无法通过 IM 长连接到达用户设备。此时如有新消息,应用程序仅能依赖推送服务(第三方厂商推送服务)通知用户设备。

    以下情况会导致 IM 连接通道断开:

    • 应用程序的主进程被杀死或者回收。
    • 应用程序主动调用 SDK 的方法(disconnect)断开 IM 连接。
    • 未调用连接方法,或未正常建立 IM 连接。
    • 当前登录用户被封禁。
    • 当前用户的 Token 过期或被作废
    • 当前用户在其他设备登录,导致在当前设备上被踢下线(具体受当前 App Key 的多设备登录限制影响)

应用程序的状态

为了理解实时消息、本地通知和远程推送的作用范围,我们需要先区分 Android 应用程序的几种状态,分别是前台状态,后台活动状态和杀死状态。

  1. 前台状态:应用程序在前台运行(假设 SDK 已经与融云服务器正常建立 IM 连接),用户此时正在使用应用程序。
  2. 后台活跃状态:应用程序进入到后台后最多活跃 2 分钟,此时 IM 连接仍然存在,应用程序可以通过 IM 连接通过接收实时消息。如果应用程序集成了 IMKit SDK,收到新消息后 IMKit 会负责在通知栏弹出通知,这种通知称为“本地通知”。如果应用程序集成了 IMLib SDK,收到新消息后会触发 IMLib 的消息监听方法(注意,IMLib 未实现该场景下的本地通知能力,应用程序可以在回调方法创建 Notification 并自行弹出本地通知)。
  3. 杀死状态:应用程序在后台超过 2 分钟后进入到暂停状态,SDK 会在此时主动断开 IM 连接,此时应用程序失去了与融云服务器的 IM 连接。在 IM 连接通道 断开的情况下,如果有人给该用户发消息,必须依赖应用程序集成的远程推送服务(华为推送、小米推送、oppo 推送、FCM 推送等)通知用户设备。第三方厂商的推送通知可直接通过 Android 系统在通知栏显示,不依赖 IMLib/IMKit 的实现。

:tipping_hand_man: 在测试推送集成时必须注意,部分模拟器和真机清理后台应用后,只是清理了 UI 界面,但应用时机并未被杀死,导致 IM 连接通道未断开,此时收到消息不会走推送通道的。

在后两种状态下,如果程序重新回到前台并建立 IM 连接,SDK 可从融云服务端收取消息。

即时通讯实时消息

无论应用程序在前台或者后台,如果是由 IM 连接通知接收的消息,SDK 一定会触发消息监听的回调方法。

以 IMKit SDK 的消息监听方法为例:

public boolean onReceived(Message message, int left, boolean hasPackage, boolean offline)

本地通知

本地通知指应用在前台或后台活跃运行时,由 IMKit 或应用客户端直接调用系统接口创建并发送的通知。IMKit SDK 内部已经实现了本地通知功能,当应用处于后台接收到新消息时,IMKit 默认会在通知面板弹出通知提醒,即本地通知。

参考 IMKit 5. X 开发者文档:本地通知

远程推送

应用程序集成第三方厂商推送服务后,在 IM 连接通道断开的情况下,可由厂商推送通道下发收到新消息的通知。

参考开发者文档: 推送 2.0 集成指南

附录:SDK 的通知流程分发图:

通过上图可以了解, 只有接收方的主进程被杀死或者回收,或者应用程序主动调用 disconnect() 操作, 导致 IM 长连接通道与服务器断开后,融云服务端才会通过推送通道下发收到新消息的通知。