当前位置: 首页 > news >正文

Flutter之使用mqtt进行连接和信息传输的使用案例

目录

引言

什么是MQTT?

在Flutter中使用MQTT

安装

iOS 

安卓

创建一个全局的客户端对象

 配置客户端对象

 连接(异步)

监听接受的消息

发送消息 

监听连接状态和订阅的回调


引言

 随着移动应用开发技术的发展,实时通信成为了许多应用程序不可或缺的一部分。无论是社交应用中的即时消息传递,还是物联网(IoT)设备之间的数据交换,都需要一个高效稳定的通信机制。MQTT(Message Queuing Telemetry Transport)作为一种轻量级的消息协议,非常适合于这种场景。本文将介绍如何在Flutter项目中集成MQTT,并通过一个简单的示例来演示其基本用法。

什么是MQTT?

MQTT是一种基于发布/订阅模式的轻量级消息协议,设计初衷是为了提供低开销、低带宽的网络连接。它特别适合于远程位置的通信,如传感器与中央服务器之间的数据传输。MQTT的主要特点包括:

  • 轻量级:非常小的代码占用空间和带宽使用。
  • 发布/订阅模型:允许一对多的消息分发,即一个消息可以发送给多个客户端。
  • 服务质量(QoS):提供了三种不同的服务质量级别,以满足不同场景下的需求。
  • 安全性:支持TLS/SSL加密,确保数据传输的安全性。

 

在Flutter中使用MQTT

首先需要安装mqtt_client这个依赖,执行下面命令

flutter pub add mqtt_client 

安装

如果您在 Android 或 iOS 设备上的 Flutter 环境中使用客户端,则需要进行以下设备权限设置。

iOS 

将以下键添加到位于ios/Runner/Info.plist的Info.plist文件中:

<key>NSLocalNetworkUsageDescription</key>
<string>Looking for local tcp Bonjour service</string>
<key>NSBonjourServices</key>
<array><string>mqtt.tcp</string>
</array>

安卓

将以下 Android 权限添加到位于android/app/src/main/AndroidManifest.xml的AndroidManifest.xml文件中:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

在页面中导入:

import 'package:mqtt_client/mqtt_client.dart';

使用案例, 这里我们使用的是wss协议:

