Flutter中优先用dart:io的WebSocket类,轻量可控;需心跳、重连或后台保活时再选插件;注意连接验证、平台配置、二进制处理及存活检测机制。

Flutter 里用 WebSocket,别急着装插件——先看 dart:io 能不能直接搞定。 大多数移动端实时通信场景(比如聊天、状态同步、通知推送),原生 WebSocket 类已足够稳定且无额外依赖。插件(如 flutter_socket 或 web_socket_channel)只在需要心跳管理、自动重连、多平台兼容封装时才真正必要。
用 dart:io 建立基础连接,几行代码就跑起来
这是最轻量、最可控的方式,适合调试和对连接生命周期有明确控制的场景。
-
WebSocket.connect()返回一个Future<websocket></websocket>,必须 await 或用.then()拿到实例,不能直接调用.add() - 连接地址必须是
ws://或wss://,HTTP 地址会抛出Unsupported scheme错误 - Android 真机需确认
android:usesCleartextTraffic="true"(开发阶段)或服务端启用 HTTPS + WSS(上线前) - 监听消息必须用
.listen(),不是回调函数;onDone和onError必须显式传入,否则断连后流不会自动终止
示例:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
final webSocketFuture = WebSocket.connect('wss://echo.websocket.org');
webSocketFuture.then((ws) {
_webSocket = ws;
_webSocket.listen(
(data) => print('收到: $data'),
onDone: () => print('连接关闭'),
onError: (e) => print('错误: $e'),
);
_webSocket.add('hello');
});
web_socket_channel 适合状态驱动 UI 和 StreamBuilder 场景
当你用 StreamBuilder 构建消息列表、想把连接/断开/重连逻辑统一收口,或者需要复用 channel 实例时,这个包更自然。
-
IOWebSocketChannel.connect()立即返回 channel,channel.stream是可监听的Stream<dynamic></dynamic>,channel.sink用于发送 - 它不自动处理重连,但方便你包装成
StreamProvider或配合Riverpod管理状态 - 注意:channel 关闭后,
channel.stream会 emitdone,但 sink 不再可用;重复调用connect()会创建新 channel,旧的不会自动销毁 - 若服务端返回二进制帧(如 protobuf),
data是Uint8List,需手动解码;文本帧才是String
自定义插件如 flutter_socket 的真实价值在后台保活与心跳
纯 dart:io 连接在 Android 后台会被系统休眠杀掉,iOS 切后台后约 30 秒断连——这时插件封装的 service 和前台通知才起作用。
-
FlutterWebSocketUtil.connect()内部启用了 AndroidForegroundService,所以你会看到通知栏常驻提示 -
util.openHeart()默认 30 秒发一次空消息,防 NAT 超时,但服务端必须响应,否则单向心跳无效 - 断开回调
onClose中的SocketConnectCloseModel.code是服务端返回的 close code(如 1000 正常关闭,4001 认证失败),不是 HTTP 状态码 - 不要在
onMessage里做耗时解析(如大 JSON 解析、本地 DB 写入),建议用compute()或 isolate 隔离
真正容易被忽略的是:**连接是否“活着”,不等于 WebSocket.readyState == WebSocket.OPEN。** 网络抖动时 readyState 可能仍为 OPEN,但 send 已无响应。生产环境必须结合心跳超时 + 服务端 ACK + 客户端重连计数器,三者缺一不可。

















