Flutter WebSocket 在 OpenHarmony 即时通讯场景中的实践与踩坑记录
本文分享了在OpenHarmony项目中使用Flutter WebSocket实现即时通讯功能的实践经验。作者最初采用简单连接方式,但在真机测试中遇到连接不稳定、后台断连、弱网重连失败等问题。通过优化方案包括:全局单例管理连接、增加心跳机制、实现断线自动重连、监听应用生命周期、优化消息流处理等,显著提升了稳定性。文章特别强调在OpenHarmony环境下,后台切换和网络变化更容易暴露问题,建议开发
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
Flutter WebSocket 在 OpenHarmony 即时通讯场景中的实践与踩坑记录
前言
最近在做 Flutter for OpenHarmony 项目时,接了一个即时通讯模块。
功能其实不复杂:
- 实时聊天
- 在线状态同步
- 消息推送
- 心跳保活
一开始我以为直接用 Flutter WebSocket 就能搞定。
结果真正跑到 OpenHarmony 真机上之后,还是遇到了不少问题。
包括:
- WebSocket 偶发断连
- 切后台后连接丢失
- 弱网环境重连失败
- 页面退出后连接没释放
- 多次进入页面重复创建连接
这些问题在 Android 上偶尔也有,但在鸿蒙设备上会更容易暴露。
后面花了不少时间重新整理 WebSocket 管理逻辑,稳定性才慢慢好起来。
这篇文章主要记录一下我这次在 OpenHarmony 项目里的 WebSocket 实践过程。
一、项目里的实际场景
当前项目主要有几个实时功能:
| 功能 | 说明 |
|---|---|
| 聊天消息 | 实时接收 |
| 在线状态 | 用户上线提醒 |
| 系统通知 | 后台推送 |
| 消息未读数 | 实时更新 |
HTTP 轮询肯定不太适合。
所以最后还是用了 WebSocket 长连接。
二、Flutter WebSocket 基础接入
我这里直接使用:
web_socket_channel
添加依赖
dependencies:
web_socket_channel: ^2.4.0
执行:
flutter pub get
三、基础连接代码
最开始我的代码其实很简单。
final channel = WebSocketChannel.connect(
Uri.parse("wss://test.com/ws"),
);
发送消息:
channel.sink.add("hello");
监听消息:
channel.stream.listen((event) {
print(event);
});
关闭连接:
channel.sink.close();
Demo 阶段没问题。
但真正进入业务后:
问题开始慢慢变多。
四、最先遇到的问题:重复连接
这个问题我一开始没注意。
问题现象
聊天页面:
每次进入:
都会重新创建 WebSocket。
initState() {
connectSocket();
}
结果:
多进出几次页面后:
服务端直接出现多个连接。
客户端也开始:
- 重复收到消息
- 消息顺序异常
- 内存占用升高
后来的解决方式
我后面把 WebSocket 单独抽成了全局管理类。
class SocketManager {
static final SocketManager _instance =
SocketManager._internal();
factory SocketManager() {
return _instance;
}
SocketManager._internal();
}
整个项目只维护一个连接。
问题稳定很多。
五、心跳机制一定要做
这个问题在 OpenHarmony 上特别明显。
问题
长时间不操作:
连接会被服务端断开。
但客户端:
有时候并不知道已经断了。
结果:
用户看起来在线。
实际已经收不到消息。
后来的方案
增加心跳。
Timer.periodic(
const Duration(seconds: 30),
(_) {
sendPing();
},
);
发送:
channel.sink.add(
jsonEncode({
"type": "ping"
}),
);
服务端返回 pong。
这样连接稳定很多。
六、断线重连是必须的
这个是实际项目里最重要的一部分。
我遇到的场景
比如:
- 用户切 WiFi
- 网络波动
- App 切后台
- 鸿蒙系统回收连接
WebSocket 都可能断掉。
后来的重连方案
监听:
onDone
和:
onError
channel.stream.listen(
onDone: () {
reconnect();
},
onError: (e) {
reconnect();
},
);
重连逻辑
void reconnect() async {
await Future.delayed(
const Duration(seconds: 3),
);
connect();
}
这个方案目前在 OpenHarmony 上稳定性还不错。
七、切后台导致连接断开的问题
这个是我在鸿蒙真机上最容易复现的问题。
问题现象
App 切后台几分钟后:
WebSocket 自动断开。
回到前台:
连接不会自动恢复。
后来的处理方式
监听页面生命周期。
class AppStateListener
with WidgetsBindingObserver {
}
监听:
didChangeAppLifecycleState
@override
void didChangeAppLifecycleState(
AppLifecycleState state) {
if (state ==
AppLifecycleState.resumed) {
reconnect();
}
}
这个优化之后:
后台恢复稳定很多。
八、消息流不要直接操作 UI
这个问题我刚开始踩得挺明显。
错误做法
收到消息:
直接:
setState(() {
msgList.add(data);
});
如果消息频率高:
页面会疯狂 rebuild。
在鸿蒙设备上:
聊天列表明显掉帧。
后来的优化
我改成:
- Provider
- StreamController
- ValueNotifier
统一管理消息流。
例如:
messageNotifier.value = newList;
局部刷新。
效果会稳定很多。
九、页面退出一定要释放监听
这个问题很多人容易忘。
问题
页面退出后:
stream.listen 还在。
结果:
- 重复监听
- 内存泄漏
- 多次收到消息
正确处理
late StreamSubscription subscription;
页面销毁:
@override
void dispose() {
subscription.cancel();
super.dispose();
}
这个在 OpenHarmony 长时间运行时挺关键。
十、弱网环境测试
这个我建议一定要做。
我测试的场景
- WiFi 切换
- 飞行模式
- 弱网
- 后台恢复
重点观察:
- 是否自动重连
- 消息是否丢失
- UI 是否卡顿
实际结果
优化前:
| 问题 | 表现 |
|---|---|
| 断线 | 高频 |
| 重连失败 | 偶发 |
| 消息重复 | 存在 |
| 页面卡顿 | 明显 |
优化后:
| 项目 | 效果 |
|---|---|
| 长连接稳定性 | 提升明显 |
| 后台恢复 | 基本正常 |
| 消息同步 | 稳定 |
| 页面流畅度 | 更好 |
目前项目里已经稳定运行了一段时间。
十一、我最终的 WebSocket 管理结构
后面我把整个连接逻辑统一封装成:
SocketManager
内部包括:
- connect
- reconnect
- send
- heartBeat
- close
业务层:
只负责收消息。
这样后面维护轻松很多。
十二、总结
这次做 Flutter WebSocket 在 OpenHarmony 下的适配,一个比较明显的感受是:
即时通讯真正难的其实不是“连上”。
而是:
- 断线处理
- 生命周期管理
- 弱网恢复
- 消息同步
- 长时间稳定性
尤其 OpenHarmony 真机环境下:
后台切换和网络变化会比模拟器更容易暴露问题。
我现在项目里的原则基本是:
- WebSocket 全局单例
- 必做心跳
- 必做重连
- 页面退出释放监听
- 生命周期统一管理
整体稳定性会好很多。
后面我还准备继续研究:
- MQTT 在 OpenHarmony 下的表现
- Flutter IM 架构优化
- WebSocket 消息队列
- 离线消息同步方案
希望这篇文章能给正在做 Flutter for OpenHarmony 开发的同学一点参考。
更多推荐
所有评论(0)