import 'dart:convert';
import 'package:flutter_diancan/utils/logger_helper.dart';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';
import 'package:shared_preferences/shared_preferences.dart';class MqttServe {final client = MqttServerClient('请求地址', '');Future<MqttClient> connect() async {try {client.setProtocolV311();client.logging(on: true);client.port = 443; // 端口号client.keepAlivePeriod = 60;client.websocketProtocols = ['mqtt'];client.useWebSocket = true;  // 因为我们这里使用的是wss协议所以加这个,这个根据自己的需求来定是否需要client.onConnected = onConnected;client.onDisconnected = onDisconnected;client.onUnsubscribed = onUnsubscribed;client.onSubscribed = onSubscribed;client.onSubscribeFail = onSubscribeFail;client.pongCallback = pong;client.connectTimeoutPeriod = 60;final connMess = MqttConnectMessage().authenticateAs("用户名", "密码").withClientIdentifier('Mqtt_MyClientUniqueId').withWillTopic('willtopic').withWillMessage('My Will message').startClean().withWillQos(MqttQos.atLeastOnce);client.connectionMessage = connMess;try {print('Connecting');await client.connect();} catch (e) {print('Exception: $e');client.disconnect();}client.updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) async {final recMessage = c![0].payload as MqttPublishMessage;final payload = MqttPublishPayload.bytesToStringAsString(recMessage.payload.message);print('Received message:$payload from topic: ${c[0].topic}');});} catch (e, s) {LoggerHelper.fatal(e, s);}return client;}Future<void> sendMessage() async {if (client.connectionStatus?.state == MqttConnectionState.connected) {final builder = MqttClientPayloadBuilder();var payloadObject = {'MsgData': "发送成功啦"};print("发送的信息:${json.encode(payloadObject)} ");builder.addUTF8String(json.encode(payloadObject));client.publishMessage('发送消息的订阅地址', MqttQos.atLeastOnce, builder.payload!);}}// Connected callbackvoid onConnected() {print("已连接");try {// 连接后订阅client.subscribe('订阅地址', MqttQos.atLeastOnce);} catch (e, s) {LoggerHelper.fatal(e, s);}}// Disconnected callbackvoid onDisconnected() async {print('已断开');final SharedPreferences prefs = await SharedPreferences.getInstance();String? token = prefs.getString('token');if (token != null) {reconnect();}}Future<void> reconnect() async {print("重连中");int retryCount = 0;const maxRetries = 10;const baseRetryInterval = 2; // 初始重连间隔时间(秒)while (retryCount < maxRetries) {try {print('Reconnecting attempt ${retryCount + 1}...');await client.connect();if (client.connectionStatus?.state == MqttConnectionState.connected) {print('Reconnected successfully.');break;}} catch (e) {print('Reconnect failed: $e');}// 计算下一次重连间隔时间(指数退避)int retryInterval = baseRetryInterval * (2 << retryCount);await Future.delayed(Duration(seconds: retryInterval));retryCount++;}}// 关闭Future<void> close() async {try {// 重新订阅client.unsubscribe('订阅地址');} catch (e, s) {LoggerHelper.fatal(e, s);}client.disconnect();}// Subscribed callbackvoid onSubscribed(String topic) {print('订阅成功,主题为: $topic');}// Subscribed failed callbackvoid onSubscribeFail(String topic) {print('订阅失败,主题为: $topic');}// Unsubscribed callbackvoid onUnsubscribed(String? topic) {print('Unsubscribed topic: $topic');}// Ping callbackvoid pong() {print('调用Ping响应客户端回调');}
}

  • 创建一个全局的客户端对象

final client = MqttServerClient('请求地址', '');
  •  配置客户端对象

      client.setProtocolV311();client.logging(on: true);client.port = 443; // 端口号client.keepAlivePeriod = 60;client.websocketProtocols = ['mqtt'];client.useWebSocket = true;  // 因为我们这里使用的是wss协议所以加这个,这个根据自己的需求来定是否需要client.onConnected = onConnected;client.onDisconnected = onDisconnected;client.onUnsubscribed = onUnsubscribed;client.onSubscribed = onSubscribed;client.onSubscribeFail = onSubscribeFail;client.pongCallback = pong;client.connectTimeoutPeriod = 60;
  • 设置连接消息
 final connMess = MqttConnectMessage().authenticateAs("用户名", "密码").withClientIdentifier('Mqtt_MyClientUniqueId').withWillTopic('willtopic').withWillMessage('My Will message').startClean().withWillQos(MqttQos.atLeastOnce);client.connectionMessage = connMess;
  •  连接(异步)

 try {print('Connecting');await client.connect();} catch (e) {print('Exception: $e');client.disconnect();}
  • 监听接受的消息

 client.updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) async {final recMessage = c![0].payload as MqttPublishMessage;final payload = MqttPublishPayload.bytesToStringAsString(recMessage.payload.message);print('Received message:$payload from topic: ${c[0].topic}');});
  • 发送消息 

Future<void> sendMessage() async {if (client.connectionStatus?.state == MqttConnectionState.connected) {final builder = MqttClientPayloadBuilder();var payloadObject = {'MsgData': "发送成功啦"};print("发送的信息:${json.encode(payloadObject)} ");builder.addUTF8String(json.encode(payloadObject));client.publishMessage('发送消息的订阅地址', MqttQos.atLeastOnce, builder.payload!);}}
  • 监听连接状态和订阅的回调

// Connected callbackvoid onConnected() {print("已连接");try {// 连接后订阅client.subscribe('订阅地址', MqttQos.atLeastOnce);} catch (e, s) {LoggerHelper.fatal(e, s);}}// Disconnected callbackvoid onDisconnected() async {print('已断开');final SharedPreferences prefs = await SharedPreferences.getInstance();String? token = prefs.getString('token');if (token != null) {reconnect();}}Future<void> reconnect() async {print("重连中");int retryCount = 0;const maxRetries = 10;const baseRetryInterval = 2; // 初始重连间隔时间(秒)while (retryCount < maxRetries) {try {print('Reconnecting attempt ${retryCount + 1}...');await client.connect();if (client.connectionStatus?.state == MqttConnectionState.connected) {print('Reconnected successfully.');break;}} catch (e) {print('Reconnect failed: $e');}// 计算下一次重连间隔时间(指数退避)int retryInterval = baseRetryInterval * (2 << retryCount);await Future.delayed(Duration(seconds: retryInterval));retryCount++;}}// 关闭Future<void> close() async {try {// 重新订阅client.unsubscribe('订阅地址');} catch (e, s) {LoggerHelper.fatal(e, s);}client.disconnect();}// Subscribed callbackvoid onSubscribed(String topic) {print('订阅成功,主题为: $topic');}// Subscribed failed callbackvoid onSubscribeFail(String topic) {print('订阅失败,主题为: $topic');}// Unsubscribed callbackvoid onUnsubscribed(String? topic) {print('Unsubscribed topic: $topic');}// Ping callbackvoid pong() {print('调用Ping响应客户端回调');}

