一、wifi操作流程

1、wx.startWifi 开启wifi模块

2、如果需要展示wifi列表则调用 wx.getWifiList(Object object)

注意:
请求获取 Wi-Fi 列表。wifiList 数据会在 onGetWifiList 注册的回调中返回。 Android 调用前需要 用户授权 scope.userLocation。

iOS 上将跳转到系统设置中的微信设置页,需要用户手动进入「无线局域网」设置页,并在系统扫描到设备后,小程序才能收到 onGetWifiList 回调。Android 不会跳转。

3、可以直接连接wifi wx.connectWifi

注意:
有可能wifi连接不上,需要传入forceNewApi 参数,文档中没有说明

wx.connectWifi({forceNewApi: true,SSID: "PUNKCYBER",password: "12345678910", //12345678910success(res3) {},fail(res) {console.log("wifi连接失败" + res.errCode + "  " + res.errMsg);},})},

android 手机连接wifi,连接成功后,会返回wifi信息,但是ios不会返回wifi信息。这个wifi信息有可能在连接tcp的时候会用到bssid,如果没有返回则可以调用 wx.getConnectedWifi

4、canvas保存为临时文件,ios 不显示
注意: backround-url 背景图片不显示 其实在image的组件中是显示的

5、TCP通讯
创建TCP : let tcp = wx.createTCPSocket();
监听绑定wifi事件 :tcp.onBindWifi
监听连接 : tcp.onConnect
监听消息 : tcp.onMessage
监听关闭 : tcp.onClose
监听错误 : tcp.onError
绑定wifi : tcp.bindWifi
连接tcp:tcp.connect
为什么从tcp转为udp:
connect能直接连接电脑端服务器tcp,但是连接硬件需要先绑定wifi,安卓没有问题,ios不支持bindWifi方法,ios一直连不上udp。所以后面从tcp转为了udp

6、UDP通讯
请忽略下面的tcp变量名,因为我是从tcp通讯改的udp通讯 UDP 有可能会限制包大小

创建UDP : let tcp = wx.createUDPSocket();
绑定

  if ("ios" == wx.getSystemInfoSync().platform) {this.globalData.tcp.bind(); // ios不需要端口} else {this.globalData.tcp.bind(20565); // android 需要端口}
  **监听方法事件** : tcp.onListening(();**监听报文的返回**: tcp.onMessage;**监听关闭**: tcp.onClose;**监听错误**: tcp.onError;发送: tcp.send({address: '192.168.4.1',port: 20565,setBroadcast: true, //ios 需要添加这个message: bufferArr[subTcpDataIndex]
})

7、wifi框架代码

// app.js
var packet = require('./utils/packet');
let wifiError = {"12005": "请打开wifi","12006": "请打开GPS","12007": "用户拒接连接wifi","12010": "系统错误,请重试","1505005": "请打开wifi或重启设备","1505006": "请连接设备"
}App({onLaunch() {console.log("onLaunch");// 展示本地存储能力wx.setEnableDebug({enableDebug: true})let tcp = wx.createUDPSocket();this.globalData.tcp = tcp;tcp.onListening((res) => {console.log("res==>", res);this.tcpConnectCallback();});tcp.onMessage((res) => {clearTimeout(getApp().globalData.timeoutTimer); //如果监听到有数据返回,在清除超时定时器let val = this.arrayBufferToHexString(res.message);console.log('onMessage-val', val)if (val == "4F4B0D0A") { //”OK\r\n”代表连接正常this.globalData.tcpDataIndex = this.globalData.tcpDataIndex + 1;packet.tcpWrite();} else if (val == "54494D45204F55540D0A") { //超时重新发送  //packet.tcpWrite();if (this.globalData.timeoutCount < 3) { //需要判断是分包发送还是整包发送this.globalData.timeoutCount++;packet.sendDataBySubPackage();} else {wx.hideLoading();wx.showToast({title: "更新失败,请重试",mask: true,icon: "none"})}} else if (val == packet.packageHex) { //分包发送完毕this.globalData.subTcpDataIndex = this.globalData.subTcpDataIndex + 1;packet.sendDataBySubPackage();} else if (val == packet.errorHex) {wx.hideLoading();wx.showToast({title: "更新失败,请重试",mask: true,icon: "none"})}})tcp.onClose((res) => {console.log('断开了', res)this.globalData.tcpIsClose = true})tcp.onError((res) => {console.log('tcp-错误了', res)// wx.hideLoading();//clearTimeout(this.globalData.timer);// errCode -2  Network is unreachable //设备断电了// errCode -2 bind socket fail:errno:48 errmsg:  // wx.showToast({ // 不提示错误信息//   title: res.errMsg,//   mask: true,//   icon: 'none',// })if (res.errMsg == "create sock fail udp alread exist") {wx.hideLoading();this.tcpConnectCallback();}})},onHide() {console.log("onHide")this.globalData.tcp.close();},tcpConnectCallback() {wx.hideLoading();clearTimeout(this.globalData.timer);this.globalData.tcpIsClose = false;console.log('tcp连接成功')packet.tcpWrite();},wifiInit() {let that = this;if ("ios" == wx.getSystemInfoSync().platform) {wx.showLoading({title: '连接中',})}wx.connectWifi({forceNewApi: true,SSID: "PUNKCYBER",password: "12345678910", //12345678910success(res3) {wx.hideLoading();console.log("连接wifi成功", res3)that.getConnectedWifi(); //ios手机会出现问题//that.connectTcp();},fail(res) {wx.hideLoading();wx.showToast({title: wifiError[res.errCode + ''] ? wifiError[res.errCode + ''] : res.errMsg,mask: true,icon: "none"})console.log("wifi连接失败" + res.errCode + "  " + res.errMsg);},})},connectTcp() {console.log('链接')wx.showLoading({title: "连接中",mask: true,})let timer = setTimeout(() => {if (this.globalData.tcpIsClose) {wx.showToast({title: '连接超时,请重试',mask: true,icon: 'none',})}}, 2000)this.globalData.timer = timer;this.globalData.tcpIsClose = true;if ("ios" == wx.getSystemInfoSync().platform) {this.globalData.tcp.bind(); // ios不需要端口} else {this.globalData.tcp.bind(20565); // android 需要端口}},tcpInit() {this.globalData.timeoutCount = 0;//判断wifi是否连接,wifi连接,则直接连接tcp,如果wifi未连接,则连接wifi然后再连接tcplet that = this;if (this.globalData.startWifi) {this.getConnectedWifi();} else {wx.startWifi({success(res) {console.log("初始化wifi模块成功" + res.errMsg)that.startWifi = true;that.getConnectedWifi();},fail(res) {wx.showToast({title: wifiError[res.errCode + ''] ? wifiError[res.errCode + ''] : res.errMsg,mask: true,icon: 'none'})}})}},getConnectedWifi() {let that = this;wx.getConnectedWifi({success(res) {console.log("获取WiFixinxi", res)if (!res.wifi || res.wifi.SSID != 'PUNKCYBER') {that.wifiInit();} else {that.connectTcp();}},fail(res) {wx.showToast({title: wifiError[res.errCode + ''] ? wifiError[res.errCode + ''] : (wifiError[res.errno + ''] ? wifiError[res.errno + ''] : res.errMsg),mask: true,icon: 'none'})console.log("获取wifi信息失败", res);}});},//buffer 转16进制arrayBufferToHexString: function (buffer) {const hexArr = Array.prototype.map.call(new Uint8Array(buffer),function (bit) {return ('00' + bit.toString(16)).slice(-2)})return hexArr.join('').toUpperCase();},globalData: {bufferArr: [],tcpDataIndex: 0,subTcpDataIndex: 0,tcpDataArr: [],tcp: null,openid: "",deviceOnline: !1,deviceId: "",userImgList: {},userLikeList: [],tcpIsClose: true,imagesCount: 12,startWifi: false,startSendBefore: 0,ssid: '',timer: '',wifi: {},isUpdateFirstDate: true, //是否第一次校验时间timeoutCount: 0,timeoutTimer: 0,}
})

packet

let newLineHex = "0D0A"; //\r\n
let byte4Hex = "00000000"; //预留4字节0x00
let byte2Hex = "0000"; //预留2字节0x00
let testHex = "495053434c4f434b20544553540D0A";
let startSendImagesHex = "55504441544520504943545552450D0A";
let endDiyImagesHex = "5345542044495920454e440D0A";
let endBbdImagesHex = "5345542042424420454e440D0A";
let timeoutHex = "54494d45204f55540D0A"
let setTimeHex = "5345542054494D45"
let setLightHex = "53455420524742204C4544"
let packageHex = "44415441205345474D454E54204F4B0D0A"
let errorHex = "4552524F520D0A"//16进制转字符串
const hexToStr = (hex, encoding) => {var trimedStr = hex.trim();var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;var len = rawStr.length;var curCharCode;var resultStr = [];for (var i = 0; i < len; i = i + 2) {curCharCode = parseInt(rawStr.substr(i, 2), 16);resultStr.push(curCharCode);}var val = "";var arr = resultStr;for (let i = 0; i < arr.length; i++) {val += String.fromCharCode(arr[i]);}return val;
}//字符串转16进制
const stringToHex = (str) => {var val = "";for (var i = 0; i < str.length; i++) {if (val == "") {val = str.charCodeAt(i).toString(16); //获取字符的Unicode码然后转16进制} else {val += str.charCodeAt(i).toString(16); //获取字符的Unicode码然后转16进制再拼接,中间用逗号隔开}}return val;
}
//十进制转十六进制
const tenToHex = (num, digit = 4) => {const hex = num.toString(16);return hex.padStart(digit, 0);
}const firstTcpData = (sendDataArr) => {let globalData = getApp().globalData;globalData.tcpDataIndex = 0;// 全局存放tcp需要发送的数据组globalData.tcpDataArr = sendDataArr;globalData.startSendBefore = 0;}
//tcp 写入数据
const tcpWrite = () => {let globalData = getApp().globalData;let isUpdateFirstDate = globalData.isUpdateFirstDate;if (isUpdateFirstDate && getApp().globalData.tcpDataArr.length != 1 && getApp().globalData.tcpDataArr[0].indexOf(setTimeHex) == -1) { //第一次要发送校验时间并且当前指令不是校验时间指令getApp().globalData.tcpDataArr.push(getNowTimePacket());getApp().globalData.isUpdateFirstDate = false;}let tcpDataArr = globalData.tcpDataArr;let tcpDataIndex = globalData.tcpDataIndex;// 将数据组遍历发送,过滤掉为空的数组if (tcpDataIndex < tcpDataArr.length) {// console.log(`发送${tcpDataIndex}次`)let content = `正在更新${tcpDataIndex+1- globalData.startSendBefore}` + "/" + globalData.imagesCount;let tcpData = tcpDataArr[tcpDataIndex];if (tcpData) {if (tcpData == testHex) {content = "正在测试连接";globalData.startSendBefore++;} else if (tcpData == startSendImagesHex) {content = "准备更新图片";globalData.startSendBefore++;} else if (tcpData == endDiyImagesHex || tcpData == endBbdImagesHex) {content = "更新图片完毕";} else if (tcpData.indexOf(setTimeHex) != -1) {content = "正在同步时间";} else if (tcpData.indexOf(setLightHex) != -1) {content = "正在同步灯光";}console.log(content)// console.log("发送的报文",tcpDataArr[tcpDataIndex]);wx.showLoading({title: content,// mask: true,})getApp().globalData.subTcpDataIndex = 0;getApp().globalData.bufferArr = getBufferArrayBy1000(tcpDataArr[tcpDataIndex]);sendDataBySubPackage();} else {getApp().globalData.tcpDataIndex = tcpDataIndex + 1;tcpWrite();}} else {wx.showToast({title: '更新成功',mask: true,icon: 'success',})getApp().globalData.tcp.close(); //tcp 断开,小程序无法再次连接tcp}
}const sendDataBySubPackage = () => {let globalData = getApp().globalData;let tcp = globalData.tcp;let subTcpDataIndex = globalData.subTcpDataIndex;let bufferArr = globalData.bufferArr;if (subTcpDataIndex < bufferArr.length) {tcp.send({address: '192.168.4.1',port: 20565,setBroadcast: true, //ios 需要添加这个message: bufferArr[subTcpDataIndex]})//1s未回复,定义为超时let timer = setTimeout(()=>{if(getApp().globalData.timeoutCount<3){ //需要判断是分包发送还是整包发送console.log("响应超时",getApp().globalData.timeoutCount);getApp().globalData.timeoutCount = getApp().globalData.timeoutCount+1;sendDataBySubPackage();}else{wx.hideLoading();wx.showToast({title: "更新失败,请重试",mask: true,icon:"none"})}},3000)getApp().globalData.timeoutTimer = timer;console.log("我发送了数据",subTcpDataIndex,bufferArr.length)}
}const getBufferArrayBy1000 = (data) => {let num = 0;let len = 1000;if (typeof data == "undefined") return [];let allBuffer = hexStringToArrayBuffer(data);let bufferLen = allBuffer.byteLength;let bufferArray = [];while (bufferLen > 0) {let buffer;if (bufferLen > len) {buffer = allBuffer.slice(num, num + len);num = num + len;bufferLen -= len;bufferArray.push(buffer);} else {buffer = allBuffer.slice(num, num + bufferLen);num += bufferLen;bufferLen -= bufferLen;bufferArray.push(buffer);}}return bufferArray;
}
const hexStringToArrayBuffer = (str) => {//十六进制转ArrayBufferreturn new Uint8Array(str.match(/[\da-f]{2}/gi).map(function (h) {return parseInt(h, 16)})).buffer
}//mode= "DIY" 表盘模式 mode= "BBD" 表白模式
// no: 图片索引 00 - 99 月:10,日11
const getImagePacket = (filePath, no, mode = 'DIY') => {const fs = wx.getFileSystemManager()// 同步接口try {const fileDataHex = fs.readFileSync(filePath, 'hex', 0)// ”SET DIY_00.jpg\r\n”+预留4字节0x00+2字节0x00+2字节图片大小+图片数据+”\r\n” 表盘模式let fileSizeHex = tenToHex(parseInt(fileDataHex.length / 2));let start = `SET ${mode}_${no}.jpg`;let startHex = stringToHex(start);let sendDataHex = (startHex + newLineHex + byte4Hex + byte2Hex + fileSizeHex + fileDataHex + newLineHex).toUpperCase();// console.log("发送的图片数据报文", sendDataHex)return sendDataHex;} catch (e) {console.error(e)}
}//mode= "DIY" 表盘模式 mode= "BBD" 表白模式
// no: 图片索引 00 - 99 月:10,日11
const getImagePacketByHttpUrl = (filePath, no, mode = 'DIY') => {// 同步接口return new Promise((resolve, reject) => {wx.request({url: filePath, //获取图片的URLmethod: "get",responseType: 'arraybuffer', //ArrayBuffer涉及面比较广,我的理解是ArrayBuffer代表内存之中的一段二进制数据,一旦生成不能再改。可以通过视图(TypedArray和DataView)进行操作。success: (res) => {const fileDataHex = arrayBufferToHexString(res.data);// ”SET DIY_00.jpg\r\n”+预留4字节0x00+2字节0x00+2字节图片大小+图片数据+”\r\n” 表盘模式let fileSizeHex = tenToHex(parseInt(fileDataHex.length / 2));let start = `SET ${mode}_${no}.jpg`;let startHex = stringToHex(start);let sendDataHex = (startHex + newLineHex + byte4Hex + byte2Hex + fileSizeHex + fileDataHex + newLineHex).toUpperCase();// console.log("发送的图片数据报文", sendDataHex)resolve(sendDataHex)//return sendDataHex;},fail(res) {console.log("失败", res);}})})}
const arrayBufferToHexString = (buffer) => {const hexArr = Array.prototype.map.call(new Uint8Array(buffer),function (bit) {return ('00' + bit.toString(16)).slice(-2)})return hexArr.join('').toUpperCase();
}
//同步时间报文
const getNowTimePacket = () => {let date = new Date();let fullYear = date.getFullYear() + '';const year = tenToHex(parseInt(fullYear.substring(fullYear.length - 2)), 2);const month = tenToHex(date.getMonth() + 1, 2);const day = tenToHex(date.getDate(), 2);const hour = tenToHex(date.getHours(), 2);const minute = tenToHex(date.getMinutes(), 2);const second = tenToHex(date.getSeconds(), 2);let start = `SET TIME`;let startHex = stringToHex(start);let dateTimeHex = year + month + day + hour + minute + second;let sendDataHex = (startHex + newLineHex + byte4Hex + dateTimeHex + byte4Hex + newLineHex).toUpperCase();//console.log("发送的时间数据报文", sendDataHex)return sendDataHex;
}//灯光报文
const getRGBPacket = (onOffStatus, bright, sleepStatus, lightMode, GRB) => {console.log("原始数据");console.log(onOffStatus, bright, sleepStatus, lightMode, GRB);let start = `SET RGB LED`;let startHex = stringToHex(start);let onOffStatusHex = onOffStatus ? "01" : "00";let brightHex = tenToHex(bright, 2);let sleepStatusHex = sleepStatus ? "01" : "00";;let lightModeHex = lightMode.toString().padStart(2, 0);let GRBHex = GRB.substring(1);console.log("16进制数据");console.log(onOffStatusHex, brightHex, sleepStatusHex, lightModeHex, GRBHex);let sendDataHex = (startHex + newLineHex + byte4Hex + onOffStatusHex + brightHex + sleepStatusHex + lightModeHex + GRBHex + byte4Hex + newLineHex).toUpperCase();console.log("发送的RGB数据报文", sendDataHex)return sendDataHex;
}module.exports = {getImagePacket,getNowTimePacket,getRGBPacket,tcpWrite,hexStringToArrayBuffer,testHex,firstTcpData,startSendImagesHex,endDiyImagesHex,endBbdImagesHex,timeoutHex,packageHex,sendDataBySubPackage,errorHex,getImagePacketByHttpUrl
}

微信小程序哪些wifi+tcp+udp踩过的坑相关推荐

  1. 扫码进入微信小程序使用WIFI进行UDP通信发送消息

    项目前提:液晶屏不可操作无网络但是有热点,需要通过扫液晶屏上的二维码进入微信小程序配置连接WIFI 业务逻辑:手机扫码进入微信小程序,登录页面输入登录密码进入配置WIFI页面,配置WIFI页面输入当前 ...

  2. 微信小程序实现大转盘抽奖----踩坑之路

    微信小程序实现大转盘抽奖----踩坑之路 需求:现在有一个小程序抽奖页面如下,此类抽奖方式为大转盘 思路:由服务端获取抽奖次数和奖品,根据服务端的中奖概率来决定是否中奖,最后利用小程序动画将转盘转起来 ...

  3. 【微信小程序控制硬件14 】 微信小程序蓝牙+WiFi双控制ESP32-C3应用示范;(附带Demo)

    文章目录 一.前言 二.设备核心代码 2.1 蓝牙控制 2.2 WiFi控制 2.3 外设驱动 三.微信小程序核心代码 3.1 蓝牙搜索 3.2 蓝牙服务发现 四.感谢 另外,不要把我的博客作为学习标 ...

  4. 微信小程序 局域网内TCP意外断开后重连

    微信小程序在局域网内遇到客户端意外断开,重新连接的问题: 前言 目前制作的小程序需要在多个页面调用TCP 发送命令,所以TCP直接创建在APP首页里面: 1,首先判断TCP是否有断开:onClose( ...

  5. 微信小程序全面实战,架构设计与躲坑攻略大全

    感谢作者齐修的授权,如需转载,请与作者联系. 作者:齐修,早先就职淘宝UED,目前在好奇心日报参与创业,除了基本的项目开发,还偏好于前端工程化.网站性能优化等方向. 责编:陈秋歌,关注微信开发等领域, ...

  6. uniapp微信小程序使用vant-weapp详细操作步骤(各种坑)

    首先在微信小程序里用的vant是vant-weapp而不是vant 官网: Vant Weapp - 轻量.可靠的小程序 UI 组件库轻量.可靠的小程序 UI 组件库https://youzan.gi ...

  7. 使用charls抓包微信小程序的解决方案(终极解决,各种坑不怕,亲测可用,不服来战!)...

    第一步:使用charles进行https抓包 https://www.jianshu.com/p/7a88617ce80b   使用charles进行https抓包 使用Charles进行HTTPS抓 ...

  8. 微信小程序源码提取与反编译爬坑

    前言 没必要说太多,基本上操作是没有什么难度的,这里说一些我遇到的问题与解决方式.首先测试小程序,由于他不像是web,是不能通过查看源代码的方式来查看js代码的,所以需要手动的将小程序源码拿出来,然后 ...

  9. 微信小程序单次请求上限20条的坑

    近期在学习小程序云开发的时候,遇到一个坑,数据请求限制单次20条-- 即便是遍历请求会出现一个数据整合异常,因为每次拿到数据的时间不一致导致有先后顺序 这里加入一个判断数组长度的方法,让新请求到的数据 ...

最新文章

  1. leangoo大讲堂--北京站
  2. MS SQL数据库服务介绍
  3. php 锁的使用场景,抢购秒杀的场景使用锁个人认为不太合理?
  4. silverlight计时器
  5. C程序设计语言现代方法14:预处理器
  6. Cisco 3550配置DHCP实例
  7. JVisualVM监控jvm
  8. php中轮转图片js代码,纯JavaScript手写图片轮播代码
  9. Kali Linux全网最细安装教程
  10. 会打飞机吗?原来用 Python 实现打飞机更爽
  11. 一步一步从原理跟我学邮件收取及发送 7.读取一行命令的实现
  12. 云存储平台——Seafile搭建
  13. 最近在论证一个问题,到底是先有鸡还是先有蛋:
  14. dos批处理脚本自动添加网络IP打印机-简单亲测可用
  15. 程序员必备小众又实用的网站,你知道几个?
  16. 2个25Ge网口做bond(mode4)后,iperf2压测不到50Gb
  17. 仿抖音右滑清屏,左滑列表功能
  18. symfony简单的博客练习,熟悉具体开发流程
  19. dialog 弹出框,遮罩层覆盖内容
  20. Unity UI插件

热门文章

  1. kdevtmpfsi 处理(挖矿病毒清除)
  2. TryHackMe新手村
  3. Day9——用栈实现队列、用队实现拟栈
  4. SpringMVC之国际化
  5. 陈冠希翻车都十年了,还有人在疯狂偷窥你的照片
  6. 国外计算机安全类期刊,信息安全-计算机取证SCI期刊(国外英文资料).doc
  7. 微信小程序自定义页面Title
  8. Pytho制作小游戏——是男人就下100层
  9. java文件读取德语乱码
  10. 7 岁男孩被 AI 机器人折断手指,仅因下棋太快?