一、 Flutter 中的 Websocket
Flutter 提供了 web_socket_channel
这个包来处理 WebSocket 消息监听和发送
使用 web_socket_channel
引入如下包即可:
import 'package:web_socket_channel/io.dart';
创建 WebScoketChannel 实例可以使用上面包提供的 IOWebSocketChannel.connect
连接到一个 websocket 服务
IOWebSocketChannel _channel = IOWebSocketChannel.connect("ws://echo.websocket.org");
connect()
方法接收 url 作为参数,除此之外还支持传入 protocal 和 header 等
factory IOWebSocketChannel.connect(url, {Iterable<String> protocols, Map<String, dynamic> headers, Duration pingInterval})
二、数据监听和数据发送
1、监听
监听 websocket 服务的消息基于 Stream.listen
方法
StreamSubscription<T> listen(void onData(T event), {Function onError, void onDone(), bool cancelOnError});
上面创建好的 _channel
可以监听服务端发送过来的 message
// 监听消息
_channel.stream.listen((message) {
print(message);
});
2、发送
websocket 本身就是双向通信的,如果要发送给服务端,借助的则是 WebSocketSink.add
的能力
void add(T data) {
_sink.add(data);
}
因此使用上面的 _channel
发送数据可以如下:
void _sendHandle() { if (_message.isNotEmpty) { _channel.sink.add(_message); } }
3、关闭链接
Widget 生命周期中,需要将 socketChannel 关闭,通过 WebSocketSink.close()
_channel.sink.close();
三、websocket 实践
- statefulWidget 通过一个 list 存储数据
- 连接 websocket ,这里使用
ws://echo.websocket.org
- 监听数据传入
- 通过 文本框 向 服务端推送数据
class WebSocketDemo extends StatefulWidget { WebSocketDemo({Key key}) : super(key: key); _WebSocketDemoState createState() => _WebSocketDemoState(); } class _WebSocketDemoState extends State<WebSocketDemo> { List _list = new List(); String _message; IOWebSocketChannel _channel = IOWebSocketChannel.connect("ws://echo.websocket.org"); void _onChangedHandle(value) { setState(() { _message = value.toString(); }); } _WebSocketDemoState() { print(_channel); } @override void initState() { super.initState(); setState(() { _list.add('[Info] Connected Successed!'); }); // 监听消息 _channel.stream.listen((message) { print(message); setState(() { _list.add('[Received] ${message.toString()}'); }); }); } void _sendHandle() { if (_message.isNotEmpty) { _list.add('[Sended] $_message'); _channel.sink.add(_message); } } Widget _generatorForm() { return Column( children: <Widget>[ TextField(onChanged: _onChangedHandle), SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ RaisedButton( child: Text('Send'), onPressed: _sendHandle, ) ], ) ], ); } List<Widget> _generatorList() { List<Widget> tmpList = _list.map((item) => ListItem(msg: item)).toList(); List<Widget> prefix = [_generatorForm()]; prefix.addAll(tmpList); return prefix; } @override Widget build(BuildContext context) { return ListView( padding: EdgeInsets.all(10), children: _generatorList(), ); } @override void dispose() { super.dispose(); _channel.sink.close(); } } class ListItem extends StatelessWidget { final String msg; ListItem({Key key, this.msg}) : super(key: key); @override Widget build(BuildContext context) { return Text(msg); } }