Skip to content

客户不在 APP 时的消息推送 ​

客户问完就退出 APP 了,客服十分钟后才回。要让他收到系统推送,需要你的服务端参与。

这件事为什么要你参与 ​

给 APP 发系统推送需要推送证书:iOS 的 APNs 证书、Android 各家厂商的推送通道。这些都在你手里,合从没有,也不应该有。

所以分工是:合从负责报信,你负责推送。客户离线期间客服发了新消息,合从把这条消息的信息发到你指定的地址,你的服务端查到这位客户的推送 token,用你自己的推送通道发出去。

和未读红点的分工 ​

推送要你的服务端参与,SDK 内置的未读消息与红点不用:客户回到 APP 时 SDK 查一次未读数,你把数字画在自己的客服入口上就行。

什么时候触达客户要你做什么
系统推送客户完全退出 APP 也能收到服务端接回调 + 用你自己的推送通道发
未读红点客户下次打开 APP 时看到在入口上画一个数字

两件事是互补的:红点管「客户回来了」,推送管「客户没回来」。这一页的推送链路要拉服务端同事一起做,先只接红点也成立 —— 客户重新打开 APP 就能看到有新回复,做法见未读消息与红点。

配置回调地址 ​

在工作台的 App 渠道详情页,左侧选择 离线消息通知,填写你的服务端接收地址。

密钥可以不填。填了之后合从会对报文签名,你的服务端可以据此确认这条请求确实来自合从,见下面的验真。

什么时候会收到 ​

三个条件同时成立时,合从发出一次请求:

  • 这位客户已经离开会话 —— 退出 APP、切到后台、或者关掉了客服页面
  • 发消息的是人工客服
  • 消息不是内部备注

机器人的回复、自动回复、场景消息都不会触发。客户还在 APP 里看着聊天页时也不会。

自己嵌容器的话,前后台联动必须接

客户切到后台时 SDK 会主动断开连接,合从据此在一秒内判定他已离开。这一步依赖 APP 的前后台事件。

用 SDK 提供的整页界面时,这件事已经内置。把聊天嵌进自己页面的话,你必须转发宿主的前后台回调,否则合从会一直认为客户在线,离线推送一条都不会发,工作台里这位客户的在线状态也会长亮。做法见把聊天嵌进自己的页面。

你会收到什么 ​

一个 POST 请求,Content-Type: application/json,报文结构:

json
{
  "event": "offline_message",
  "tenantId": "…",
  "channelId": "…",
  "dialogId": "…",
  "customerId": "…",
  "anonymousId": "…",
  "externalUserId": "…",
  "agentNickname": "小美",
  "message": {
    "id": "…",
    "contentType": "text",
    "text": "您的订单已经发出了",
    "createdAt": 1755500000000
  },
  "ts": 1755500000100
}
字段说明
anonymousId合从给这台设备的稳定标识,客户没登录时靠它认人
externalUserId你通过 identify 传的会员 ID,客户登录过才有值
agentNickname客服的对外昵称,可以直接写进推送文案
message.contentType消息类型,text 之外还有图片、视频、语音等
message.text文本内容,只给前 500 个字符。非文本消息这里是 null,按 contentType 出兜底文案(例如「[图片]」)
message.createdAt消息时间,毫秒时间戳

anonymousId 和 externalUserId 两个都会给,不是二选一。客户登录过的话两个同时有值。

怎么找到该推给谁 ​

你的服务端要能从报文里的身份找到设备的推送 token,分两种情况:

客户登录过:用 externalUserId,那就是你自己的会员 ID,直接查你的库。

客户没登录:只能用 anonymousId。这个值要提前存下来 —— 在 APP 里监听 onAnonymousIdChanged 回调,拿到值之后连同这台设备的推送 token 一起报给你的服务端:

kotlin
// Android
HecongChat.onAnonymousIdChanged = { anonymousId ->
    reportToMyServer(anonymousId, myPushToken)
}

不要用你自己生成的设备 ID 去对照

anonymousId 由合从维护,可能和你在配置里传的 deviceId 不同。以回调里给到的值为准。

验证请求确实来自合从 ​

配了密钥的话,请求头里会带一个签名:

X-Hecong-Signature: sha256=<十六进制签名>

签名是用你填的密钥对请求体原始字符串做 HMAC-SHA256。你的服务端用同样的方法算一遍,比对一致再处理。

用解析后的对象重新序列化再算签名会对不上,要用原始的请求体字节。

送达与失败 ​

只发一次,不重试。 手机推送本身不承诺百分之百送达,为报信建重试机制的收益有限。

你的服务端返回什么状态码都算送到了,包括 4xx。合从不消费响应内容。连续失败 5 次(超时、连不上、5xx)之后,这个渠道的报信会暂停 5 分钟再恢复,避免地址配错时持续空打。

所以你的服务端要做到:快速返回,把推送逻辑丢进自己的队列异步处理,不要在这个请求里同步等推送结果。

怎么自测 ​

工作台里没有测试发送按钮,验证要走一遍真实链路:

  1. 真机打开 APP,进客服页面发一条消息,让对话建立起来
  2. 把 APP 切到后台或直接杀掉进程
  3. 在工作台里用人工客服身份回一条消息
  4. 看你的服务端有没有收到回调

收不到的话,先对照什么时候会收到的三个条件,再看接入问题排查。

用机器人回复、或者客户还开着客服页面,都不会触发。

下一步 ​