unapp 集成MQTT协议

一、核心前提

已有可用的 MQTT 服务端(如 EMQ X、Mosquitto,需开启 WebSocket 监听,默认端口:8083(ws)/8084(wss))

二、安装 MQTT 依赖

推荐使用 mqtt@3.0.0 版本(高版本对小程序兼容性较差):

npm install mqtt@3.0.0 --save

三、封装 MQTT 工具类

在项目 common 目录下创建 mqtt.js,统一管理连接、订阅、发布、断开等逻辑:

import mqtt from 'mqtt/dist/mqtt.min'

// MQTT 配置(根据实际服务端修改)
const MQTT_CONFIG = {
  // 不同端的连接协议:
  // H5: ws://xxx:8083/mqtt 或 wss://xxx:8084/mqtt
  // 微信小程序: wxs://xxx:8084/mqtt(需配置域名白名单)
  // App: tcp://xxx:1883(需配置网络权限)
  host: 'wss://your-mqtt-server.com:8084/mqtt', 
  clientId: `uni-app-${Math.random().toString(16).substr(2, 8)}`, // 唯一客户端ID
  username: 'your-username', // 服务端认证用户名(无则留空)
  password: 'your-password', // 服务端认证密码(无则留空)
  keepalive: 60, // 心跳间隔(秒)
  reconnectPeriod: 5000, // 重连间隔(毫秒)
  clean: true // 清除会话(true:断开后不保留订阅)
}

// 全局 MQTT 客户端实例
let client = null
// 消息回调函数(供页面监听)
let messageCallback = null

/**
 * 连接 MQTT 服务器
 * @param {Function} callback 消息接收回调 (topic, message) => {}
 */
export function connectMQTT(callback) {
  // 保存消息回调
  messageCallback = callback

  // 已连接则直接返回
  if (client && client.connected) return

  // 创建连接
  client = mqtt.connect(MQTT_CONFIG.host, {
    clientId: MQTT_CONFIG.clientId,
    username: MQTT_CONFIG.username,
    password: MQTT_CONFIG.password,
    keepalive: MQTT_CONFIG.keepalive,
    reconnectPeriod: MQTT_CONFIG.reconnectPeriod,
    clean: MQTT_CONFIG.clean
  })

  // 连接成功回调
  client.on('connect', () => {
    console.log('MQTT 连接成功:', MQTT_CONFIG.clientId)
  })

  // 接收消息回调
  client.on('message', (topic, message) => {
    console.log(`收到消息:topic=${topic}, message=${message.toString()}`)
    if (messageCallback) {
      messageCallback(topic, message.toString()) // 转字符串便于处理
    }
  })

  // 连接错误回调
  client.on('error', (error) => {
    console.error('MQTT 连接错误:', error)
  })

  // 断开连接回调
  client.on('close', () => {
    console.log('MQTT 连接断开')
  })

  // 重连回调
  client.on('reconnect', () => {
    console.log('MQTT 正在重连...')
  })
}

/**
 * 订阅 MQTT 主题
 * @param {String|Array} topic 主题(单个字符串或数组)
 * @param {Number} qos 服务质量(0/1/2,默认0)
 */
export function subscribeMQTT(topic, qos = 0) {
  if (!client || !client.connected) {
    console.error('MQTT 未连接,无法订阅')
    return
  }
  client.subscribe(topic, { qos }, (error) => {
    if (error) {
      console.error(`订阅主题 ${topic} 失败:`, error)
    } else {
      console.log(`订阅主题 ${topic} 成功`)
    }
  })
}

/**
 * 发布 MQTT 消息
 * @param {String} topic 主题
 * @param {String|Object} message 消息内容(对象会转为JSON字符串)
 * @param {Number} qos 服务质量(0/1/2,默认0)
 */
