1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 支付宝小程序使用MQTT over WebSocket连接阿里云IoT物联网平台

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

时间:2022-05-18 06:30:45

相关推荐

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

前言

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

坑点

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

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

修改源码步骤:

首先git clone /mqttjs/MQTT.js.git 把源码下到本地修改入口的判断,及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')

改成(即把 typeofwebpack_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'

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

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

修改支持支付宝小程序协议部分(对照PR修改即可)

对应文件:lib/connect/ali.js 修改完成如下

'use strict'var Transform = require('readable-stream').Transformvar duplexify = require('duplexify')var base64 = require('base64-js')/* global FileReader */var myvar proxyvar streamvar 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

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

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

开始编码

随便在一个页面的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}.`,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参考文档:/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)

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,不想自己编译的小伙伴自行下载。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。