微信小程序使用MQTT问题记录
这里环境是 uniapp vue3 typescript
很多国内轻量 IOT 应用都选择开发小程序做入口,那么肯定会集成 MQTT 框架,通常是选用 mqtt.js ,但是这个库是给 web 设计的, 很多环境微信小程序中没有,因此会遇到一些问题,常见的有
1. 直接使用无法连接上MQTT
__2. 如果手动导入引用 mqtt.min.js __
初发现可以使用,也是网上常见的解决办法,什么用旧版本 4.0.2 之类的解决办法 . 但是深度测试会发现,很多 MQTT__生命周期不会回调!!!__ 这种属于深坑了,会导致一些应用 BUG 影响用户体验.
所以我们的解决思路还是以解决官方包使用无效的方向为主
解决方案 1. 导入额外依赖 首先看下官方文档在关于小程序支持上有说明
要增加这些部分
1 2 3 4 5 6 import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only' // import before mqtt. import 'esbuild-plugin-polyfill-node/polyfills/navigator' const mqtt = require("mqtt"); const client = mqtt.connect("wxs://test.mosquitto.org", { timerVariant: 'native' // more info ref issue: #1797 });
实际操作中发现,前面的 import 如果只是在同一个文件中导入顺序有限于mqtt.js ,那么实际上是无效的.
所以只能放到 main.ts 的最上方
第一行导入后也需要执行 npm install 能解决 AbsortController 缺失的报错 ,然而第二行还是会报错,我们直接去除. navigator这边查看源码后,只是一个简单的对象, 我们手动加入到源码即可
var navigator={deviceMemory:8,hardwareConcurrency:8,language:"en-Us"}; 这段代码手动添加到 node_modules/mqtt/dist/mqtt.esm.js最前面 至此 navigator 问题解决
2. 配置问题 现在会遇到 WebSocket is not a constructor 的错误,或者不报错.这里是因为小程序环境不传入 websocket对象的话默认new的是有问题的,所以我们要手动传入一个, 这里重点是 timerVariant,forceNativeWebSocket,createWebsocket 这三个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 private buildClientOptions () : IClientOptions { return { clientId : this .clientId , username : this .userId , password : this .boundAccessToken , clean : false , keepalive : KEEP_ALIVE_SECONDS , reconnectPeriod : RECONNECT_PERIOD_MS , connectTimeout : CONNECT_TIMEOUT_MS , protocolVersion : 5 , resubscribe : true , properties : { sessionExpiryInterval : SESSION_EXPIRY_SECONDS , }, will : { topic : this .willTopic , payload : JSON .stringify ({ foreground : false }), qos : 1 , retain : false , }, timerVariant : 'native' , forceNativeWebSocket : true , createWebsocket : (url : string , websocketSubProtocols : string [], options : IClientOptions ) : WebSocket => { const socketTask = wx.connectSocket ({ url, protocols : websocketSubProtocols, header : { 'content-type' : 'application/json' , }, }); const listeners : Record <string , Function []> = { open : [], close : [], error : [], message : [], }; let readyState = 0 ; let binaryType = 'arraybuffer' ; const messageQueue : (string | ArrayBuffer )[] = []; socketTask.onOpen (() => { readyState = 1 ; listeners.open .forEach (fn => fn ()); while (messageQueue.length > 0 ) { const msg = messageQueue.shift (); if (msg === undefined ) continue ; socketTask.send ({ data : msg, fail : err => console .error ('Queued message send error:' , err), }); } }); socketTask.onClose (res => { readyState = 3 ; listeners.close .forEach (fn => fn (res)); }); socketTask.onError (res => { readyState = 3 ; listeners.error .forEach (fn => fn (res)); }); socketTask.onMessage (res => { listeners.message .forEach (fn => fn ({ data : res.data })); }); const socketLike : WebSocket = { get readyState () { return readyState; }, get binaryType () { return binaryType; }, set binaryType (type ) { binaryType = type ; }, send (data : string | ArrayBufferLike | Blob | ArrayBufferView ) { let payload : string | ArrayBuffer ; try { payload = toStandardArrayBuffer (data); } catch (err) { console .error ('Data conversion error:' , err); return ; } if (readyState === 1 ) { socketTask.send ({ data : payload, fail : (err ) => console .error ('Send error:' , err), }); } else { console .warn ('Socket not open yet, message queued' ); messageQueue.push (payload); } }, close (code ?: number , reason ?: string ) { socketTask.close ({ code, reason }); }, addEventListener (type : string , listener : Function ) { if (listeners[type ]) { listeners[type ].push (listener); } }, removeEventListener (type : string , listener : Function ) { if (listeners[type ]) { listeners[type ] = listeners[type ].filter (fn => fn !== listener); } }, set onopen (fn : Function ) { listeners.open = [fn]; }, set onclose (fn : Function ) { listeners.close = [fn]; }, set onerror (fn : Function ) { listeners.error = [fn]; }, set onmessage (fn : (arg0 : any ) => any ) { listeners.message = [(e : any ) => fn (e)]; }, } as any ; return socketLike; } } }
1 const client = mqtt.connect (MQTT_URL , this .buildClientOptions ())
解决!