import modal from "@/utils/modal";
import {
mapState
} from "vuex";
import skeyTool from "@/utils/skeyTool";
import utils from "@/utils/utils";
export default {
data() {
return {
connectTime: null,
isIos: false, //ios特殊处理
isOpenBluebooth: false,
isOpenSetting: false,//检测蓝牙未打开 跳转蓝牙设置页
userLocation: true,//判断Android机型下是否授权了地理位置
bleAdapterState: false,//蓝牙适配器状态
}
},
mounted() {
const systemInfo = wx.getSystemInfoSync();
if (/iPhone/.test(systemInfo.model)) {
this.isIos = true;
}
//针对Android 部分机型需要地理位置授权
// wx.getSetting({
// success(res) {
// if (!this.isIos && !res.authSetting['scope.userLocation']) {
// wx.authorize({
// scope: 'scope.userLocation',
// success(res) {
// console.log('authorize', 'success');
// },
// fail() {
// this.userLocation = false
// console.log('authorize', 'fail');
// }
// })
// }
// }
// })
},
methods: {
//用户授权信息判断
getSetting() {
let _that = this
try {
wx.getSetting({
withSubscriptions: true,
success(res) {
if (res.authSetting['scope.bluetooth']) {
_that.initBlueTooth()
} else {
if (_that.$refs["setBlueRef"]) _that.$refs["setBlueRef"].hide();
modal.toast('您拒绝了蓝牙授权')
_that.closeBlueTooth()
}
}
})
} catch (error) {
// console.log(error, 'getSetting');
throw error
}
},
// 打开手机蓝牙功能
setBlueTooth() {
this.isOpenSetting = true
//ios特殊处理
if (this.isIos) {
try {
wx.openAppAuthorizeSetting({
success: (res) => {
this.isOpenBluebooth = true
// console.log('您拒绝了蓝牙授权', res);
if (this.$refs["setBlueRef"]) this.$refs["setBlueRef"].hide();
},
fail: (res) => {
this.isOpenBluebooth = false
},
});
} catch (error) {
throw error
}
} else {
//安卓手机打开蓝牙设置页面
try {
wx.openSystemBluetoothSetting({
success: (data) => {
this.isOpenBluebooth = true
if (this.$refs["setBlueRef"]) this.$refs["setBlueRef"].hide();
},
fail: (err) => {
this.isOpenBluebooth = false
},
});
} catch (error) {
throw error
}
}
},
//---------------------step1------------------------
// 判断是否打开了蓝牙
async initBlueTooth() {
let _that = this;
await this.$refs["privacyModal"].show();
try {
wx.openBluetoothAdapter({
mode: "central",
success: function (res) {
// 蓝牙已打开直接扫码
// 获取蓝牙适配器状态
_that.isOpenBluebooth = true
_that.getBluetoothAdapter();
},
fail: function (res) {
if (res.errCode == 10001) {
uni.hideToast()
if (_that.$refs["setBlueRef"]) return _that.$refs["setBlueRef"].show();
}
_that.isOpenBluebooth = false
_that.getSetting()
},
});
} catch (error) {
throw error
}
},
//-----------------------step1 end-------------------
//------------------------step4-------------------
//获取本机蓝牙适配器状态
//检测本机蓝牙是否可用
async getBluetoothAdapter() {
let _that = this;
try {
//获取本机蓝牙适配器状态
wx.getBluetoothAdapterState({
success: function (res2) {
// console.log('getBluetoothAdapterState', res2);
//跳转到手机系统蓝牙设置页后回到此页面监听蓝牙是否打开
if (!res2.available && _that.isOpenSetting) {
_that.isOpenSetting = false
_that.bleAdapterState = false
modal.toast('蓝牙未打开')
return
}
if (res2.errMsg == "getBluetoothAdapterState:ok") {
//搜寻附近的蓝牙设备
uni.showLoading({
title: "连接设备蓝牙中",
mask: true,
});
_that.startBluetoothDevices();
_that.isOpenSetting = false
_that.bleAdapterState = true
}
},
fail: function (res2) {
if (_that.isOpenSetting)
uni.hideLoading();
},
});
} catch (error) {
throw error
// console.log(error, "getBluetoothAdapterState");
}
},
//------------------------step4 end-------------------
//------------------------- step5----------------------
//开始搜寻附近的蓝牙外围设备。
async startBluetoothDevices() {
let _that = this;
try {
wx.startBluetoothDevicesDiscovery({
success: function (res) {
if (res.errCode == 0) {
// 监听寻找到新设备的事件
_that.onBluetoothDevice();
}
console.log('startBluetoothDevicesDiscovery', res
);
},
fail: function (res) {
if (res.errCode < 0 && res.errMsg.includes('location')) {
uni.hideToast()
uni.hideLoading()
modal.toast('请开启微信定位授权')
return
}
console.log(res, 'startBluetoothDevicesDiscovery');
if (res.errCode > 1) modal.toast("连接失败");
// if (_that.connectTime) clearTimeout(_that.connectTime);
// _that.connectTime = null;
},
});
} catch (error) {
// console.log(error, "startBluetoothDevicesDiscovery");
throw error
}
},
//------------------------- step5 end----------------
//----------------step6-------------------
//监听寻找到新设备的事件
async onBluetoothDevice() {
let _that = this;
/**
advertisData ArrayBuffer 当前蓝牙设备的广播数据段中的 ManufacturerData 数据段。
advertisServiceUUIDs Array.<string> 当前蓝牙设备的广播数据段中的 ServiceUUIDs 数据段
localName string 当前蓝牙设备的广播数据段中的 LocalName 数据段
serviceData Object 当前蓝牙设备的广播数据段中的 ServiceData 数据段
connectable boolean 当前蓝牙设备是否可连接( Android 8.0 以下不支持返回该值 )
*/
try {
wx.onBluetoothDeviceFound((res) => {
res.devices.length &&
res.devices.forEach((device) => {
//https://developers.weixin.qq.com/miniprogram/dev/api/device/bluetooth/wx.onBluetoothDeviceFound.html
//这里要求柜机外围设备发送ManufacturerData 数据段 (advertisData ArrayBuffer数据类型)
if (device.deviceId && device.advertisData && device.localName) {
let deviceId = _that.hex2ab(device.advertisData);
// 确保蓝牙设备中的advertisData字段有数据
if (deviceId) {
//转换后多了一个P 字符?
let new_sim = deviceId.substr(
deviceId.length - 15,
deviceId.length
);
if (_that.sim == new_sim) {
_that.deviceId = device.deviceId;
//筛选完成,连接蓝牙 先连接蓝牙后停止搜寻附近的蓝牙设备
_that.stopBluetooth()
setTimeout(() => {
_that.createBLEConnectionFn(device.deviceId);
}, 400)
}
}
}
});
});
} catch (error) {
uni.hideLoading();
_that.stopBluetooth();
throw error
}
},
//------------------step6 end-----------------------
//-----------------------step7-----------------------
//连接蓝牙
async createBLEConnectionFn() {
let _that = this;
try {
//连接蓝牙前先关闭已连接蓝牙
wx.createBLEConnection({
deviceId: _that.deviceId,
success: function (res) {
//获取连接设备的service服务
_that.getBLEDeviceServicesFn(_that.deviceId);
uni.hideLoading();
uni.showToast({
title: "连接设备蓝牙成功",
icon: "success",
mask: true,
});
_that.currentIndex = 1;
_that.connectSuccess = true
_that.connectFlag = true;
//监听蓝牙关闭
wx.onBLEConnectionStateChange(function (res) {
if (!res.connected) {
uni.hideLoading()
_that.connectFlag = false
_that.isConnectIng = false
_that.showLoading = false
_that.connectSuccess = false
// console.log('设备已断开蓝牙连接');
modal.toast("设备已断开蓝牙连接");
if (_that.$refs["paging"]) {
_that.$refs["paging"].scrollToTop();
_that.$refs["paging"].complete();
}
}
});
},
fail: function (res) {
console.log(res, 'createBLEConnection');
_that.stopBluetooth();
uni.hideLoading();
uni.showToast({
title: "连接蓝牙失败",
icon: "error",
mask: true,
});
_that.connectSuccess = false
if (_that.$refs["paging"]) {
_that.$refs["paging"].scrollToTop();
_that.$refs["paging"].complete();
}
},
});
} catch (error) {
throw error
}
},
//----------------------step7 end--------------------------
//---------------------step8----------------------
//获取连接设备的service服务
async getBLEDeviceServicesFn(deviceId) {
let _that = this;
try {
wx.getBLEDeviceServices({
deviceId: _that.deviceId,
success: function (res) {
for (let i = 0; i < res.services.length; i++) {
if (res.services[i].isPrimary) {
_that.serviceId = res.services[i].uuid;
//获取连接设备的所有特征值
_that.getBLEDevice(
deviceId,
res.services[i].uuid
);
}
}
},
fail: function (res) {
// console.log("获取蓝牙失败", res);
},
});
} catch (error) {
throw error
}
},
//-----------------------step8 end----------------------
//-----------------------step 9---------------------
//获取连接设备的所有特征值
async getBLEDevice(deviceId, serviceId) {
let _that = this;
try {
wx.getBLEDeviceCharacteristics({
deviceId: deviceId,
serviceId: serviceId,
success: function (res) {
if (res.errCode == 0) {
let characteristicId = res.characteristics;
for (var i = 0; i < res.characteristics.length; i++) {
if (res.characteristics[i].properties.write) {
_that.characteristicId = characteristicId[i]["uuid"];
//确保设备能够写入数据
let str = "xx" + _that.sim + "ok";
_that.writeBLECharacteristic(str);
//启用低功耗蓝牙设备特征值变化时的 notify 功能
setTimeout(() => {
_that.notifyBLECharacteristic(
deviceId,
serviceId,
characteristicId[i]["uuid"]
);
}, 500);
//设备详情 与终端确定 切换仅4G模式相当于清空WiFi配置
// 没有WiFi列表数据主动获取一次
if (_that.wifiList) {
if (!_that.wifiList.length) _that.getWifiList()
}
// 设置详情页面通过蓝牙清空WiFi配置
if (_that.isClearWifiConf) {
setTimeout(() => {
_that.clearWrite()
}, 500)
}
}
}
} else {
// console.log("获取特征值失败");
// modal.toast("获取特征值失败");
}
},
});
} catch (error) {
throw error
}
},
//---------------------------step11------------------------
//启用低功耗蓝牙设备特征值变化时的 notify 功能
async notifyBLECharacteristic(
deviceId,
serviceId,
characteristicId
) {
let _that = this;
try {
wx.notifyBLECharacteristicValueChange({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: characteristicId,
state: true,
success: function (res) {
// console.log("启用低功耗蓝牙设备特征值变化时的 notify 功能", res);
/*用来监听手机蓝牙设备的数据变化*/
_that.onBLECharacteristic();
_that.watchBleConnectionState()
},
fail: function (res) {
modal.toast('启用notify失败')
},
});
} catch (error) {
modal.toast('启用notify失败')
// console.log(error, "notifyBLECharacteristicValueChange");
throw error
}
},
//--------------------------------ste11 end--------------------
//--------------------------------step12 ----------------------
onBLECharacteristic() {
let _that = this;
try {
wx.onBLECharacteristicValueChange(function (res) {
let flag = _that.hex2ab(res.value); //针对WiFi列表发送完成
console.log('通过hex2ab解析的数据', flag);
console.log(res, res.value, 'onBLECharacteristic');
if (_that.sendIngWifi) {
if (flag === "sendWifiListOK") {
_that.connectFlag = true;
uni.hideLoading()
_that.stopSendWifi();
_that.sendIngWifi = false;
_that.initWifiList(_that.wifiListStr);
} else {
let val = _that.str2abEmpty(res.value);
_that.wifiListStr += val;
console.log('通过str2abEmpty解析的数据', val,);
}
}
//当前WiFi连接成功后会切换模式
if (flag == "WifiConnectOK") {
_that.connectFlag = true;
//控制设备连接WiFi成功
_that.isConnectIng = false
} else if (flag == "WifiConnectFailed") {
uni.showToast({
title: "WiFi连接失败",
icon: "error",
mask: true,
});
_that.isConnectIng = false
}
});
} catch (error) {
// console.log(error, 'onBLECharacteristic');
uni.hideLoading()
modal.toast('监听notify失败')
throw error
}
},
//--------------------------------step12end----------------------
// 获取要写入蓝牙设备的值
writeBLECharacteristic(val) {
let _that = this;
let buffer = _that.string2ArrayBuffer(val);
try {
wx.writeBLECharacteristicValue({
deviceId: _that.deviceId,
serviceId: _that.serviceId,
characteristicId: _that.characteristicId,
value: buffer,
// writeType: "write",
success: function (res) {
},
fail: function (err) {
uni.hideLoading()
if (_that.showLoading) _that.showLoading = false
modal.toast("写入数据失败");
if (_that.$refs["paging"]) {
_that.$refs["paging"].scrollToTop();
_that.$refs["paging"].complete();
}
},
});
} catch (error) {
uni.hideLoading()
modal.toast("写入数据失败");
if (_that.showLoading) _that.showLoading = false;
throw error
}
},
async stopBluetooth() {
let _that = this
try {
wx.stopBluetoothDevicesDiscovery({
success: (result) => {
if (_that.$refs["paging"]) {
_that.$refs['paging'].scrollToTop()
_that.$refs["paging"].complete()
}
},
fail: (error) => {
console.log("停止搜寻附近的蓝牙外围设备失败", error);
},
});
} catch (error) {
// console.log('stopBluetooth', error);
throw error
}
},
// 字符串转ArrayBuffer
string2ArrayBuffer(str) {
try {
var bytes = new Array();
var len, c;
len = str.length;
for (var i = 0; i < len; i++) {
c = str.charCodeAt(i);
if (c >= 0x010000 && c <= 0x10ffff) {
bytes.push(((c >> 18) & 0x07) | 0xf0);
bytes.push(((c >> 12) & 0x3f) | 0x80);
bytes.push(((c >> 6) & 0x3f) | 0x80);
bytes.push((c & 0x3f) | 0x80);
} else if (c >= 0x000800 && c <= 0x00ffff) {
bytes.push(((c >> 12) & 0x0f) | 0xe0);
bytes.push(((c >> 6) & 0x3f) | 0x80);
bytes.push((c & 0x3f) | 0x80);
} else if (c >= 0x000080 && c <= 0x0007ff) {
bytes.push(((c >> 6) & 0x1f) | 0xc0);
bytes.push((c & 0x3f) | 0x80);
} else {
bytes.push(c & 0xff);
}
}
var array = new Int8Array(bytes.length);
for (var i in bytes) {
array[i] = bytes[i];
}
return array.buffer;
} catch (error) {
uni.hideLoading()
modal.toast('解析ArrayBuffer失败~')
// console.log(error, 'string2ArrayBuffer');
throw error
}
},
//ArrayBuffer 转字符串
str2ab(arrayBuffer) {
try {
let unit8Arr = new Uint8Array(arrayBuffer);
let encodedString = String.fromCharCode.apply(null, unit8Arr);
let decodedString = decodeURIComponent(escape(encodedString)); //没有这一步中文会乱码
return decodedString;
} catch (error) {
//抛出异常不管了
// console.log(error, 'str2ab');
uni.hideLoading()
modal.toast('解析数据失败~str2ab')
return false;
}
},
hex2ab(str) {
try {
return String.fromCharCode.apply(null, new Uint8Array(str));
} catch (error) {
uni.hideLoading()
modal.toast('解析数据失败~hex2ab')
// console.log(error, 'hex2ab');
throw error
}
},
//16进制ArrayBuffer 转字符串 不去掉 \n
str2abEmpty(arrayBuffer) {
try {
let str = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer));
let ret = str.replace(/\n/g, "/n"); //将\n标记为/n
return ret;
} catch (error) {
uni.hideLoading()
modal.toast('解析数据失败~')
throw error
}
},
// 16进制(byte格式)转字符串
hexToString(str) {
try {
let res = str.replace(/\\x/g, "%");
let result = decodeURIComponent(res, "utf-8");
return result;
} catch (error) {
uni.hideLoading()
modal.toast('解析WiFi数据失败')
setTimeout(() => {
this.currentIndex = 0
}, 1000);
this.$store.commit('submitErrorLog', {
error_type: "handlerError",
url: 'bluebooth.hexToString',
param: { wifiListStr: this.wifiListStr },
timeout: '0',
epukey: skeyTool.getSkey(),
datetime: utils.formatTime(new Date()),
err_code: '200'
})
throw error
}
},
async closeBlueTooth() {
try {
if (this.connectFlag) {
wx.closeBLEConnection({
deviceId: this.deviceId,
success(res) {
console.log('closeBLEConnection', res);
},
fail(err) {
console.log(err, 'closeBlueTooth', 'fail')
},
})
}
} catch (error) {
throw error
}
},
watchBleConnectionState() {
try {
wx.onBLEConnectionStateChange((res) => {
if (!res?.connected) {
uni.hideLoading()
modal.toast('设备已断开蓝牙连接')
}
})
} catch (error) {
throw error
}
},
//清空倒计时、重置蓝牙功能相关数据配置
//关闭蓝牙相关操作
handlerCloese() {
//关闭蓝牙模块。
wx.closeBluetoothAdapter({
success: (res) => {
console.log('closeBluetoothAdapter', res);
},
fail: (err) => {
console.log('closeBluetoothAdapter', err);
}
});
// 移除搜索到新设备的事件的全部监听函数
uni.hideLoading();
uni.hideToast();
}
},
beforeDestroy() {
this.handlerCloese()
},
//针对蓝牙打开手机自带蓝牙设置页面 返回到当前页面 特殊处理
onShow() {
setTimeout(() => {
if (this.isOpenSetting) this.getBluetoothAdapter()
}, 500)
},
computed: {
...mapState(["privacyFlag", 'needPrivacy']),
},
}
安卓端、iOS端 多次写入数据wx.writeBLECharacteristicValue 偶现wx.onBLECharacteristicValueChange无回调 有时候收到第一条数据后后面无回调 有时候是接收到了硬件方发送的一半数据 硬件方始终是20字节 我这边也没有超过20字节 这里的wifiListStr我会在设备端发送给我sendWifiListOK之后重新解析一遍 当前这个代码是当做一个mixins使用的 frequency signal 是硬件发送的自定义数据(第一条数据),后面就没执行了也没报错 返回上个页面关闭了蓝牙适配器
解决了吗