前言

之前写了一篇微信小程序使用MQTT over WebSocket连接阿里云IoT物联网平台,介绍了如何使用mqtt.js在微信小程序上连接mqtt服务器,文中顺带提了mqtt.js是支持支付宝小程序的,但是我本人没有实际编写过,后来有小伙伴来问我相关的问题,正好有空,于是稍微研究了一下,踩了不少坑,最后连接上了,以此记录,希望能给后来人一点帮助。

坑点

  1. 支付宝小程序和开发工具环境目前差距挺大,有时候开发工具能跑到真机就GG
  2. 支付宝mqtt.js连接参数要传入一个my(mqtt.js文档里没写这点,看了源码才懂)
  3. 由于支付宝小程序底层变动,以及最新mqtt.js(v4.2.0)版本的改动,导致mqtt.js当前版本v4.2.0未支持支付宝小程序(有人提交了PR,但是没有后续,没合并)

综上所述,如果当前你想在支付宝小程序上使用mqtt.js,只能等合并pr发布的新版本,或者自己下载源码修改编译(注意:开发工具要最新版本,否则会报错FileReader is not constructor(当前v1.13.7)

修改源码步骤:

  1. 首先git clone https://github.com/mqttjs/MQTT.js.git 把源码下到本地
  2. 修改入口的判断,及PR#1135改动的部分
    对应文件 :lib/connect/index.js
if ((typeof process !== 'undefined' && process.title !== 'browser') || typeof __webpack_require__ === 'function') {protocols.mqtt = require('./tcp')   protocols.mqtt = require('./tcp')protocols.tcp = require('./tcp')     protocols.tcp = require('./tcp')protocols.ssl = require('./tls')      protocols.ssl = require('./tls')

改成(即把 typeof webpack_require === ‘function’ 条件去掉)

if ((typeof process !== 'undefined' && process.title !== 'browser') ) {protocols.mqtt = require('./tcp')    protocols.mqtt = require('./tcp')protocols.tcp = require('./tcp')     protocols.tcp = require('./tcp')protocols.ssl = require('./tls')      protocols.ssl = require('./tls')

对应文件:lib/connect/ws.js

// eslint-disable-next-line camelcasevar IS_BROWSER = (typeof process !== 'undefined' && process.title === 'browser') || typeof __webpack_require__ === 'function'

改成(同样去掉 typeof webpack_require === ‘function’ 条件),这个地方其实改不改都可以

// eslint-disable-next-line camelcasevar IS_BROWSER = (typeof process !== 'undefined' && process.title === 'browser')
  1. 修改支持支付宝小程序协议部分(对照PR修改即可)
    对应文件:lib/connect/ali.js 修改完成如下
'use strict'var Transform = require('readable-stream').Transform
var duplexify = require('duplexify')
var base64 = require('base64-js')/* global FileReader */
var my
var proxy
var stream
var isInitialized = falsefunction buildProxy () {var proxy = new Transform()proxy._write = function (chunk, encoding, next) {const _data = chunk.toString('base64'); //订正mqttjs支付宝小程序使用错误,支付宝data需要传入base64 stringmy.sendSocketMessage({data: _data,isBuffer: 1,success: function () {next()},fail: function () {next(new Error())}})}proxy._flush = function socketEnd (done) {my.closeSocket({success: function () {done()}})}return proxy
}function setDefaultOpts (opts) {if (!opts.hostname) {opts.hostname = 'localhost'}if (!opts.path) {opts.path = '/'}if (!opts.wsOptions) {opts.wsOptions = {}}
}function buildUrl (opts, client) {var protocol = opts.protocol === 'alis' ? 'wss' : 'ws'var url = protocol + '://' + opts.hostname + opts.pathif (opts.port && opts.port !== 80 && opts.port !== 443) {url = protocol + '://' + opts.hostname + ':' + opts.port + opts.path}if (typeof (opts.transformWsUrl) === 'function') {url = opts.transformWsUrl(url, opts, client)}return url
}function bindEventHandler () {if (isInitialized) returnisInitialized = truemy.onSocketOpen(function () {stream.setReadable(proxy)stream.setWritable(proxy)stream.emit('connect')})my.onSocketMessage(function (res) {if (typeof res.data === 'string') {var array = base64.toByteArray(res.data)var buffer = Buffer.from(array)proxy.push(buffer)} else {var reader = new FileReader()reader.addEventListener('load', function () {var data = reader.resultif (data instanceof ArrayBuffer) data = Buffer.from(data)else data = Buffer.from(data, 'utf8')proxy.push(data)})reader.readAsArrayBuffer(res.data)}})my.onSocketClose(function () {stream.end()stream.destroy()})my.onSocketError(function (res) {stream.destroy(res)})
}function buildStream (client, opts) {opts.hostname = opts.hostname || opts.hostif (!opts.hostname) {throw new Error('Could not determine host. Specify host manually.')}var websocketSubProtocol =(opts.protocolId === 'MQIsdp') && (opts.protocolVersion === 3)? 'mqttv3.1': 'mqtt'setDefaultOpts(opts)var url = buildUrl(opts, client)my = opts.mymy.connectSocket({url: url,headers : {"Sec-WebSocket-Protocol" : "mqtt"}})proxy = buildProxy()stream = duplexify.obj()bindEventHandler()return stream
}module.exports = buildStream

修改完成之后,执行npm install等待编译完成即可在dist目录下看到两个文件:mqtt.js 和mqtt.min.js,前一个是未压缩版本,有日志输出,可以用来调试,后一个是压缩版本,线上环境使用

当然你要是嫌麻烦,可以用我已经编译好的mqtt.js

准备工作(这一步基本就和微信小程序没啥大的区别了)

  1. 自己编译或者下载我上面已经编译好的mqtt.js包
  2. 去官方库aliyun-iot-client-sdk下载hmac-sha1算法库hex_hmac_sha1.js(当然也可以使用其他的库,比如crypto-js),点击打开链接然后右键另存为即可
  3. 下载支付宝小程序开发工具,新建任意项目
  4. 拷贝mqtt.min.js和hex_hmac_sha1.js到utils目录中去
  5. 可能支付宝还有其他配置,具体自己看文档了

开始编码

随便在一个页面的js文件中加入以下代码,注意替换参数为自己产品和设备的参数

const crypto = require('../../utils/hex_hmac_sha1.js'); //根据自己存放的路径修改
import {connect} from '../../utils/mqtt.min.js' //根据自己存放的路径修改// 获取全局 app 实例
const app = getApp();
// 数据管理器
let conn = null;Page({// 声明页面数据data: {dataLoaded: false,tasks: [],taskHandlers: [],taskCheckers: [],info:'看看',message:''},// 监听生命周期回调 onLoadonLoad() {},// 监听生命周期回调 onShowonShow() {// 同步全局数据到本地//this.loadData();},onHide() {// TODO: 清理注册事件},
onTap(){this.doConnect();
},doConnect(){const deviceConfig = {productKey: "替换",deviceName: "替换",deviceSecret: "替换",regionId: "替换"};const options = this.initMqttOptions(deviceConfig);console.log(options)//替换productKey为你自己的产品的(注意这里是wxs,不是wss,否则你可能会碰到ws不是构造函数的错误)const client = connect(`alis://${deviceConfig.productKey}.iot-as-mqtt.${deviceConfig.regionId}.aliyuncs.com`,options)this.setData({info:"开始连接.."})client.on('connect',  ()=> {console.log('连接服务器成功')this.setData({info:"连接服务器成功"})//订阅主题,替换productKey和deviceName(这里的主题可能会不一样,具体请查看后台设备Topic列表或使用自定义主题)client.subscribe(`/${deviceConfig.productKey}/${deviceConfig.deviceName}/get`, function (err) {if (!err) {console.log('订阅成功!');}})})//接收消息监听client.on('message',  (topic, message) =>{// message is Bufferconsole.log('收到消息:'+message.toString())this.setData({message:message.toString()})//关闭连接 client.end()})},//IoT平台mqtt连接参数初始化initMqttOptions(deviceConfig) {const params = {productKey: deviceConfig.productKey,deviceName: deviceConfig.deviceName,timestamp: Date.now(),clientId: Math.random().toString(36).substr(2),}//CONNECT参数const options = {keepalive: 60, //60sclean: true, //cleanSession不保持持久会话protocolVersion: 4 ,//MQTT v3.1.1my:my //注意这里的my}//1.生成clientId,username,passwordoptions.password = this.signHmacSha1(params, deviceConfig.deviceSecret);options.clientId = `${params.clientId}|securemode=2,signmethod=hmacsha1,timestamp=${params.timestamp}|`;options.username = `${params.deviceName}&${params.productKey}`;return options;},/*生成基于HmacSha1的password参考文档:https://help.aliyun.com/document_detail/73742.html?#h2-url-1
*/signHmacSha1(params, deviceSecret) {let keys = Object.keys(params).sort();// 按字典序排序keys = keys.sort();const list = [];keys.map((key) => {list.push(`${key}${params[key]}`);});const contentStr = list.join('');return crypto.hex_hmac_sha1(deviceSecret, contentStr);}
});

运行代码,点击连接即可看到


至此支付宝小程序使用mqtt.js连接服务器已完成,更多信息可以参考

微信小程序使用MQTT over WebSocket连接阿里云IoT物联网平台

有疑问可以加我QQ:343672271 (备注mqtt)

2020年9月15日 补充:

mqttv4.2.0在模拟器和android机上中文显示正常,但是在苹果机上会乱码,需要自行修改源码ali.js接收数据解码部分,即改成:

 my.onSocketMessage(function (res) {if(res.isBuffer){let buff=new Buffer.from(res.data,'base64');proxy.push(buff);}else if (typeof res.data === 'string') {var array = base64.toByteArray(res.data)var buffer = Buffer.from(array)proxy.push(buffer)} else {var reader = new FileReader()reader.addEventListener('load', function () {var data = reader.resultif (data instanceof ArrayBuffer) data = Buffer.from(data)else data = Buffer.from(data, 'utf8')proxy.push(data)})reader.readAsArrayBuffer(res.data)}})

增加了其他的解码方式:

if(res.isBuffer){let buff=new Buffer.from(res.data,'base64');proxy.push(buff);}

本解决方案由小伙伴无疆(QQ昵称)提供,本人作为搬运工,编译好了一个版本mqtt.js,不想自己编译的小伙伴自行下载。

支付宝小程序使用MQTT over WebSocket连接阿里云IoT物联网平台相关推荐

  1. 【微信小程序控制硬件⑧ 】微信小程序以 websocket 连接阿里云IOT物联网平台mqtt服务器,封装起来使用就是这么简单!(附带Demo)

    [微信小程序控制硬件第1篇 ] 全网首发,借助 emq 消息服务器带你如何搭建微信小程序的mqtt服务器,轻松控制智能硬件! [微信小程序控制硬件第2篇 ] 开始微信小程序之旅,导入小程序Mqtt客户 ...

  2. 微信小程序使用MQTT.js连接阿里云IoT物联网平台

    官方已经开源了一个SDK版本,也是基于mqtt.js,进行了各种封装: https://github.com/aliyun/alibabacloud-iot-device-sdk · 阅读以下内容需要 ...

  3. 【小程序案例】支付宝小程序-MQTT模器,IoT设备通过WSS接入阿里云IoT物联网平台...

    支付宝小程序-MQTT模拟器通过WSS接入阿里云IoT物联网平台 准备工作 1.1 注册阿里云账号 开通阿里云账号,并通过支付宝实名认证 https://www.aliyun.com 1.2 免费开通 ...

  4. 解密阿里云IoT物联网平台MQTT Access Server核心架构

    MQTT是基于TCP/IP协议栈构建的异步通信消息协议,是一种轻量级的发布.订阅信息传输协议.MQTT已逐渐成为IoT领域最热门的协议,也是国内外各大物联网平台最主流的传输协议,阿里云IoT物联网平台 ...

  5. MQTT协议与阿里云IoT物联网平台

    1.MQTT协议介绍 1.1 MQTT协议 MQTT(消息队列遥测传输) 是基于 TCP/IP 协议栈而构建的支持在各方之间异步通信的消息协议.MQTT在空间和时间上将消息发送者与接收者分离,因此可以 ...

  6. 阿里云 IoT 物联网平台 MQTT 通讯模式

    阿里云 IoT企业物联网平台为不同场景的硬件提供了多种通信模式,例如设备到云,云到设备,设备到设备之间的通信.尽管不同业务场景设备和交互行为差异很大,但是大多数底层数据流通信模型都可以归类为三种MQT ...

  7. 用MQTT.fx模拟温度设备联调阿里云IOT物联网平台

    目录 一.介绍 二.创建产品 1.新建产品 2.查看属性 3.查看上报主题 三.添加设备 1.添加设备 2.设备信息 四.用MQTT.fx模拟设备 1.创建一个温度模拟器 2.发送信息 查看产品属性 ...

  8. 基于阿里云的MQTT协议入门一:注册及开通阿里云IoT物联网平台

    近日看了一些MQTT协议的入门及实战,在此记录一下MQTT的协议详解及调试笔记 阿里云的介绍就不多说了,下面直接开始进入讲解 首先需要登陆到阿里云平台 然后点击工作台,没有开通的需要开通,开通过程省略 ...

  9. MQTT.fx 模拟 IoT 设备接入阿里云企业物联网平台

    MQTT.fx是一款基于Eclipse Paho SDK,使用Java语言编写的MQTT客户端,支持Windows.Mac和Linux操作系统,可用于验证设备是否可与物联网平台正常连接,并基于 Top ...

最新文章

  1. 页面 table 可编辑的实现
  2. Unity Shaders
  3. amazon mws api 获取所有产品_致跨境电商新卖家 - 如何确定一个产品的市场容量?...
  4. 豪华奢侈的中国作家代表大会
  5. 前端学习(1606):数据请求与json-server
  6. 排队接水(洛谷-P1223)
  7. google摄像头查找办法
  8. DevExpress控件介绍
  9. 相机技术公司Lytro获6000万美元D轮融资,阿里巴巴参投
  10. 休闲娱乐游戏-贱鸟跳跳
  11. iOS开发中runtime介绍
  12. ubuntu16.04使用ipv6
  13. [linux] ab压测工具进行post压力测试
  14. 数据库课程设计:某自来水公司收费管理系统(SQL Server)
  15. redimine 插件_3DMine软件与国内外同类软件对比
  16. 基于FPGA 的毫米波雷达系统
  17. Docker管理工具Web UI:DockerUI Shipyard /portainer
  18. linux 显卡 卡死,linux服务器显卡崩溃解决方案
  19. 高速PCB设计指南系列(四)
  20. OpenGL Ant Tweak Bar的用户界面库

热门文章

  1. Android调用系统分享和指定app分享-微信朋友圈图文分享和qq分享
  2. 币圈炒币只有四种人能赚到钱其中之一是使用炒币机器人的玩家
  3. 毕业设计日志(18)
  4. 推荐一款开源的ICO制作神器——greenfish
  5. NLP(7): Word Sense Disambiguation and CKY
  6. 创建RAID磁盘列表(Raid5和Raid10)
  7. Windows10开机音乐替换
  8. 马克思主义基本原理笔记(黄色标记要求会背)
  9. android 2k屏分辨率,2K、4K、8K分辨率屏幕有用吗?看看它们怎么说!
  10. Real-time signal