相关文章:

Flutter之使用mqtt进行连接和信息传输的使用案例

目录 引言 什么是MQTT&#xff1f; 在Flutter中使用MQTT 安装 iOS 安卓 创建一个全局的客户端对象 配置客户端对象 连接&#xff08;异步&#xff09; 监听接受的消息 发送消息 监听连接状态和订阅的回调 引言 随着移动应用开发技术的发展&#xff0c;实时通信成为…...

汽车HiL测试:利用TS-GNSS模拟器掌握硬件性能的仿真艺术

一、汽车HiL测试的概念 硬件在环&#xff08;Hardware-in-the-Loop&#xff0c;简称HiL&#xff09;仿真测试&#xff0c;是模型基于设计&#xff08;Model-Based Design&#xff0c;简称MBD&#xff09;验证流程中的一个关键环节。该步骤至关重要&#xff0c;因为它整合了实际…...

【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段

文章目录 一、MyBatis-Plus简介二、快速入门1、环境准备2、将mybatis项目改造成mybatis-plus项目&#xff08;1&#xff09;引入MybatisPlus依赖&#xff0c;代替MyBatis依赖&#xff08;2&#xff09;配置Mapper包扫描路径&#xff08;3&#xff09;定义Mapper接口并继承BaseM…...

前端知识点---rest(javascript)

文章目录 前端知识点---rest(javascript)rest的用法基本语法特点使用场景与扩展运算符&#xff08;spread&#xff09;区别小练习 前端知识点—rest(javascript) rest出现于ES2015 function doSum(a,b, ...args) //示例中的args就是一个rest参数 //它会将后续的所有参数存储…...

13. 猜最大公约数最小公倍数小游戏

文章目录 概要整体架构流程技术名词解释技术细节小结 1. 概要 ~ Jack Qiao对米粒说&#xff1a;“今天咱们玩个小游戏&#xff0c;这个游戏的玩家需要猜出&#xff0c;两个随机生成的整数的最大公约数&#xff08;GCD&#xff09;和最小公倍数&#xff08;LCM&#xff09;。如…...

Git 多仓库提交用户信息动态设置

Git 多仓库提交用户信息动态设置 原文地址&#xff1a;dddhl.cn 前言 在日常开发中&#xff0c;我们可能需要同时管理多个远程仓库&#xff08;如 GitHub、Gitee、GitLab&#xff09;&#xff0c;而每个仓库使用不同的邮箱和用户名。比如&#xff0c;GitHub 和 Gitee 使用相…...

2024.6使用 UMLS 集成的基于 CNN 的文本索引增强医学图像检索

Enhancing Medical Image Retrieval with UMLS-Integrated CNN-Based Text Indexing 问题 医疗图像检索中&#xff0c;图像与相关文本的一致性问题&#xff0c;如患者有病症但影像可能无明显异常&#xff0c;影响图像检索系统准确性。传统的基于文本的医学图像检索&#xff0…...

了解Redis(第一篇)

目录 Redis基础 什么事Redis Redis为什么这么快 除了 Redis&#xff0c;你还知道其他分布式缓存方案吗? 说-下 Redis 和 Memcached 的区别和共同点 为什么要用Redis? 什么是 Redis Module?有什么用? Redis基础 什么事Redis Redis &#xff08;REmote DIctionary S…...

UE5 第一人称射击项目学习(二)

在上一章节中。 得到了一个根据视角的位置创建actor的项目。 现在要更近一步&#xff0c;对发射的子弹进行旋转。 不过&#xff0c;现在的子弹是圆球形态的&#xff0c;所以无法分清到底怎么旋转&#xff0c;所以需要把子弹变成不规则图形。 现在点开蓝图。 这里修改一下&…...

