在Flutter中实现实时通信:使用MQTT进行连接与消息传递

前言
实时通信对于现代移动应用而言是至关重要的一项功能。在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在实时通信中的优势。在实际应用中,确保正确处理连接状态、消息传递和订阅/取消订阅等方面的逻辑,以确保应用的稳定性和用户体验。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Android程序Su

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值