export function publishMQTT(topic, message, qos = 0) {
  if (!client || !client.connected) {
    console.error('MQTT 未连接,无法发布消息')
    return
  }
  // 统一转为字符串
  const msg = typeof message === 'object' ? JSON.stringify(message) : message
  client.publish(topic, msg, { qos }, (error) => {
    if (error) {
      console.error(`发布消息到 ${topic} 失败:`, error)
    } else {
      console.log(`发布消息到 ${topic} 成功:`, msg)
    }
  })
}

/**
 * 取消订阅 MQTT 主题
 * @param {String|Array} topic 主题(单个字符串或数组)
 */
export function unsubscribeMQTT(topic) {
  if (!client || !client.connected) {
    console.error('MQTT 未连接,无法取消订阅')
    return
  }
  client.unsubscribe(topic, (error) => {
    if (error) {
      console.error(`取消订阅 ${topic} 失败:`, error)
    } else {
      console.log(`取消订阅 ${topic} 成功`)
    }
  })
}

/**
 * 断开 MQTT 连接
 */
export function disconnectMQTT() {
  if (client && client.connected) {
    client.end()
    client = null
    console.log('MQTT 主动断开连接')
  }
}
mqtt.js

四、页面中使用 MQTT

以 pages/index/index.vue 为例,实现「连接→订阅→发布→接收消息→断开」完整流程:
<template>
  <view class="container">
    <button @click="connect">连接MQTT</button>
    <button @click="subscribe">订阅主题</button>
    <button @click="publish">发布消息</button>
    <button @click="disconnect">断开连接</button>
    <view class="message">
      <text>收到的消息:{{ receiveMessage }}</text>
    </view>
  </view>
</template>

<script>
import { connectMQTT, subscribeMQTT, publishMQTT, disconnectMQTT } from '@/common/mqtt.js'

export default {
  data() {
    return {
      receiveMessage: '' // 接收的消息
    }
  },
  onUnload() {
    // 页面卸载时断开连接,避免内存泄漏
    disconnectMQTT()
  },
  methods: {
    // 连接MQTT
    connect() {
      connectMQTT((topic, message) => {
        // 监听接收的消息
        this.receiveMessage = `主题:${topic},内容:${message}`
      })
    },

    // 订阅主题(示例:/uni-app/test)
    subscribe() {
      subscribeMQTT('/uni-app/test')
    },

    // 发布消息(示例:向/uni-app/test发布消息)
    publish() {
      publishMQTT('/uni-app/test', {
        content: 'Hello Uni-app MQTT',
        time: new Date().toLocaleString()
      })
    },

    // 断开连接
    disconnect() {
      disconnectMQTT()
      this.receiveMessage = ''
    }
  }
}
</script>

<style scoped>
.container {
  padding: 20rpx;
}
button {
  margin: 10rpx 0;
  padding: 15rpx;
  background: #007AFF;
  color: #fff;
  border-radius: 8rpx;
}
.message {
  margin-top: 20rpx;
  padding: 15rpx;
  background: #f5f5f5;
  border-radius: 8rpx;
}
</style>
index.vue

五、多端兼容配置

1. 微信小程序端

  • 域名白名单:登录「微信公众平台」→ 开发 → 开发设置 → 服务器域名,添加 MQTT 的 wss 域名到「request 合法域名」和「socket 合法域名」;
  • 协议限制:小程序仅支持 wxs://(wss)协议,不支持 ws:// 或 tcp://
  • 调试模式:本地调试可勾选「不校验合法域名」(仅开发阶段)。

2. App 端

  • 网络权限:在 manifest.json → App 模块配置 → Android 权限配置,添加:
    <uses-permission android:name="android.permission.INTERNET"/>
  • 协议支持:App 端可直接使用 tcp:// 协议(性能更好),无需通过 WebSocket 中转。

3. H5 端

  • 跨域问题:MQTT 服务端需配置 CORS 允许前端域名访问;
  • 协议选择:生产环境建议用 wss://(加密),避免 ws:// 被浏览器拦截。
posted @ 2026-01-04 22:08  zhang_you_wu  阅读(19)  评论(0)    收藏  举报