npm/cnpm的使用

npm 1、安装npm 前往nodejs官网下载安装node 验证是否安装成功node node -v node安装npm也会安装 npm -v 2、使用npm 1. 初始化项目 在一个项目文件夹中运行&#xff1a; npm init 根据提示输入项目信息&#xff08;如项目名称、版本号等&#xff09;。 如果你希望快速初…...

go-zero(六) JWT鉴权

go-zero JWT鉴权 还记得我们之前登录功能&#xff0c;返回的信息是token吗&#xff1f; 这个token其实就是JSON Web Token简称JWT,它是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在网络应用环境间安全地传递声明信息。 它是一种基于 JSON 的令牌&#xf…...

做一个FabricJS.cc的中文文档网站——面向markdown编程

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;用爱发电&#…...

开发 + 安全:网络安全的协作方法

开发团队和安全团队之间由来已久的紧张关系一直是组织内部摩擦的根源。开发人员优先考虑速度和效率&#xff0c;旨在通过快节奏、迭代的开发周期快速交付功能和产品并高效前进。另一方面&#xff0c;安全团队努力平衡风险和创新&#xff0c;但必须专注于使用护栏保护敏感数据和…...

Next.js- App Router 概览

#题引&#xff1a;我认为跟着官方文档学习不会走歪路 一&#xff1a;App Router与Page Router 在 v13 版本中&#xff0c;Next.js 引入了一个基于 React 服务器组件 构建的新的 App Router&#xff0c;而在这之前&#xff0c;Next.js 使用的是Page Router。 目录结构 pages …...

python oa服务器巡检报告脚本的重构和修改(适应数盾OTP)有空再去改

Two-Step Vertification required&#xff1a; Please enter the mobile app OTPverification code: 01.因为巡检的服务器要双因子认证登录&#xff0c;也就是登录堡垒机时还要输入验证码。这对我的巡检查服务器的工作带来了不便。它的机制是每一次登录&#xff0c;算一次会话…...

【工控】线扫相机小结 第四篇

背景 这一片主要是对第三篇继续补充。话说上一篇讲到了两种模式的切换&#xff0c;上一篇还遗留了一个Bug&#xff0c;在这一篇里进行订正&#xff01; 代码回顾 /// <summary>/// 其实就是打开触发/// </summary>void SetLineSacanWorkMode(){-----首先设置为帧…...

亲测解决Unpack operator in subscript requires Python 3.11 or newer

这个问题是在小虎想提前定义一个list,然后作为index list来调用另一个list里面的变量出现的问题。 环境 Ubuntu 22.04 + python 3.10 故障代码示例 NoneList = [None] * opt.spatial_dims TargetMask = Target[i] == torch.arange(1...

数据结构 ——— 堆排序算法的实现

目录 前言 向下调整算法&#xff08;默认建大堆&#xff09; 堆排序算法的实现&#xff08;默认升序&#xff09; 前言 在之前几章学习了如何用向上调整算法和向下调整算法对数组进行建大/小堆数据结构 ——— 向上/向下调整算法将数组调整为升/降序_对数组进行降序排序代码…...

On-Chip-Network之Topology

片上网络拓扑决定了网络中节点和通道之间的物理布局和连接。拓扑对整体网络性价比的影响是巨大的。拓扑决定了消息 必须经过的跳数&#xff08;或路由器&#xff09;以及跳数之间的互连长度&#xff0c;从而显著影响网络延迟。由于经过路由器和链路会产生功耗&#xff0c;因此 …...

2024年11月21日Github流行趋势

项目名称&#xff1a;twenty 项目维护者&#xff1a;charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael项目介绍&#xff1a;正在构建一个由社区支持的现代化Salesforce替代品。项目star数&#xff1a;21,798项目fork数&#xff1a;2,347 项目名称&#xff1a;p…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)

第一篇&#xff1a;Liunx环境下搭建PaddlePaddle 3.0基础环境&#xff08;Liunx Centos8.5安装Python3.10pip3.10&#xff09; 一&#xff1a;前言二&#xff1a;安装编译依赖二&#xff1a;安装Python3.10三&#xff1a;安装PIP3.10四&#xff1a;安装Paddlepaddle基础框架4.1…...