Flutter WebSocket通信插件ya_websocket的使用
Flutter WebSocket通信插件ya_websocket的使用
ya_websocket
一个使用 iOS 和 Android 上原生库进行 WebSocket 通信的 Flutter 插件。
由于使用 Flutter 的 WebSocket 库尝试连接某台 IoT 设备通信时,总是无法连接,所以单独做了一个 WebSocket 库,它基于各系统中已经成熟的库进行通信。
感谢这些好用的库
平 台 | Flutter 插件语言 | 原生端使用的库 | 库版本 | 库使用的语言 |
---|---|---|---|---|
iOS | Kotlin | Java-WebSocket | 1.5.2 | Java |
Android | Swift | Starscream | 4.0.4 | Swift |
系统版本要求
平 台 | 可运行最低版本 | 推荐最低版本 |
---|---|---|
Dart | 2.12.0 | 2.13.4 |
Flutter | 2 | 2.2.3 |
iOS | 10 | 14 |
Android | 4.1 | 11 |
在使用本插件前,请先将 APP 的适用版本设置为「可运行最低版本」之上。
引入
如果您准备使用 release 发布版本:
- 在项目目录中,运行
flutter pub add ya_websocket
。 - 运行后,您项目中
pubspec.yaml
中的dependencies:
节会自动添加一行代码(并自动运行dart pub get
):
ya_websocket: ^1.0.0 # 使用的版本号,你也可以修改它
如果您准备使用 main 主线版本,请添加:
- 编辑您项目中的文件
pubspec.yaml
,在dependencies:
节添加以下代码:
ya_websocket:
git:
url: git://github.com/kagurazakayashi/yaWebSocket.git
ref: main
- 保存后,在项目目录中运行
flutter pub get
。
使用
- 导入包:
import 'package:ya_websocket/ya_websocket.dart';
- 在需要的类中实现接口
class ... implements YaWebsocketDelegate
,实现以下接口:
已连接时
void yaWebsocketDelegateOnOpen(String httpStatus, String httpStatusMessage, String? tag);
参数:
httpStatus
: HTTP 状态码httpStatusMessage
: 状态描述文本tag
: 自定义标记
开始尝试连接时
void yaWebsocketDelegateOnConnecting(String? tag);
参数:
tag
: 自定义标记
收到信息时
void yaWebsocketDelegateOnMessage(String message, String? tag);
参数:
message
: 信息内容tag
: 自定义标记
连接关闭时 (Android 和 iOS 返回信息可能有区别)
void yaWebsocketDelegateOnClose(String code, String reason, String remote, String? tag);
参数:
code
: 状态代码reason
: 描述文本remote
: 是否由远程关闭tag
: 自定义标记
连接发生错误时 (Android 和 iOS 返回信息可能有区别)
void yaWebsocketDelegateOnError(String localizedMessage, String? message, String? tag);
参数:
localizedMessage
: 本地化描述文本message
: 描述文本tag
: 自定义标记
通常情况下的状态代码( code
)
-1
表示操作失败/不正常0
表示正常/正常地处于关闭状态1
表示正常/正常地处于开启状态
- 创建对象:
YaWebsocket websocket = YaWebsocket();
- 指定接口实现类:
_websocket.delegate = this;
- 开始连接:
websocket.connect(uri, tag: tag);
参数:
uri
: Websocket 的连接地址,以ws://
开头。tag
: 可选标签,可以输入任意字符串,库调用接口返回时,会带上它。
返回值(字符串字典):
status
:0
: 现在开始连接,请等待接口收到yaWebsocketDelegateOnOpen
或yaWebsocketDelegateOnClose
调用后再进行下一步。-1
: 未能开始连接
info
: (可选)如果未能开始连接,可能提供此错误信息描述
- 检查是否连接
websocket.isOpen();
返回值(字符串字典):
status
:1
: 已连接0
: 未连接-1
: 未能查询
info
: (可选)如果未能查询,可能提供此错误信息描述
- 发送数据:
websocket.send(text);
参数:
text
: 要发送的字符串
返回值(字符串字典):
status
:0
: 已发送-1
: 未发送
info
: (可选)如果未能发送,可能提供此错误信息描述
- 断开连接:
websocket.close();
返回值(字符串字典):
status
:0
: 关闭成功或已经处于关闭状态,关闭成功接口将收到yaWebsocketDelegateOnClose
调用。-1
: 遇到问题
info
: (可选)如果遇到问题,可能提供此错误信息描述
注意事项
- 执行
websocket.*
时会立即有返回值,该返回值通常只表示是否成功开始执行。真正的运行结果状态回调在YaWebsocketDelegate
。 - 正在进行操作时(如正在连接、正在断开链接时)不要进行操作,尤其是重复的连接和断开操作,请等到收到状态回调后再进行下一步操作。
- 连接关闭的回调
yaWebsocketDelegateOnClose
会在每次连接关闭时触发,而错误回调yaWebsocketDelegateOnError
仅在识别到错误时触发。如果因错误断开,yaWebsocketDelegateOnError
和yaWebsocketDelegateOnClose
都会触发。因此建议在yaWebsocketDelegateOnClose
中判断连接关闭。
示例程序
DEMO 演示了 连接、发送、接收、断开、重新连接 的过程。
- 在输入框中输入
ws://
地址进行连接。 - 然后输入内容并发送,屏幕上会以聊天式气泡显示接收和发送的信息。
- 点按右上角连接图标可以连接和断开,请在当前连接或断开操作完成或超时后再按。
<iOS 示例程序> | <Android 示例程序>
更多
许可
示例代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:ya_websocket/ya_websocket.dart';
import 'package:bubble/bubble.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> implements YaWebsocketDelegate {
String _webSocketURI = ''; // ws://192.168.1.46:8866/chat?user_id=1
String _webSocketTAG = '0';
late TextEditingController _textFController;
List _data = [];
bool _isConnect = false;
late YaWebsocket _websocket;
String _title = "点按屏幕下方橙色区域输入";
ScrollController _scrollController = ScrollController();
[@override](/user/override)
void initState() {
initPlatformState().whenComplete(() {});
_textFController = TextEditingController(text: '');
_websocket = YaWebsocket();
_websocket.delegate = this;
if (_webSocketURI.length > 0) {
connect(_webSocketURI, _webSocketTAG);
} else {
setState(() {
_textFController.text = "ws://";
_data.add([false, "请输入连接地址,以 ws:// 开头。"]);
});
}
super.initState();
}
[@override](/user/override)
void dispose() {
_textFController.dispose();
_websocket.close();
super.dispose();
}
Future<void> initPlatformState() async {
// String platformVersion;
// try {
// platformVersion =
// await websocket.platformVersion ?? 'Unknown platform version';
// } on PlatformException {
// platformVersion = 'Failed to get platform version.';
// }
// if (!mounted) return;
// setState(() {
// _platformVersion = platformVersion;
// // child: Text('Running on: $_platformVersion\n'),
// });
}
Future<bool> send(String text) async {
bool isOK = true;
Map? info = await _websocket.send(text);
if (info!["status"] == "-1") {
setState(() {
_data.add(
[false, "发送失败 " + (info.containsKey("info") ? info["info"] : "")]);
});
isOK = false;
}
return isOK;
}
Future<bool> close() async {
bool isOK = true;
setState(() {
_data.add([false, "正在断开..."]);
});
Map? info = await _websocket.close();
if (info!["status"] == "-1") {
setState(() {
_data.add([
false,
"断开时出现异常 " + (info.containsKey("info") ? info["info"] : "")
]);
});
isOK = false;
}
return isOK;
}
Future<bool> reconnect() async {
bool isOK = true;
setState(() {
_data.add([false, "正在尝试连接到上次的地址..."]);
});
Map? info = await _websocket.reconnect();
if (info!["status"] == "-1") {
setState(() {
_data.add(
[false, "未能连接 " + (info.containsKey("info") ? info["info"] : "")]);
});
isOK = false;
}
return isOK;
}
Future<bool> connect(String toURI, String toTAG) async {
bool isOK = true;
setState(() {
_title = toURI;
_data.add([false, "现在开始尝试连接 $toURI ..."]);
});
Map? info = await _websocket.connect(toURI, tag: toTAG);
if (info!["status"] == "-1") {
setState(() {
_data.add(
[false, "未能连接 " + (info.containsKey("info") ? info["info"] : "")]);
});
isOK = false;
}
return isOK;
}
[@override](/user/override)
yaWebsocketDelegateOnClose(
String code, String reason, String remote, String? tag) {
setState(() {
_isConnect = false;
_data.add([
false,
"连接已被关闭( $remote , $code ) $reason ,请输入新的连接地址或按右上角按钮重新连接到上次的服务器。"
]);
});
}
[@override](/user/override)
yaWebsocketDelegateOnError(
String localizedMessage, String? message, String? tag) {
setState(() {
_data.add([false, "发生错误: $localizedMessage ."]);
});
}
[@override](/user/override)
yaWebsocketDelegateOnMessage(String message, String? tag) {
setState(() {
_data.add([false, message]);
});
}
[@override](/user/override)
yaWebsocketDelegateOnOpen(
String httpStatus, String httpStatusMessage, String? tag) {
setState(() {
_isConnect = true;
_data
.add([false, "连接已建立( $httpStatus ): $httpStatusMessage 。请输入要发送的消息。"]);
});
}
[@override](/user/override)
yaWebsocketDelegateOnConnecting(String? tag) {
setState(() {
_data.add([false, "正在连接 $tag ($_webSocketURI) ,请不要进行其他操作。"]);
});
}
[@override](/user/override)
Widget build(BuildContext context) {
if (_data.length > 0 &&
_scrollController.hasClients &&
_scrollController.position.maxScrollExtent > _scrollController.offset) {
Timer(
Duration(milliseconds: 500),
() => _scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 200),
curve: Curves.ease,
),
);
}
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(_title),
actions: [
IconButton(
onPressed: () async {
if (await _websocket.isOpen) {
close();
} else {
reconnect();
}
},
icon: Icon(
_isConnect ? Icons.link_off : Icons.link,
),
),
],
),
body: Column(
children: [
Expanded(
child: ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(16.0),
itemCount: _data.length, //data.length*2-1,
itemBuilder: (context, i) {
return Container(
child: InkWell(
onLongPress: () {
_textFController.text = _data[i][1].toString();
},
child: Bubble(
margin: BubbleEdges.only(top: 10),
alignment: _data[i][0]
? Alignment.centerRight
: Alignment.centerLeft,
nip: _data[i][0]
? BubbleNip.rightBottom
: BubbleNip.leftBottom,
color: _data[i][0]
? Color.fromRGBO(225, 255, 199, 1.0)
: Color.fromRGBO(212, 234, 244, 1.0),
child: Text(
_data[i][1],
textAlign:
_data[i][0] ? TextAlign.right : TextAlign.left,
),
),
),
);
},
),
),
Container(
height: 50,
color: Colors.deepOrange,
child: Row(
children: [
Expanded(
child: TextField(
controller: _textFController,
onSubmitted: (value) {
setState(() {
_data.add([true, value]);
});
if (value.length >= 5 && value.substring(0, 5) == "ws://") {
connect(value, _webSocketTAG);
} else {
send(value);
}
_textFController.text = "";
},
),
),
IconButton(
onPressed: () {
_textFController.text = '';
},
icon: Icon(Icons.clear, color: Colors.white),
),
IconButton(
onPressed: () {
String value = _textFController.text;
setState(() {
_data.add([true, value]);
});
if (value.length >= 5 && value.substring(0, 5) == "ws://") {
connect(value, _webSocketTAG);
} else {
send(value);
}
_textFController.text = "";
},
icon: Icon(
Icons.send,
color: Colors.white,
),
),
],
),
),
],
),
),
);
}
}
更多关于Flutter WebSocket通信插件ya_websocket的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter WebSocket通信插件ya_websocket的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用ya_websocket
插件进行WebSocket通信的代码示例。这个示例将展示如何建立WebSocket连接、发送消息以及接收消息。
首先,确保你已经在pubspec.yaml
文件中添加了ya_websocket
依赖:
dependencies:
flutter:
sdk: flutter
ya_websocket: ^x.y.z # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,我们编写Flutter代码来实现WebSocket通信。
main.dart
import 'package:flutter/material.dart';
import 'package:ya_websocket/ya_websocket.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'WebSocket Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: WebSocketPage(),
);
}
}
class WebSocketPage extends StatefulWidget {
@override
_WebSocketPageState createState() => _WebSocketPageState();
}
class _WebSocketPageState extends State<WebSocketPage> {
WebSocketClient? _webSocketClient;
TextEditingController _messageController = TextEditingController();
List<String> _messages = [];
@override
void initState() {
super.initState();
initWebSocket();
}
void initWebSocket() {
String url = 'wss://your-websocket-server-url'; // 替换为你的WebSocket服务器URL
_webSocketClient = WebSocketClient(url);
_webSocketClient!.onMessage!.listen((WebSocketMessage message) {
setState(() {
_messages.add('Received: ${message.data}');
});
});
_webSocketClient!.onOpen!.listen((_) {
setState(() {
_messages.add('WebSocket connected.');
});
});
_webSocketClient!.onClose!.listen((_) {
setState(() {
_messages.add('WebSocket disconnected.');
});
});
_webSocketClient!.onError!.listen((error) {
setState(() {
_messages.add('Error: $error');
});
});
_webSocketClient!.connect();
}
void sendMessage() {
if (_webSocketClient!.readyState == WebSocketReadyState.OPEN) {
String message = _messageController.text;
_webSocketClient!.send(message);
setState(() {
_messages.add('Sent: $message');
_messageController.clear();
});
} else {
setState(() {
_messages.add('WebSocket is not open.');
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebSocket Demo'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _messages.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_messages[index]),
);
},
),
),
TextField(
controller: _messageController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Message',
),
onSubmitted: (String value) {
sendMessage();
},
),
ElevatedButton(
onPressed: sendMessage,
child: Text('Send'),
),
],
),
),
);
}
@override
void dispose() {
_webSocketClient?.close();
_messageController.dispose();
super.dispose();
}
}
解释
-
依赖导入:
- 导入
ya_websocket
包和其他必要的Flutter包。
- 导入
-
主应用:
MyApp
是根组件,它定义了应用的主题和主页。
-
WebSocket页面:
WebSocketPage
是一个有状态的组件,它管理WebSocket连接和消息。
-
初始化WebSocket:
- 在
initState
方法中,创建WebSocketClient
实例,并设置消息、打开、关闭和错误事件的监听器。 - 调用
connect
方法启动WebSocket连接。
- 在
-
发送消息:
sendMessage
方法检查WebSocket是否打开,如果打开则发送消息,并更新消息列表。
-
UI构建:
- 使用
ListView.builder
显示消息列表。 - 使用
TextField
和ElevatedButton
构建消息输入框和发送按钮。
- 使用
-
资源释放:
- 在
dispose
方法中关闭WebSocket连接并释放控制器。
- 在
请确保将wss://your-websocket-server-url
替换为你的实际WebSocket服务器URL。这个示例展示了如何使用ya_websocket
插件在Flutter中实现基本的WebSocket通信功能。