MQTT 插件
@capacitor-rydeen/mqtt 为 Android、iOS、Web、Electron 提供统一的 MQTT 客户端能力:连接、订阅、发布、心跳与网络质量监控,并通过事件驱动(addListener)向应用层推送消息与状态变化。
插件设计目标:
- 在弱网/移动网络环境中尽量保持「不断连」,自动处理重连;
- 对外暴露统一的 TypeScript API 和事件模型,隐藏各平台底层差异;
- 为门店终端、收银机、一体机等场景提供稳定的消息通道。
支持平台:Android / iOS / Web / Electron,各平台能力差异见下文「平台能力矩阵」。
设计思想
- 事件驱动:所有消息、连接状态、心跳、订阅结果、网络质量等都通过事件推送到 JS 层,前端只需订阅对应事件即可。
- 弱网不断连:通过
keepAliveInterval、reconnectInterval、maxReconnectAttempts、heartbeatEnabled、monitorEnabled等配置,在断网/恢复、App 前后台切换等情况下自动恢复连接。 - 网络路径切换:通过
NetworkPathType(PUBLIC/VPC)与vpcHost/vpcPort,在公网与 VPC 之间平滑切换。 - 平台对齐:Android/iOS 使用原生 MQTT 客户端(弱网优化、心跳、网络质量);Web/Electron 使用
mqtt包的 WebSocket 实现,并尽量对齐事件与心跳格式。
安装与集成
npm install @capacitor-rydeen/mqtt
npx cap sync
Web / Electron 需要安装对等依赖:
npm install mqtt
在应用中导入:
import { Mqtt } from '@capacitor-rydeen/mqtt'
平台能力矩阵
| 能力 | Android | iOS | Web | Electron |
|---|---|---|---|---|
| 方法 | ||||
connect | ✅ | ✅ | ✅ | ✅ |
reconnect | ✅ | ✅ | ✅ | ✅ |
isConnected | ✅ | ✅ | ✅ | ✅ |
disconnect | ✅ | ✅ | ✅ | ✅ |
subscribe | ✅ | ✅ | ✅ | ✅ |
unsubscribe | ✅ | ✅ | ✅ | ✅ |
updateConfig | ✅ | ✅ | ✅ | ✅ |
switchServer | ✅ | ✅ | ✅ | ✅ |
publish | ✅ | ✅ | ✅ | ✅ |
| 事件 | ||||
mqttMessage | ✅ | ✅ | ✅ | ✅ |
mqttConnectionState | ✅ | ✅ | ✅ | ✅ |
mqttSubscriptionResult | ✅ | ✅ | ✅ | ✅ |
mqttHeartbeat | ✅ | ✅ | ✅ | ✅ |
mqttSignalStrength | ✅ | ❌ | ❌ | ❌ |
mqttNetworkQuality | ✅ | ✅ | ❌ | ❌ |
- Android:原生实现(依赖
rydeen-mqtt-android),TCP/TLS 直连,支持全部 6 类事件(消息、连接状态、心跳、信号强度、网络质量、订阅结果)。 - iOS:原生实现(见
ios/DESIGN.md),TCP/TLS 直连;实现消息、连接状态、心跳、订阅结果、网络质量。- 信号强度:iOS 无公开 API 获取实时 RSSI/dBm,暂不实现。
- 网络质量:在
monitorEnabled为 true 时,按monitorCheckInterval对 Broker host:port 做 TCP 建连测时与丢包统计,通过mqttNetworkQuality上报。
- Web:基于 npm 包
mqtt,使用 WebSocket(ws/wss)连接/mqtt端点;实现消息、连接状态、订阅结果、心跳事件:heartbeatEnabled为 true 时,按keepAliveInterval向$heartbeat/{clientId}发心跳并触发mqttHeartbeat;- 无系统级信号强度/网络质量,
mqttSignalStrength/mqttNetworkQuality不可用。
- Electron:与 Web 共用同一套
MqttWeb实现,能力与 Web 一致。
快速开始
import { Mqtt } from '@capacitor-rydeen/mqtt'
// 1. 建立连接
await Mqtt.connect({
server: {
host: 'your-broker.com',
port: 8883,
username: 'user',
password: 'pass',
clientId: 'my-client-id',
networkPath: 'PUBLIC',
vpcHost: 'vpc-broker.com',
vpcPort: 8883
},
keepAliveInterval: 60,
reconnectInterval: 5000,
heartbeatEnabled: true,
monitorEnabled: true,
autoReconnect: true
})
// 2. 监听连接状态
Mqtt.addListener('mqttConnectionState', (e) => {
console.log('[MQTT] state =', e.state, e.stateDesc, 'network:', e.networkType)
})
// 3. 监听消息
Mqtt.addListener('mqttMessage', (msg) => {
console.log('[MQTT] message', msg.topic, msg.payload)
})
// 4. 订阅与发布
await Mqtt.subscribe({ topic: 'device/+/status' })
await Mqtt.publish({
topic: 'device/123/cmd',
payload: JSON.stringify({ action: 'reboot' }),
qos: 1,
retained: false,
messageId: '',
properties: new Map()
})
实战示例:门店终端在线状态与远程指令
场景:门店一体机通过 MQTT 上报自身在线状态、网络质量,并接收后台下发的远程指令(如重启、更新配置)。
Topic 约定
- 状态上报:
status/{clientId} - 心跳:
$heartbeat/{clientId}(插件内部已实现) - 网络质量:通过
mqttNetworkQuality事件上报; - 远程指令:
cmd/{clientId}/#
共享订阅 Topic 规则(Shared Subscription)
在需要做「多实例均衡消费」时,可以使用 MQTT 共享订阅,标准写法为:
-
协议版本要求:
- 共享订阅是 MQTT 5.0 标准中新增的特性,大部分 Broker 需要显式开启或仅在 MQTT 5.0 连接下可用;
- 使用前请确认 Broker 已支持并开启共享订阅能力。
-
基本语法:
$share/{groupId}/{topicFilter}groupId:共享组 ID,用于把多个客户端划入同一消费组,例如store-terminal;topicFilter:常规的 Topic Filter,例如cmd/{clientId}/#、status/+/online等。
-
组内均衡消费:
- 同一
groupId + topicFilter下,只会有 一个 在线客户端实际收到某条消息,用于做负载均衡; - 需要多实例同时收到消息时,请使用普通订阅(非
$share/前缀)。
- 同一
-
Topic Filter 规则:
topicFilter的写法与普通订阅完全一致,支持+、#通配符;- 禁止 在
groupId中使用/、+、#等分隔符和通配符,推荐只用字母、数字与中划线/下划线。
-
订阅示例:
- 单个客户端订阅:
cmd/{clientId}/#(所有实例都能收到) - 共享订阅(同组均衡):
$share/store-terminal/cmd/{clientId}/#
- 单个客户端订阅:
-
与插件配合使用:
- 在
Mqtt.subscribe的topic字段中,直接传入以上$share/...形式即可; - 建议同一业务类型统一约定
groupId,避免不同应用意外进入同一共享组。
- 在
-
典型使用场景:
- 共享订阅通常用于 服务端 / 后台消费端(如订单处理集群、推送服务集群),以实现多实例之间的消息负载均衡;
- 一般业务侧前端/客户端不需要使用共享订阅,但在 门店有多台 POS 机 的场景中,为避免单点故障,也可以考虑让多台 POS 机加入同一共享组来「接单」,只要有一台在线即可消费到该订单。
代码示例(简化版)
import { Mqtt } from '@capacitor-rydeen/mqtt'
async function setupMqtt(clientId: string) {
await Mqtt.connect({
server: {
host: 'broker.rydeen.com',
port: 8883,
username: clientId,
password: '***',
clientId,
networkPath: 'PUBLIC',
vpcHost: 'mqtt-vpc.rydeen.com',
vpcPort: 8883
},
keepAliveInterval: 60,
reconnectInterval: 5000,
heartbeatEnabled: true,
monitorEnabled: true,
monitorCheckInterval: 30,
autoReconnect: true
})
// 1. 订阅远程指令
await Mqtt.subscribe({ topic: `cmd/${clientId}/#` })
// 2. 监听指令消息
Mqtt.addListener('mqttMessage', (msg) => {
if (!msg.topic.startsWith(`cmd/${clientId}/`)) return
const payload = JSON.parse(msg.payload || '{}')
switch (payload.action) {
case 'reboot':
// 触发应用重启或提示用户
break
case 'update-config':
// 更新本地配置后持久化到 storage/preferences
break
}
})
// 3. 监听心跳与网络质量
Mqtt.addListener('mqttHeartbeat', (hb) => {
console.log('[MQTT] heartbeat', hb.clientId, hb.status, hb.timestamp)
})
Mqtt.addListener('mqttNetworkQuality', (q) => {
console.log('[MQTT] quality', q.pingLatency, 'ms', q.packetLossDesc)
// 可上报到 logger 或展示在 UI
})
}
在实际项目中,推荐将上述逻辑封装为 MqttService,由应用启动流程统一初始化,并通过状态管理(如 Angular Service / RxJS / Signal)向组件层暴露简化后的状态。
API 与类型参考
本节根据 src/definitions.ts 展开所有方法、事件与类型,便于仅靠文档就能开发。
方法列表
| 方法 | 签名 | 说明 |
|---|---|---|
| connect | connect(config: MqttConfig): Promise<void> | 建立连接。 |
| reconnect | reconnect(): Promise<void> | 使用最近一次配置重连;若用户主动 disconnect 则不再自动重连。 |
| isConnected | isConnected(): Promise<MqttConnectionResult> | 返回当前是否已连接。 |
| disconnect | disconnect(): Promise<void> | 主动断开连接,标记为用户断开。 |
| subscribe | subscribe(config: MqttSubscribeConfig): Promise<void> | 订阅主题。 |
| unsubscribe | unsubscribe(config: MqttSubscribeConfig): Promise<void> | 取消订阅。 |
| updateConfig | updateConfig(config: MqttConfig): Promise<void> | 更新配置,不主动断开重连。 |
| switchServer | switchServer(config: MqttSwitchServerConfig): Promise<void> | 按 networkPath 切换到 PUBLIC/VPC 并重连。 |
| publish | publish(config: MqttPublishConfig): Promise<void> | 发布消息。 |
事件(addListener)
| 事件名 | 回调参数类型 | 说明 |
|---|---|---|
mqttMessage | MqttMessage | 收到订阅主题的消息。 |
mqttConnectionState | MqttConnection | 连接状态变化(connected / disconnected / reconnecting / error 等)。 |
mqttSubscriptionResult | MqttSubscriptionResult | 订阅/取消订阅结果。 |
mqttHeartbeat | MqttHeartbeat | 心跳上报(clientId、status、timestamp)。 |
mqttSignalStrength | MqttSignalStrength | 信号强度(仅 Android)。 |
mqttNetworkQuality | MqttNetworkQuality | 网络质量(Android、iOS)。 |
主要类型摘要
完整字段与默认值请参考源码中的
src/definitions.ts,此处列出关键字段与含义。
-
MqttConfig:连接与行为配置
server: MqttServer:MQTT 服务端配置;sessionExpiryInterval?: number:会话过期时间;keepAliveInterval?: number:保活/心跳间隔(秒);reconnectInterval?: number:重连间隔(毫秒);maxReconnectAttempts?: number:最大重连次数;heartbeatEnabled?: boolean:是否启用心跳;monitorEnabled?: boolean:是否启用网络监控;monitorCheckInterval?: number:网络质量检测间隔(秒);autoReconnect?: boolean:是否自动重连。
-
MqttServer:服务端与网络路径
host: string:主机;port: number:端口;username: string/password: string:鉴权;clientId: string:客户端 ID;groupId?: string:分组 ID;networkPath?: 'PUBLIC' | 'VPC':网络路径;vpcHost?: string/vpcPort?: number:VPC 主机与端口。
-
MqttPublishConfig:发布参数
topic: string、payload: string、qos: number、retained: boolean、messageId: string、properties: Map<string,string>。
-
事件 payload:
MqttMessage:topic、messageId、timestamp、retained、qos、payload、properties;MqttConnection:state、stateDesc、networkType;MqttHeartbeat:clientId、status、timestamp;MqttSubscriptionResult:topic、timestamp、action、success、messageId;MqttSignalStrength:networkType、signalStrength、signalStrengthDesc;MqttNetworkQuality:pingLatency、pingLatencyDesc、packetLoss、packetLossDesc。
在实际使用中,建议为以上事件定义统一的封装层(如 MqttService),对上层屏蔽 topic 细节、错误重试与平台差异。