Android端无法直连Redis Pub/Sub,因系统限制后台长连接且无可靠重连机制;必须通过支持WebSocket的中间服务中转,该服务需校验权限、动态映射频道并转发消息。

Android 端不能直接订阅 Redis,因为 Redis 的 PUBSUB 是长连接、阻塞式协议,而 Android 原生不支持在主线程外稳定维持这种连接,且无法绕过系统对后台 Socket 的限制(尤其 Android 9.0+)。必须通过中间服务中转,否则要么连不上,要么被系统杀掉。
为什么不能在 Android 上直连 Redis Pub/Sub
Redis 的 SUBSCRIBE 命令要求客户端保持 TCP 连接并持续读取响应流,但 Android 在后台时会冻结或终止非前台进程的网络 I/O;JobIntentService 或 WorkManager 不支持长连接回调;AlarmManager 精确闹钟在 Android 9.0+ 被禁用,无法靠轮询模拟监听。实测中,直接用 Jedis 或 Lettuce 在 Android 上调用 pubsub().subscribe() 后,切后台 2 分钟内连接基本断开,且无可靠重连机制。
中间服务必须暴露 WebSocket 接口
Android 客户端只和中间服务通信,中间服务负责:连接 Redis、监听频道、将消息转成轻量帧(如 JSON)并通过 WebSocket 下推。关键点是:
- 中间服务(如 Spring Boot)用
RedisMessageListenerContainer监听频道,避免自己手写PubSubConnection状态管理 - WebSocket 连接需带心跳(ping/pong),防止 NAT 超时断连;Android 端用
OkHttp的WebSocketListener实现,不要用Socket原生封装 - 消息体建议加字段
"channel"和"payload",便于客户端做路由分发,而不是把 Redis 的原始message对象原样透传
Android 端 WebSocket 连接要处理三类断连场景
中间服务只是转发层,不解决终端网络抖动问题。Android 端必须自行处理:
- WebSocket 连接建立失败 → 回退到指数退避重试(初始 1s,上限 30s),不要无限重连
- 连接中途断开(
onFailure或onClosing)→ 清空本地订阅状态缓存,重发JOIN控制帧给中间服务 - 收到中间服务发来的
{"type":"reconnect_required"}→ 主动关闭当前连接,触发重连流程
注意:别把 Redis 频道名硬编码进 Android APK,应由中间服务统一分配并返回订阅 Token,避免客户端伪造频道名导致消息污染。
中间服务需支持动态频道映射与权限校验
真实业务中,用户只能收自己权限范围内的频道消息。中间服务不能简单把所有 Redis 频道全量透传,而应:
- WebSocket 握手阶段验证 JWT 或 session token,提取用户 ID 和角色
- 查 DB 或缓存,拿到该用户允许订阅的频道白名单(如
user:1001:notify、team:205:status) - 在
RedisMessageListenerContainer中按需注册监听器,而非全局psubscribe __keyevent@0__:* - 收到 Redis 消息后,先比对频道是否在白名单内,再转发给对应 WebSocket 连接
这个环节最容易被跳过,结果就是测试环境 OK,上线后一个用户能收到其他用户的消息。


















