前言
实时通信对于现代移动应用而言是至关重要的一项功能。在Flutter中,我们可以利用MQTT(Message Queuing Telemetry Transport)协议实现高效、可靠的消息传递。本文将深入介绍如何使用Flutter,结合一个灵活的MQTT工具类,实现MQTT连接和消息传递的过程。
1.了解MQTT
MQTT是一种发布/订阅模式的通信协议,特别适用于物联网和需要快速、轻量级消息传递的场景。其工作原理基于客户端和服务器之间的消息交换,支持订阅主题、发布消息等功能。
二、导入依赖
在Flutter/pubspec.yaml中添加以下内容:
mqtt_client: ^8.0.0
//运行flutter pub
三、创建MQTT工具类
在Flutter中,我们可以创建一个用于处理MQTT连接和消息传递的工具类。以下是一个简化的实现:
class MqttTool {
MqttQos qos = MqttQos.atLeastOnce;
late MqttServerClient mqttClient;
static MqttTool? _instance;
// 记录客户端是否正在连接
bool isConnecting = false;
static MqttTool? getInstance() {
_instance ??= MqttTool();
return _instance;
}
Future<MqttClientConnectionStatus?> connect(String server, int port,
String clientIdentifier, String username, String password,
{bool isSsl = false}) {
mqttClient = MqttServerClient.withPort(server, clientIdentifier, port);
//设置心跳
mqttClient.keepAlivePeriod = 20;
// 设置自动重连和重连时间间隔
mqttClient.autoReconnect = true;
// 注册onAutoReconnect回调函数
mqttClient.onAutoReconnect = () {
if (!isConnecting) {
if (mqttClient.connectionStatus.state ==
MqttConnectionState.disconnected) {
Global().logWrite('正在尝试重新连接到MQTT代理...');
mqttClient.connect().then((value) => isConnecting = true);
} else {
isConnecting = false;
}
}
};
mqttClient.onConnected = onConnected;
mqttClient.onDisconnected = onDisconnected;
mqttClient.onSubscribed = _onSubscribed;
mqttClient.onSubscribeFail = _onSubscribeFail;
mqttClient.onUnsubscribed = _onUnSubscribed;
var mqttConnectMessage = MqttConnectMessage()
.authenticateAs(username, password)
.withClientIdentifier(clientIdentifier)
.withWillTopic('willTopic')
.withWillMessage('Will message')
.startClean()
.withProtocolName("MQTT")
.withProtocolVersion(4)
.keepAliveFor(20)
.withWillQos(MqttQos.atLeastOnce);
mqttClient.connectionMessage = mqttConnectMessage;
mqttClient.setProtocolV311();
mqttClient.pongCallback = pong; //收到 PING 响应回调
mqttClient.logging(on: true);
if (isSsl) {
mqttClient.secure = true;
mqttClient.onBadCertificate = (dynamic a) => true;
}
Global().logWrite("_正在连接中...");
return mqttClient.connect(username, password);
}
disconnect() {
mqttClient.autoReconnect = false;
mqttClient.disconnect();
Global().logWrite("_disconnect");
}
void onDisconnected() {
Global().logWrite('Disconnected, reconnecting...');
isConnecting = false;
}
// TODO: 收到 PING 响应
void pong() {}
int publishMessage(String pTopic, String msg) {
Global().logWrite("_发送数据-topic:$pTopic,playLoad:$msg");
Uint8Buffer uint8buffer = Uint8Buffer();
var codeUnits = msg.codeUnits;
uint8buffer.addAll(codeUnits);
return mqttClient.publishMessage(pTopic, qos, uint8buffer, retain: false);
}
int publishRawMessage(String pTopic, List<int> list) {
Global().logWrite("_发送数据-topic:$pTopic,playLoad:$list");
Uint8Buffer uint8buffer = Uint8Buffer();
uint8buffer.addAll(list);
return mqttClient.publishMessage(pTopic, qos, uint8buffer, retain: false);
}
//MQTT状态
MqttConnectionState mqttCurrentStatus() {
return mqttClient == null
? MqttConnectionState.disconnected
: mqttClient.connectionStatus.state;
}
Subscription? subscribeMessage(String subtopic) {
return mqttClient.subscribe(subtopic, qos);
}
void unsubscribeMessage(String? unSubtopic) {
mqttClient.unsubscribe(unSubtopic!);
}
MqttClientConnectionStatus? getMqttStatus() {
return mqttClient.connectionStatus;
}
Stream<List<MqttReceivedMessage<MqttMessage>>>? updates() {
Global().logWrite("_监听成功!");
return mqttClient.updates;
}
onConnected() {
// mqttClient.onConnected = callback;
Global().logWrite("_onConnected");
//订阅主题
_subscribeTopic();
}
// 订阅主题
_subscribeTopic() {
String topic = "*********";
subscribeMessage(topic);
}
// 取消订阅
unSubscribeTopic() {
String topic = "*********";
unsubscribeMessage(topic);
}
_onSubscribed(String topic) {
Global().logWrite("_订阅主题成功---topic:$topic");
}
_onUnSubscribed(String? topic) {
Global().logWrite("_取消订阅主题成功---topic:$topic");
}
_onSubscribeFail(String topic) {
Global().logWrite("_onSubscribeFail");
}
}
四、连接到MQTT代理
在Flutter应用中,使用 'MqttTool.connect()’连接MQTT
MqttTool.getInstance()
?.connect(
server, // MQTT代理地址
port, // MQTT代理端口
clientId, // 客户端标识符
userName, // 用户名
password // 密码
)
.then((v) {
if (v?.returnCode == MqttConnectReturnCode.connectionAccepted) {
showShortToast("mqtt连接成功$clientId");
_startListen();
} else if (v?.returnCode == MqttConnectReturnCode.badUsernameOrPassword) {
Global().logWrite("密码错误!!!");
} else {
showShortToast("mqtt连接失败!!!$clientId");
}
});
五、订阅/取消订阅主题
在’MqttTool中,已实现连接成功后自动订阅主题
// 订阅主题
_subscribeTopic() {
String topic = "*********";
subscribeMessage(topic);
}
Subscription? subscribeMessage(String subtopic) {
return mqttClient.subscribe(subtopic, qos);
}
//取消订阅主题
unSubscribeTopic2() {
String topic = "*********";
unsubscribeMessage(topic);
}
void unsubscribeMessage(String? unSubtopic) {
mqttClient.unsubscribe(unSubtopic!);
}
六、发送消息
MqttTool.getInstance()?.publishMessage("topic", "MQTT Message");
七、接收消息
在MQTT连接代理成功后开启监听接收消息
_startListen() {
MqttTool.getInstance()?.updates()?.listen(_onData);
}
// 监听消息的具体实现
_onData(List<MqttReceivedMessage<MqttMessage>> data) {
final MqttPublishMessage recMess = data[0].payload as MqttPublishMessage;
final String topic = data[0].topic;
Utf8Decoder utf8Decoder = Utf8Decoder(allowMalformed: true);
mqttMsg = utf8Decoder.convert(recMess.payload.message);
Map<String, dynamic> responseData = jsonDecode(mqttMsg);
String desString = "topic is <$topic>, payload is <-- $mqttMsg -->";
Global().logWrite("$desString");
//解析desString ...
}
八、断开MQTT连接
MqttTool.getInstance()?.disconnect();
总结
通过使用MQTT工具类,我们能够在Flutter应用中轻松实现MQTT连接和消息传递。这为实现实时通信提供了一种强大而灵活的方式,适用于各种应用场景。希望本文能够帮助Flutter开发者更好地了解和应用MQTT在实时通信中的优势。在实际应用中,确保正确处理连接状态、消息传递和订阅/取消订阅等方面的逻辑,以确保应用的稳定性和用户体验。