微信小程序哪些wifi+tcp+udp踩过的坑

一、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", //12345678910
      success(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", //12345678910
      success(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然后再连接tcp
    let 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) => {
  //十六进制转ArrayBuffer
  return 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, //获取图片的URL
      method: "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
}
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值