| @@ -0,0 +1,5 @@ | |||
| //app.js | |||
| App({ | |||
| onLaunch: function () { | |||
| } | |||
| }) | |||
| @@ -0,0 +1,21 @@ | |||
| { | |||
| "pages": [ | |||
| "pages/index/index", | |||
| "pages/wifiList/wifiList" | |||
| ], | |||
| "window": { | |||
| "navigationBarBackgroundColor": "#0082FE", | |||
| "navigationBarTextStyle": "white", | |||
| "navigationBarTitleText": "蓝牙连接Demo", | |||
| "backgroundColor": "#eeeeee", | |||
| "backgroundTextStyle": "light" | |||
| }, | |||
| "plugins": { | |||
| "sdkPlugin": { | |||
| "version": "1.1.2", | |||
| "provider": "wx17e93aad47cdae1a" | |||
| } | |||
| }, | |||
| "style": "v2", | |||
| "sitemapLocation": "sitemap.json" | |||
| } | |||
| @@ -0,0 +1,72 @@ | |||
| /**app.wxss**/ | |||
| view, | |||
| cover-view, | |||
| scroll-view, | |||
| swiper, | |||
| swiper-item, | |||
| movable-area, | |||
| movable-view, | |||
| button, | |||
| input, | |||
| textarea, | |||
| label, | |||
| navigator | |||
| { | |||
| box-sizing: border-box; | |||
| } | |||
| page{ | |||
| --safe-bottom: env(safe-area-inset-bottom); | |||
| } | |||
| .container{ | |||
| position: relative; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| width: 100vw; | |||
| height: 100vh; | |||
| padding-bottom: var(--safe-bottom); | |||
| } | |||
| .flex{ | |||
| display: flex; | |||
| } | |||
| .flex_column{ | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .ai_center{ | |||
| align-items: center; | |||
| } | |||
| .ai_start{ | |||
| align-items: flex-start; | |||
| } | |||
| .ai_end{ | |||
| align-items: flex-end; | |||
| } | |||
| .jc_center{ | |||
| justify-content: center; | |||
| } | |||
| .jc_sa{ | |||
| justify-content: space-around; | |||
| } | |||
| .jc_sb{ | |||
| justify-content: space-between; | |||
| } | |||
| .jc_end{ | |||
| justify-content: flex-end; | |||
| } | |||
| .flex_center{ | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| } | |||
| .flex_center_sa{ | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-around; | |||
| } | |||
| .flex_center_sb{ | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| } | |||
| @@ -0,0 +1,470 @@ | |||
| const util = require("../../utils/util"); | |||
| const {inArray, ab2hex} = util | |||
| const plugin = requirePlugin("sdkPlugin").AiLink; | |||
| Page({ | |||
| data: { | |||
| showWriteInput: false, | |||
| devices: [ | |||
| // { | |||
| // deviceId: "02:03:04:05:06:07", | |||
| // name: "elink", | |||
| // localName: "elink", | |||
| // mac: "02:03:04:05:06:07", | |||
| // RSSI: -69, | |||
| // advertisServiceUUIDs:[ | |||
| // "FFE0","FFC0" | |||
| // ], | |||
| // analyzeDataText:"0102003241123413" | |||
| // } | |||
| ], | |||
| connected: false, | |||
| chs: [], | |||
| cmd: '', | |||
| name: '', | |||
| deviceId: null, | |||
| historyList: [], | |||
| }, | |||
| onLoad: function () { | |||
| let historyList = [] | |||
| historyList = wx.getStorageSync('historyList') | |||
| this.setData({ | |||
| historyList, | |||
| }) | |||
| }, | |||
| toConnectWifi() { | |||
| this.offBLECharacteristicValueChange() | |||
| wx.navigateTo({ | |||
| url: '../wifiList/wifiList', | |||
| }) | |||
| }, | |||
| // 初始化蓝牙模块 | |||
| openBluetoothAdapter() { | |||
| wx.openBluetoothAdapter({ | |||
| success: (res) => { | |||
| console.log('openBluetoothAdapter success', res) | |||
| this.startBluetoothDevicesDiscovery() | |||
| }, | |||
| fail: (res) => { | |||
| if (res.errCode === 10001) { | |||
| wx.showToast({ | |||
| title: '请打开蓝牙', | |||
| icon: "none" | |||
| }) | |||
| wx.onBluetoothAdapterStateChange(function (res) { | |||
| console.log('onBluetoothAdapterStateChange', res) | |||
| if (res.available) { | |||
| this.startBluetoothDevicesDiscovery() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| // 获取本机蓝牙适配器状态 | |||
| getBluetoothAdapterState() { | |||
| wx.getBluetoothAdapterState({ | |||
| success: (res) => { | |||
| console.log('getBluetoothAdapterState', res) | |||
| if (res.discovering) { | |||
| this.onBluetoothDeviceFound() | |||
| } else if (res.available) { | |||
| this.startBluetoothDevicesDiscovery() | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| // 开始搜寻附近的蓝牙外围设备 | |||
| startBluetoothDevicesDiscovery() { | |||
| if (this._discoveryStarted) { | |||
| return | |||
| } | |||
| this._discoveryStarted = true | |||
| wx.startBluetoothDevicesDiscovery({ | |||
| allowDuplicatesKey: true, | |||
| services: [ | |||
| "FFE0", | |||
| // "F0A0", // BM30广播模块需加上,如使用连接模块可忽略 | |||
| ], | |||
| success: (res) => { | |||
| console.log('startBluetoothDevicesDiscovery success', res) | |||
| this.onBluetoothDeviceFound() | |||
| }, | |||
| }) | |||
| }, | |||
| // 停止搜寻附近的蓝牙外围设备 | |||
| stopBluetoothDevicesDiscovery() { | |||
| wx.stopBluetoothDevicesDiscovery() | |||
| }, | |||
| // 监听寻找到新设备的事件 | |||
| onBluetoothDeviceFound() { | |||
| wx.onBluetoothDeviceFound((res) => { | |||
| res.devices.forEach(device => { | |||
| if (!device.name && !device.localName) { | |||
| return | |||
| } | |||
| const foundDevices = this.data.devices | |||
| const idx = inArray(foundDevices, 'deviceId', device.deviceId) | |||
| const data = {} | |||
| // console.log(device) | |||
| // console.log(ab2hex(device.advertisData)) | |||
| // 此处判断是否BM30广播模块,如使用连接模块请删除此 if ,只保留 else 内容 | |||
| if (device.advertisServiceUUIDs[0].indexOf("F0A0") !== -1) { | |||
| let parseDataRes = plugin.parseBroadcastData(device.advertisData) | |||
| console.log(parseDataRes) | |||
| if (parseDataRes.status == 1) { | |||
| let analyzeData = plugin.analyzeBroadcastScaleData(parseDataRes) | |||
| console.log(analyzeData) | |||
| device.analyzeDataText = analyzeData.text | |||
| } | |||
| } else { | |||
| let buff = device.advertisData.slice(-6) | |||
| device.mac = new Uint8Array(buff) // 保存广播数据中的mac地址,这是由于iOS不直接返回mac地址 | |||
| let tempMac = Array.from(device.mac) | |||
| tempMac.reverse() | |||
| device.macAddr = ab2hex(tempMac, ':').toUpperCase() | |||
| } | |||
| if (idx === -1) { | |||
| data[`devices[${foundDevices.length}]`] = device | |||
| } else { | |||
| data[`devices[${idx}]`] = device | |||
| } | |||
| this.setData(data) | |||
| }) | |||
| }) | |||
| }, | |||
| // 连接低功耗蓝牙设备 | |||
| createBLEConnection(e) { | |||
| this._connLoading = true | |||
| wx.showLoading({ | |||
| title: '连接中', | |||
| }) | |||
| setTimeout(() => { | |||
| if (this._connLoading) { | |||
| this._connLoading = false | |||
| wx.hideLoading() | |||
| } | |||
| }, 6000) | |||
| const ds = e.currentTarget.dataset | |||
| const index = ds.index | |||
| // 保存当前连接的设备,注意不能从wxml的dataset中直接返回该对象,因为ArrarBuffer类型的数据无法保留 | |||
| this._device = this.data.devices[index] | |||
| console.log(this._device) | |||
| const deviceId = ds.deviceId | |||
| const name = ds.name | |||
| this.mac = ds.mac | |||
| wx.createBLEConnection({ | |||
| deviceId, | |||
| success: (res) => { | |||
| this.setData({ | |||
| connected: true, | |||
| name, | |||
| deviceId, | |||
| }) | |||
| console.log("createBLEConnection:success") | |||
| wx.stopBluetoothDevicesDiscovery() | |||
| this.onBLEConnectionStateChange() | |||
| this.getBLEDeviceServices(deviceId) | |||
| }, | |||
| fail: res => { | |||
| this._connLoading = false | |||
| wx.hideLoading() | |||
| wx.showToast({ | |||
| title: '连接失败', | |||
| icon: 'none' | |||
| }) | |||
| } | |||
| }) | |||
| // 连接上设备就可以停止蓝牙搜索,减少功耗。 | |||
| this.stopBluetoothDevicesDiscovery() | |||
| }, | |||
| onBLEConnectionStateChange() { | |||
| wx.onBLEConnectionStateChange((res) => { | |||
| console.log('wx.onBLEConnectionStateChange() ', res.deviceId, res.connected, res.errorCode, res.errorMsg) | |||
| // 该方法回调中可以用于处理连接意外断开等异常情况 | |||
| // console.log(`%c device ${res.deviceId} state has changed, connected: ${res.connected}`, 'color: #F26363') | |||
| if (!res.connected) { | |||
| setTimeout(()=>{ | |||
| wx.showToast({ | |||
| title: '连接已断开', | |||
| icon: 'none' | |||
| }) | |||
| },500) | |||
| wx.navigateBack() | |||
| this.setData({ | |||
| connected: false, | |||
| showWriteInput: false, | |||
| }) | |||
| } | |||
| }) | |||
| }, | |||
| // 断开与低功耗蓝牙设备的连接 | |||
| closeBLEConnection() { | |||
| wx.closeBLEConnection({ | |||
| deviceId: this._deviceId | |||
| }) | |||
| this.setData({ | |||
| connected: false, | |||
| chs: [], | |||
| showWriteInput: false, | |||
| }) | |||
| }, | |||
| // 获取蓝牙设备的 serviceId | |||
| getBLEDeviceServices(deviceId) { | |||
| wx.getBLEDeviceServices({ | |||
| deviceId, | |||
| success: (res) => { | |||
| for (let i = 0; i < res.services.length; i++) { | |||
| if (res.services[i].isPrimary && res.services[i].uuid.indexOf('FFE0') > -1) { | |||
| this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) | |||
| return | |||
| } | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| // 获取蓝牙设备某个服务中所有特征值(characteristic) | |||
| getBLEDeviceCharacteristics(deviceId, serviceId) { | |||
| this._deviceId = deviceId | |||
| this._serviceId = serviceId | |||
| this._device.serviceId = serviceId | |||
| wx.getBLEDeviceCharacteristics({ | |||
| deviceId, | |||
| serviceId, | |||
| success: (res) => { | |||
| console.log('getBLEDeviceCharacteristics success', res.characteristics) | |||
| // 这部分功能在插件的 initPlugin 中已实现,如需用到其中的 uuid 也可取消注释 | |||
| // for (let i = 0; i < res.characteristics.length; i++) { | |||
| // let item = res.characteristics[i] | |||
| // if (item.uuid.indexOf('0000FFE1') != -1) { | |||
| // this.uuid1 = item.uuid //下发数据 | |||
| // } else if (item.uuid.indexOf('0000FFE2') != -1) { | |||
| // this.uuid2 = item.uuid //监听数据 | |||
| // } else if (item.uuid.indexOf('0000FFE3') != -1) { | |||
| // this.uuid3 = item.uuid //写入设置 | |||
| // } | |||
| // } | |||
| // // 打开监听 | |||
| // wx.notifyBLECharacteristicValueChange({ | |||
| // deviceId, | |||
| // serviceId, | |||
| // characteristicId: this.uuid2, | |||
| // state: true, | |||
| // }) | |||
| // wx.notifyBLECharacteristicValueChange({ | |||
| // deviceId, | |||
| // serviceId, | |||
| // characteristicId: this.uuid3, | |||
| // state: true, | |||
| // }) | |||
| // 初始化插件 | |||
| plugin.initPlugin(res.characteristics, this._device) | |||
| wx.onBLECharacteristicValueChange((characteristic) => { | |||
| // 解析特征值,返回解密后的数据 | |||
| let bleData = plugin.parseBleData(characteristic.value) | |||
| console.log(bleData) | |||
| if (bleData.status == 0) { | |||
| console.log("握手成功") | |||
| this._connLoading = false | |||
| wx.hideLoading() | |||
| wx.showToast({ | |||
| title: '连接成功', | |||
| }) | |||
| setTimeout(()=>{ | |||
| this.toConnectWifi() | |||
| },500) | |||
| } else if (bleData.status == 1) { | |||
| let payload = bleData.data //对应协议中的payload数据,可以自行解析该数据 | |||
| // console.log(ab2hex(payload, ' ')) | |||
| // console.log(ab2hex(bleData.completeData, ' ')) | |||
| // 以体脂秤数据解析为例 | |||
| switch (payload[0]) { | |||
| /* | |||
| * 例如: A7 00 0E 05 01 00 01 F4 10 19 7A---------50.0kg | |||
| * 其中 01 00 01 F4 10 为 payload | |||
| * 具体指令请根据协议解析 | |||
| */ | |||
| case 0x01: | |||
| case 0x02: | |||
| let weightValue = (payload[1] << 16) | (payload[2] << 8) | payload[3] | |||
| let decPoint = (payload[4] & 0xf0) >> 4 | |||
| let unit = payload[4] & 0x0f | |||
| // console.log("体重数值:" + weightValue) | |||
| // console.log("小数点:" + decPoint) | |||
| // console.log("单位:" + unit) | |||
| if (unit == 1) { // 单位为斤 | |||
| this._weight = weightValue / 2 | |||
| } else { | |||
| // ... 其他单位 | |||
| } | |||
| this._weight = weightValue / (decPoint * 10) // 除去小数点位数 | |||
| break; | |||
| // ... | |||
| /* | |||
| * 例如: A7 00 0E 03 07 02 30 4A 7A---------阻抗测量成功,阻抗 560Ω | |||
| * 其中 07 02 30 为 payload | |||
| * 具体指令请根据协议解析 | |||
| */ | |||
| case 0x07: | |||
| this._adc = (payload[1] << 8) | payload[2] | |||
| break; | |||
| case 0x0A: | |||
| //测量完成 | |||
| let bodyData = plugin.getBodyData(1, 20, 170, this._weight, this._adc) // 体脂秤数据解析 | |||
| console.log("解析后的体脂数据: ", bodyData) | |||
| console.log(util.getWeightDisplay(170, this._weight)) | |||
| break; | |||
| } | |||
| const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId) | |||
| const data = {} | |||
| if (idx === -1) { | |||
| data[`chs[${this.data.chs.length}]`] = { | |||
| uuid: characteristic.characteristicId, | |||
| value: ab2hex(bleData.completeData, ' ') | |||
| } | |||
| } else { | |||
| data[`chs[${idx}]`] = { | |||
| uuid: characteristic.characteristicId, | |||
| value: ab2hex(bleData.completeData, ' ') | |||
| } | |||
| } | |||
| this.setData(data) | |||
| } else if (bleData.status == 2) { | |||
| console.log('A6-----^') | |||
| } | |||
| }) | |||
| }, | |||
| fail(res) { | |||
| console.error('getBLEDeviceCharacteristics', res) | |||
| } | |||
| }) | |||
| }, | |||
| writeBLECharacteristicValue(buffer, uuid, deviceId, serviceId) { | |||
| // 向蓝牙设备发送一个二进制流数据 | |||
| wx.writeBLECharacteristicValue({ | |||
| deviceId, | |||
| serviceId, | |||
| characteristicId: uuid, | |||
| value: buffer, | |||
| success(res) { | |||
| console.log('writeBLECharacteristicValue success', res) | |||
| console.log('下发指令==> ' + ab2hex(buffer)) | |||
| } | |||
| }) | |||
| }, | |||
| offBLECharacteristicValueChange() { | |||
| wx.offBLECharacteristicValueChange((res)=>{ | |||
| console.log(res) | |||
| }) | |||
| }, | |||
| closeBluetoothAdapter() { | |||
| wx.closeBluetoothAdapter() | |||
| this._discoveryStarted = false | |||
| }, | |||
| // 打开指令输入框 | |||
| showWriteInputView() { | |||
| this.setData({ | |||
| showWriteInput: true | |||
| }) | |||
| }, | |||
| // 关闭指令输入框 | |||
| hideWriteInputView() { | |||
| this.setData({ | |||
| showWriteInput: false | |||
| }) | |||
| }, | |||
| // 指令下发 | |||
| submitCmd(e, cmd) { | |||
| let arr = [] | |||
| let temp = [] | |||
| if (!cmd) { | |||
| cmd = this.data.cmd | |||
| } | |||
| console.log(cmd) | |||
| if(!cmd || !this.data.connected){ | |||
| return | |||
| } | |||
| if(cmd.indexOf(",") == -1){ | |||
| temp = cmd.split(" ") | |||
| } else { | |||
| temp = cmd.split(",") | |||
| } | |||
| let tempCmd = temp.join(' ') | |||
| for(let i = 0; i < temp.length; i++){ | |||
| arr[i] = parseInt(temp[i],16) | |||
| } | |||
| // let arr = [ | |||
| // 0xA6, | |||
| // 0x01, | |||
| // 0x28, | |||
| // 0x29, | |||
| // 0x6A, | |||
| // //A6 01 28 29 6A | |||
| // ] | |||
| if(arr[0] == 0xA6){ | |||
| let len = arr[1] | |||
| let payload = arr.slice(2, 2 + len) | |||
| plugin.sendDataOfA6(payload) | |||
| // let buff = new Uint8Array(arr).buffer | |||
| // this.writeBLECharacteristicValue(buff, this.uuid3, this._deviceId, this._serviceId) | |||
| } else if(arr[0] == 0xA7) { | |||
| let len = arr[3] | |||
| let payload = arr.slice(4, 4 + len) | |||
| plugin.sendDataOfA7(payload) | |||
| } | |||
| let historyList = wx.getStorageSync('historyList') || [] | |||
| let idx = historyList.findIndex(item => item.cmd == tempCmd) | |||
| if (idx < 0) { | |||
| historyList.push({cmd: tempCmd}) | |||
| } | |||
| this.setData({ | |||
| historyList | |||
| }) | |||
| wx.setStorage({ | |||
| data: historyList, | |||
| key: 'historyList', | |||
| }) | |||
| wx.showToast({ | |||
| title: '已发送', | |||
| icon: 'none' | |||
| }) | |||
| }, | |||
| history_delete(e) { | |||
| let index = e.currentTarget.dataset.index | |||
| this.data.historyList.splice(index, 1) | |||
| this.setData({ | |||
| historyList: this.data.historyList | |||
| }) | |||
| wx.setStorage({ | |||
| data: this.data.historyList, | |||
| key: 'historyList', | |||
| }) | |||
| }, | |||
| history_copy(e) { | |||
| let index = e.currentTarget.dataset.index | |||
| wx.setClipboardData({ | |||
| data: this.data.historyList[index].cmd | |||
| }) | |||
| }, | |||
| history_send(e) { | |||
| let index = e.currentTarget.dataset.index | |||
| let cmd = this.data.historyList[index].cmd | |||
| this.submitCmd(null, cmd) | |||
| }, | |||
| }); | |||
| @@ -0,0 +1,4 @@ | |||
| { | |||
| "usingComponents": { | |||
| } | |||
| } | |||
| @@ -0,0 +1,74 @@ | |||
| <wxs module="utils"> | |||
| module.exports.max = function(n1, n2) { | |||
| return Math.max(n1, n2) | |||
| } | |||
| module.exports.len = function(arr) { | |||
| arr = arr || [] | |||
| return arr.length | |||
| } | |||
| </wxs> | |||
| <view class="container"> | |||
| <view class="header"> | |||
| <button bindtap="openBluetoothAdapter" style="font-size: 32rpx;line-height:100rpx;width: 100%;">开始扫描</button> | |||
| <button bindtap="stopBluetoothDevicesDiscovery" style="font-size: 32rpx;line-height:100rpx;width: 100%;">停止扫描</button> | |||
| <button bindtap="closeBluetoothAdapter" style="font-size: 32rpx;line-height:100rpx;width: 100%;">结束流程</button> | |||
| </view> | |||
| <view class="devices_summary">已发现 {{devices.length}} 个外围设备:</view> | |||
| <scroll-view class="device_list" scroll-y scroll-with-animation> | |||
| <view wx:for="{{devices}}" wx:key="index" | |||
| data-device-id="{{item.deviceId}}" | |||
| data-name="{{item.name || item.localName}}" | |||
| data-mac="{{item.mac}}" | |||
| data-index="{{index}}" | |||
| bindtap="createBLEConnection" | |||
| class="device_item" | |||
| hover-class="device_item_hover"> | |||
| <view style="font-size: 32rpx;"> | |||
| <text style="color:#000;font-weight:bold">{{item.name}}</text> | |||
| <text style="font-size:26rpx">(信号强度: {{item.RSSI}}dBm)</text> | |||
| </view> | |||
| <view style="font-size: 26rpx">mac地址: {{item.macAddr || item.deviceId}}</view> | |||
| <!-- <view style="font-size: 10px">Service数量: {{utils.len(item.advertisServiceUUIDs)}}</view> --> | |||
| <view style="font-size: 26rpx">广播数据:{{item.analyzeDataText}}</view> | |||
| </view> | |||
| </scroll-view> | |||
| <view class="connected_info" wx:if="{{connected}}"> | |||
| <view> | |||
| <text>已连接到 {{name}}</text> | |||
| <view class="operation"> | |||
| <!-- <button wx:if="{{canWrite}}" size="mini" bindtap="writeBLECharacteristicValue">写数据</button> --> | |||
| <button size="mini" bindtap="showWriteInputView" style="line-height:54rpx; font-size:28rpx;padding:0 20rpx;margin-right:10rpx" wx:if="{{0}}">写入指令</button> | |||
| <button size="mini" bindtap="toConnectWifi" style="line-height:54rpx; font-size:28rpx;padding:0 20rpx;margin-right:10rpx">连接wifi</button> | |||
| <button size="mini" bindtap="closeBLEConnection" style="line-height:54rpx; font-size:28rpx;padding:0 20rpx;">断开连接</button> | |||
| </view> | |||
| </view> | |||
| <view wx:for="{{chs}}" wx:key="index" style="font-size: 26rpx; margin-top: 20rpx;"> | |||
| <view>特性值: {{item.value}}</view> | |||
| </view> | |||
| </view> | |||
| <view class="writeInputView" wx:if="{{showWriteInput}}"> | |||
| <view class="writeInput"> | |||
| <input type="text" model:value="{{cmd}}"></input> | |||
| </view> | |||
| <view class="hint">请输入16进制数,Byte之间用空格或英文逗号分隔</view> | |||
| <view class="btns"> | |||
| <button bindtap="submitCmd" style="line-height:70rpx; font-size:30rpx;padding:0 50rpx;margin-right:30rpx;">发送</button> | |||
| <button bindtap="hideWriteInputView" style="line-height:70rpx; font-size:30rpx;padding:0 50rpx;">取消</button> | |||
| </view> | |||
| <view class="history"> | |||
| <view class="history_title">历史记录:</view> | |||
| <scroll-view class="history_wrap" scroll-y="true"> | |||
| <view class="history_item" wx:for="{{historyList}}" wx:key="index"> | |||
| <view class="history_cmd">{{item.cmd}}</view> | |||
| <view class="history_btns"> | |||
| <button size="mini" bindtap="history_send" data-index="{{index}}" style="line-height:54rpx; font-size:24rpx;padding:0 30rpx;">发送</button> | |||
| <button size="mini" bindtap="history_delete" data-index="{{index}}" style="line-height:54rpx; font-size:24rpx;padding:0 30rpx;margin-left:20rpx">删除</button> | |||
| </view> | |||
| </view> | |||
| </scroll-view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| @@ -0,0 +1,143 @@ | |||
| page { | |||
| background: #f0f0f0; | |||
| color: #333; | |||
| } | |||
| .container{ | |||
| padding-bottom: 200rpx; | |||
| } | |||
| .header{ | |||
| width: 100%; | |||
| } | |||
| .container button{ | |||
| padding-top: 0; | |||
| padding-bottom: 0; | |||
| border: 1px solid #ddd; | |||
| } | |||
| .devices_summary { | |||
| width: 100%; | |||
| line-height: 70rpx; | |||
| padding: 0 30rpx; | |||
| margin-top: 30rpx; | |||
| font-size: 32rpx; | |||
| } | |||
| .device_list { | |||
| flex: 1; | |||
| width: 100%; | |||
| height: calc(100vh - 600rpx); | |||
| margin-top: 0; | |||
| border: 1px solid #fff; | |||
| border-radius: 5px; | |||
| background: #fff; | |||
| } | |||
| .device_item { | |||
| line-height: 1.5; | |||
| padding: 10rpx 30rpx; | |||
| border-bottom: 1px solid #EEE; | |||
| } | |||
| .device_item_hover { | |||
| background-color: rgba(0, 0, 0, .1); | |||
| } | |||
| .connected_info { | |||
| position: fixed; | |||
| bottom: 0; | |||
| width: 100%; | |||
| height: 200rpx; | |||
| padding: 10px; | |||
| border-top: 1px solid #ddd; | |||
| background-color: #fff; | |||
| font-size: 14px; | |||
| box-shadow: 0px -4rpx 4rpx 0px rgba(0,0,0,.05); | |||
| } | |||
| .connected_info .operation { | |||
| position: absolute; | |||
| display: inline-block; | |||
| right: 30rpx; | |||
| } | |||
| .writeInputViewBg{ | |||
| position: fixed; | |||
| top: 0; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 0; | |||
| z-index: 1000; | |||
| background-color: rgba(0,0,0,0.5); | |||
| } | |||
| .writeInputView{ | |||
| position: fixed; | |||
| bottom: 200rpx; | |||
| left: 0; | |||
| z-index: 1001; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| width: 100%; | |||
| height: calc(100vh - 500rpx); | |||
| background-color: #fff; | |||
| border-top: 1px solid #ddd; | |||
| } | |||
| .history{ | |||
| position: relative; | |||
| flex: 1; | |||
| width: 690rpx; | |||
| padding-top: 60rpx; | |||
| border: 1px solid #ddd; | |||
| margin: 30rpx; | |||
| } | |||
| .history_title{ | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| padding: 0 30rpx; | |||
| line-height: 60rpx; | |||
| font-size: 30rpx; | |||
| } | |||
| .history_wrap{ | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .history_item{ | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| width: 100%; | |||
| height: 72rpx; | |||
| padding: 0 30rpx; | |||
| border-top: 1px solid #ddd; | |||
| } | |||
| .history_cmd{ | |||
| flex: 1; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| white-space: nowrap; | |||
| font-size: 24rpx; | |||
| } | |||
| .history_btns{ | |||
| height: 60rpx; | |||
| overflow: hidden; | |||
| } | |||
| .writeInput{ | |||
| margin-top: 30rpx; | |||
| width: 690rpx; | |||
| height: 80rpx; | |||
| border: 1rpx solid #ccc; | |||
| } | |||
| .writeInput input{ | |||
| width: 100%; | |||
| height: 100%; | |||
| padding: 10rpx; | |||
| font-size: 32rpx; | |||
| } | |||
| .hint{ | |||
| padding-top: 10rpx; | |||
| font-size: 24rpx; | |||
| color: #999; | |||
| } | |||
| .btns{ | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| width: 60%; | |||
| padding-bottom: 30rpx; | |||
| margin-top: 30rpx; | |||
| } | |||
| @@ -0,0 +1,328 @@ | |||
| // pages/wifiList/wifiList.js | |||
| const util = require("../../utils/util"); | |||
| const { | |||
| ab2hex | |||
| } = util; | |||
| const plugin = requirePlugin("sdkPlugin").AiLink; | |||
| Page({ | |||
| /** | |||
| * 页面的初始数据 | |||
| */ | |||
| data: { | |||
| list: [], | |||
| wifi_connected: false, | |||
| conn_wifi: {}, | |||
| scanEnd: false, | |||
| totalAP: 0, | |||
| pwdModal: false, | |||
| pwdInput: '', | |||
| statusText: '', | |||
| statusList: ['', '', '已连接'] | |||
| }, | |||
| /** | |||
| * 生命周期函数--监听页面加载 | |||
| */ | |||
| onLoad: function (options) { | |||
| let pages = getCurrentPages() | |||
| this._home = pages[pages.length - 2] | |||
| wx.onBLECharacteristicValueChange((characteristic) => { | |||
| // 解析特征值,返回解密后的数据 | |||
| let bleData = plugin.parseBleData(characteristic.value) | |||
| // console.log(bleData) | |||
| if (bleData.status == 0) { | |||
| console.log("握手成功") | |||
| } else if (bleData.status == 1) { | |||
| console.log('A7-----^') | |||
| } else if (bleData.status == 2) { | |||
| console.log(bleData) | |||
| console.log('A6-----^') | |||
| let payload = bleData.data | |||
| const result = ['成功', '失败', '不支持'] | |||
| switch (payload[0]) { | |||
| case 0x26: { | |||
| console.log('状态改变') | |||
| let bleStatus = payload[1] & 0x0f | |||
| let wifiStatus = payload[1] >> 4 | |||
| const bleStatusList = ['无连接', '已连接', '配对完成'] | |||
| const wifiStatusList = ['未连接', '连接失败', '连接的WiFi信号不好', '连接成功', '正在连接'] | |||
| console.log('蓝牙状态:' + bleStatusList[bleStatus]) | |||
| console.log('WiFi状态:' + wifiStatusList[wifiStatus]) | |||
| this.setData({ | |||
| statusText: '蓝牙状态:' + bleStatusList[bleStatus] + ' ,WiFi状态:' + wifiStatusList[wifiStatus] | |||
| }) | |||
| break | |||
| } | |||
| case 0x80: { | |||
| wx.hideLoading() | |||
| wx.showToast({ | |||
| title: '扫描AP' + result[payload[1]], | |||
| icon: 'none' | |||
| }) | |||
| console.log('扫描AP' + result[payload[1]]) | |||
| break; | |||
| } | |||
| case 0x81: { | |||
| let id = payload[1] | |||
| console.log('上报WiFi名===>') | |||
| let nameArr = payload.slice(2) | |||
| console.log('原始数据===>' + ab2hex(nameArr, ' ')) | |||
| let name = nameArr.length ? util.hex2str(nameArr) : '' | |||
| if (name) { | |||
| console.log('WiFi名===>' + name) | |||
| let index = this.data.list.findIndex(item => item.name == name) | |||
| if (index < 0) { | |||
| this.data.list.push({ | |||
| id, | |||
| name, | |||
| }) | |||
| } else { | |||
| this.data.list[index].name = name | |||
| } | |||
| this.setData({ | |||
| list: this.data.list | |||
| }) | |||
| } | |||
| break; | |||
| } | |||
| case 0x82: { | |||
| console.log('上报WiFi信息-----^') | |||
| let id = payload[1] | |||
| let index = this.data.list.findIndex(item => item.id == id) | |||
| let addr = payload.slice(2, 8) | |||
| let signal = payload[8] | |||
| let type = payload[9] | |||
| let status = payload[10] | |||
| if (index < 0) { | |||
| // this.data.list.push({ | |||
| // id, | |||
| // addr, | |||
| // signal, | |||
| // type, | |||
| // status, | |||
| // }) | |||
| } else { | |||
| this.data.list[index].addr = addr | |||
| this.data.list[index].signal = signal | |||
| this.data.list[index].type = type | |||
| this.data.list[index].status = status | |||
| this.setData({ | |||
| list: this.data.list | |||
| }) | |||
| } | |||
| break; | |||
| } | |||
| case 0x83: | |||
| let num = payload[1] | |||
| console.log('上报扫描完毕-----^') | |||
| this.setData({ | |||
| totalAP: num, | |||
| scanEnd: true | |||
| }) | |||
| break; | |||
| case 0x84: { | |||
| console.log('设置地址' + result[payload[1]]) | |||
| wx.showToast({ | |||
| title: '设置地址' + result[payload[1]], | |||
| icon: 'none' | |||
| }) | |||
| // if (this._conn_wifi.status > 0) { | |||
| // this.connectWifi() | |||
| // } | |||
| break; | |||
| } | |||
| case 0x86: { | |||
| console.log('设置密码' + result[payload[1]]) | |||
| wx.showToast({ | |||
| title: '设置密码' + result[payload[1]], | |||
| icon: 'none' | |||
| }) | |||
| if (payload[1] === 0) { | |||
| this.connectWifi() | |||
| this.closeModal() | |||
| } | |||
| break; | |||
| } | |||
| case 0x88: { | |||
| console.log('设置 wifi 状态' + result[payload[1]]) | |||
| wx.showToast({ | |||
| title: '设置 wifi 状态' + result[payload[1]], | |||
| icon: 'none' | |||
| }) | |||
| if (payload[1] === 0) { | |||
| if (this.data.wifi_connected) { // true 建立连接, false 断开连接 | |||
| this.data.list.forEach(item=>{ | |||
| if (item.name === this._conn_wifi.name) { | |||
| item.status = 2 | |||
| } else if (item.status == 2) { | |||
| item.status = 1 | |||
| } | |||
| }) | |||
| } | |||
| this.setData({ | |||
| conn_wifi: this._conn_wifi, | |||
| wifi_connected: this.data.wifi_connected, | |||
| list: this.data.list | |||
| }) | |||
| } else { | |||
| this.setData({ | |||
| wifi_connected: !this.data.wifi_connected | |||
| }) | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| doSearch() { | |||
| let payload = [0x80, 0x01] | |||
| this.setData({ | |||
| scanEnd: false, | |||
| }) | |||
| wx.showLoading({ | |||
| title: '开始搜索', | |||
| }) | |||
| this.data.list = [] | |||
| plugin.sendDataOfA6(payload) | |||
| }, | |||
| tapItem(e) { | |||
| let index = e.currentTarget.dataset.index | |||
| let item = this.data.list[index] | |||
| console.log(item) | |||
| // 设置希望连接的 AP 地址 | |||
| let cmd = [0x84, ...item.addr] | |||
| plugin.sendDataOfA6(cmd) | |||
| this.showModal() | |||
| this._conn_wifi = item | |||
| }, | |||
| confirmPwd() { | |||
| if (!this.data.pwdInput || this.data.pwdInput.length < 8) { | |||
| wx.showToast({ | |||
| title: '密码有误', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| let pwdArr = util.str2hex(this.data.pwdInput) | |||
| if (pwdArr.length > 56) { | |||
| wx.showToast({ | |||
| title: '密码有误', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| if (pwdArr.length > 14) { // 超出14 byte 需分包 | |||
| console.log('密码超出14位===') | |||
| let pwdList = [] | |||
| let len = parseInt(pwdArr.length / 14) + 1 | |||
| for (let i = 0; i < len; i++) { | |||
| setTimeout(() => { | |||
| pwdList[i] = pwdArr.slice(i * 14, (i + 1) * 14) | |||
| let isEnd = +(i !== len - 1) | |||
| console.log(isEnd) | |||
| let cmd = [0x86, isEnd, ...pwdList[i]] | |||
| console.log(cmd) | |||
| plugin.sendDataOfA6(cmd) | |||
| }, 200 * i) | |||
| } | |||
| console.log(pwdArr) | |||
| console.log(pwdList) | |||
| } else { | |||
| // 设置希望连接的 AP 密码 | |||
| let cmd = [0x86, 0x00, ...pwdArr] | |||
| plugin.sendDataOfA6(cmd) | |||
| } | |||
| }, | |||
| connectWifi() { | |||
| // 发起 wifi 连接 | |||
| this.setData({ | |||
| wifi_connected: true | |||
| }) | |||
| let cmd = [0x88, 0x01] | |||
| plugin.sendDataOfA6(cmd) | |||
| }, | |||
| closeWifiConnection() { | |||
| // 断开 wifi 连接 | |||
| this.setData({ | |||
| wifi_connected: false | |||
| }) | |||
| let cmd = [0x88, 0x00] | |||
| plugin.sendDataOfA6(cmd) | |||
| }, | |||
| showModal() { | |||
| this.setData({ | |||
| pwdModal: true | |||
| }) | |||
| }, | |||
| closeModal() { | |||
| this.setData({ | |||
| pwdModal: false | |||
| }) | |||
| }, | |||
| stopAction() { | |||
| return false | |||
| }, | |||
| /** | |||
| * 生命周期函数--监听页面初次渲染完成 | |||
| */ | |||
| onReady: function () { | |||
| }, | |||
| /** | |||
| * 生命周期函数--监听页面显示 | |||
| */ | |||
| onShow: function () { | |||
| }, | |||
| /** | |||
| * 生命周期函数--监听页面隐藏 | |||
| */ | |||
| onHide: function () { | |||
| }, | |||
| /** | |||
| * 生命周期函数--监听页面卸载 | |||
| */ | |||
| onUnload: function () { | |||
| }, | |||
| /** | |||
| * 页面相关事件处理函数--监听用户下拉动作 | |||
| */ | |||
| onPullDownRefresh: function () { | |||
| }, | |||
| /** | |||
| * 页面上拉触底事件的处理函数 | |||
| */ | |||
| onReachBottom: function () { | |||
| }, | |||
| /** | |||
| * 用户点击右上角分享 | |||
| */ | |||
| onShareAppMessage: function () { | |||
| } | |||
| }) | |||
| @@ -0,0 +1,3 @@ | |||
| { | |||
| "usingComponents": {} | |||
| } | |||
| @@ -0,0 +1,40 @@ | |||
| <!--pages/wifiList/wifiList.wxml--> | |||
| <view class="container"> | |||
| <view class="header_button"> | |||
| <button bindtap="doSearch" style="font-size: 32rpx;line-height:100rpx;width: 100%;background:#fff">开始搜索WiFi</button> | |||
| </view> | |||
| <view class="wifi_title"> | |||
| <text>WiFi列表</text> | |||
| <text>-WiFi总数:{{list.length}}</text> | |||
| <view wx:if="{{0}}">扫描结束,本次扫描到WiFi数:{{totalAP}}</view> | |||
| </view> | |||
| <scroll-view scroll-y="true" class="wifi_list"> | |||
| <view class="wifi_item flex_center_sb" wx:for="{{list}}" wx:key='index' bindtap="tapItem" data-index="{{index}}" hover-class="item_hover"> | |||
| <view>{{item.name}}</view> | |||
| <view class="wifi_item_right">{{statusList[item.status]}}</view> | |||
| </view> | |||
| </scroll-view> | |||
| <view class="footer" wx:if="{{conn_wifi.id}}"> | |||
| <view> | |||
| <text>{{conn_wifi.name}} </text> | |||
| <text>{{wifi_connected?'已连接':'已断开连接'}}</text> | |||
| <view class="operation"> | |||
| <button size="mini" bindtap="connectWifi" style="line-height:54rpx; font-size:28rpx;padding:0 20rpx;margin-right:10rpx" wx:if="{{!wifi_connected}}">重新连接</button> | |||
| <button size="mini" bindtap="closeWifiConnection" style="line-height:54rpx; font-size:28rpx;padding:0 20rpx;">断开连接</button> | |||
| </view> | |||
| </view> | |||
| <view style="font-size: 26rpx; margin-top: 20rpx;" wx:if="{{statusText}}">{{statusText}}</view> | |||
| </view> | |||
| </view> | |||
| <view class="modal_wrapper {{pwdModal ? 'modal_wrapper_show': ''}}" catchtouchmove="stopAction"> | |||
| <view class="remindModal"> | |||
| <view class="remindModal_title">密码输入</view> | |||
| <view class="modal_input_wrap"> | |||
| <input model:value='{{pwdInput}}' class="modal_input" placeholder="请输入密码" placeholder-style="font-size:30rpx;color:#b4b4b4" /> | |||
| </view> | |||
| <view class="remindModal_btn"> | |||
| <view class="confirm_btn" bindtap="confirmPwd">确定</view> | |||
| <view class="remindModal_cancel_btn" bindtap="closeModal" hover-class="hover_tap">取消</view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| @@ -0,0 +1,142 @@ | |||
| /* pages/wifiList/wifiList.wxss */ | |||
| page{ | |||
| background: #f8f8f8; | |||
| } | |||
| .container{ | |||
| padding-bottom: 200rpx; | |||
| } | |||
| .container button{ | |||
| padding-top: 0; | |||
| padding-bottom: 0; | |||
| border: 1px solid #ddd; | |||
| } | |||
| .header_button{ | |||
| flex: 0 0 auto; | |||
| width: 100%; | |||
| } | |||
| .wifi_title{ | |||
| width: 100%; | |||
| padding: 40rpx 30rpx 20rpx; | |||
| line-height: 1.5; | |||
| } | |||
| .wifi_list{ | |||
| width: 100%; | |||
| height: calc(100vh - 400rpx); | |||
| border: 1px solid #ccc; | |||
| } | |||
| .wifi_item{ | |||
| height: 100rpx; | |||
| padding: 0 30rpx; | |||
| border-bottom: 1px solid #ddd; | |||
| background: #fff; | |||
| } | |||
| .wifi_item_right{ | |||
| color: #1977ff; | |||
| } | |||
| .footer { | |||
| position: fixed; | |||
| bottom: 0; | |||
| width: 100%; | |||
| height: 200rpx; | |||
| padding: 10px; | |||
| border-top: 1px solid #ddd; | |||
| background-color: #fff; | |||
| font-size: 14px; | |||
| box-shadow: 0px -4rpx 4rpx 0px rgba(0,0,0,.05); | |||
| } | |||
| .footer .operation { | |||
| position: absolute; | |||
| display: inline-block; | |||
| right: 30rpx; | |||
| } | |||
| .modal_wrapper{ | |||
| position: fixed; | |||
| top: 0; | |||
| left: 0; | |||
| right: 0; | |||
| z-index: -1; | |||
| background: rgba(0,0,0,0.5); | |||
| transition: .4s all; | |||
| height: 200vh; | |||
| opacity: 0; | |||
| } | |||
| .modal_wrapper_show{ | |||
| transform: translateY(-100vh); | |||
| opacity: 1; | |||
| overflow-x: hidden; | |||
| overflow-y: auto; | |||
| z-index: 1000; | |||
| } | |||
| .remindModal{ | |||
| position: absolute; | |||
| bottom: 50vh; | |||
| left: 50%; | |||
| z-index: 101; | |||
| transform: translate(-50%, 50%); | |||
| background: #fff; | |||
| width: 600rpx; | |||
| padding: 40rpx 60rpx; | |||
| border-radius: 20rpx; | |||
| } | |||
| .remindModal_title{ | |||
| padding: 10rpx 30rpx 50rpx; | |||
| text-align: center; | |||
| font-size: 32rpx; | |||
| } | |||
| .remindModal_content{ | |||
| font-size: 30rpx; | |||
| line-height: 1.6; | |||
| text-align: center; | |||
| padding-top: 30rpx; | |||
| min-height: 100rpx; | |||
| } | |||
| .remindModal_btn{ | |||
| margin-top: 80rpx; | |||
| margin-bottom: 10rpx; | |||
| } | |||
| .remindModal_cancel_btn{ | |||
| margin-top: 30rpx; | |||
| height: 80rpx; | |||
| line-height: 80rpx; | |||
| text-align: center; | |||
| color: #FA1111; | |||
| font-size: 30rpx; | |||
| } | |||
| .modal_input_wrap{ | |||
| width: 100%; | |||
| height: 80rpx; | |||
| padding: 0 10rpx; | |||
| border: 1px solid #dcdcdc; | |||
| border-radius: 10rpx; | |||
| } | |||
| .modal_input{ | |||
| width: 100%; | |||
| height: 100%; | |||
| padding: 10rpx; | |||
| font-size: 30rpx; | |||
| } | |||
| .confirm_btn{ | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| width: 480rpx; | |||
| height: 100rpx; | |||
| border: 1px solid transparent; | |||
| margin: auto; | |||
| background: #1977FF; | |||
| color: #fff; | |||
| font-size: 16px; | |||
| letter-spacing: 2rpx; | |||
| border-radius: 1000rpx; | |||
| white-space: nowrap; | |||
| } | |||
| .item_hover{ | |||
| background-color: rgba(0, 0, 0, .1); | |||
| } | |||
| @@ -0,0 +1,73 @@ | |||
| { | |||
| "description": "项目配置文件", | |||
| "packOptions": { | |||
| "ignore": [] | |||
| }, | |||
| "setting": { | |||
| "urlCheck": true, | |||
| "es6": true, | |||
| "enhance": true, | |||
| "postcss": true, | |||
| "preloadBackgroundData": false, | |||
| "minified": true, | |||
| "newFeature": false, | |||
| "coverView": true, | |||
| "nodeModules": false, | |||
| "autoAudits": false, | |||
| "showShadowRootInWxmlPanel": true, | |||
| "scopeDataCheck": false, | |||
| "uglifyFileName": false, | |||
| "checkInvalidKey": true, | |||
| "checkSiteMap": true, | |||
| "uploadWithSourceMap": true, | |||
| "compileHotReLoad": true, | |||
| "useMultiFrameRuntime": true, | |||
| "useApiHook": true, | |||
| "useApiHostProcess": false, | |||
| "babelSetting": { | |||
| "ignore": [], | |||
| "disablePlugins": [], | |||
| "outputPath": "" | |||
| }, | |||
| "enableEngineNative": false, | |||
| "bundle": false, | |||
| "useIsolateContext": true, | |||
| "useCompilerModule": true, | |||
| "userConfirmedUseCompilerModuleSwitch": false, | |||
| "userConfirmedBundleSwitch": false, | |||
| "packNpmManually": false, | |||
| "packNpmRelationList": [], | |||
| "minifyWXSS": true | |||
| }, | |||
| "compileType": "miniprogram", | |||
| "libVersion": "2.16.0", | |||
| "appid": "wx17e93aad47cdae1a", | |||
| "projectname": "wifi_ble_demo", | |||
| "debugOptions": { | |||
| "hidedInDevtools": [] | |||
| }, | |||
| "scripts": {}, | |||
| "isGameTourist": false, | |||
| "simulatorType": "wechat", | |||
| "simulatorPluginLibVersion": {}, | |||
| "condition": { | |||
| "search": { | |||
| "list": [] | |||
| }, | |||
| "conversation": { | |||
| "list": [] | |||
| }, | |||
| "game": { | |||
| "list": [] | |||
| }, | |||
| "plugin": { | |||
| "list": [] | |||
| }, | |||
| "gamePlugin": { | |||
| "list": [] | |||
| }, | |||
| "miniprogram": { | |||
| "list": [] | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,7 @@ | |||
| { | |||
| "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", | |||
| "rules": [{ | |||
| "action": "allow", | |||
| "page": "*" | |||
| }] | |||
| } | |||
| @@ -0,0 +1,47 @@ | |||
| function inArray(arr, key, val) { | |||
| if (!arr || !arr.length || typeof arr != 'object' || !Array.isArray(arr)) { | |||
| return -1 | |||
| } | |||
| for (let i = 0; i < arr.length; i++) { | |||
| if (!key) { | |||
| if (arr[i] == val) { | |||
| return i | |||
| } | |||
| } else if (arr[i][key] === val) { | |||
| return i | |||
| } | |||
| } | |||
| return -1; | |||
| } | |||
| // ArrayBuffer转16进度字符串示例 | |||
| function ab2hex(buffer, split) { | |||
| var hexArr = Array.prototype.map.call( | |||
| new Uint8Array(buffer), | |||
| function (bit) { | |||
| return ('00' + bit.toString(16)).slice(-2) | |||
| } | |||
| ) | |||
| return hexArr.join(split); | |||
| } | |||
| const {TextDecoder, TextEncoder} = require('./encoding') | |||
| function hex2str(arr) { | |||
| let decoder = new TextDecoder('utf8') | |||
| let uint8 = new Uint8Array(arr) | |||
| let res = decoder.decode(uint8) | |||
| return res | |||
| } | |||
| function str2hex(str) { | |||
| let encoder = new TextEncoder('utf8') | |||
| return encoder.encode(str) | |||
| } | |||
| module.exports = { | |||
| inArray, | |||
| ab2hex, | |||
| hex2str, | |||
| str2hex, | |||
| } | |||