支付宝微信小程序连接蓝牙兼容IOS和安卓(开源)
1. 前言
最近被支付宝的蓝牙和IOS的蓝牙整破防了,太多兼容性问题,磕磕绊绊终于把支付宝小程序和微信小程序的蓝牙问题给解决了。该方案完美解决
- 安卓微信小程序
- IOS微信小程序
- 安卓支付宝小程序
- IOS支付宝小程序
的蓝牙连接问题
2. 解决思路
因为支付宝和微信的api不同,收到消息后解析也有所差别,所以对支付宝和微信编写两份APIJS文件,如果业务只涉及单边的蓝牙连接,就只需要引入所需的js即可。
另外IOS和安卓也略有不同,不通型号的手机可发送字节也不同,这都是踩坑才出来的,一把辛酸泪。
3. 微信API文件
新建BLEWX.js文件
/** * 微信连接蓝牙API * @author RedEric * @date 2023年9月6日 */ const logEnable = false let isAndroid = false let BluetoothAdapterStateChangeCallback = () => {} let BLEConnectionStateChangeCallback = () => {} let DeviceId = '' let GattServerUUID = '' const GattServerUUIDOption1 = '0000FFF0-0000-1000-8000-00805F9B34FB' const GattServerUUIDOption2 = 'FFF0' let GattCharacteristicWriteUUID = '' const GattCharacteristicWriteUUIDOption1 = '0000FFF2-0000-1000-8000-00805F9B34FB' const GattCharacteristicWriteUUIDOption2 = 'FFF2' const log = data => { if (logEnable) { console.log('[eciot]:' + JSON.stringify(data)) } } const onBluetoothAdapterStateChange = cb => { BluetoothAdapterStateChangeCallback = cb } const getSetting = () => { return new Promise(function (resolve, reject) { wx.getSetting({ success(res) { log(res) if (res.authSetting && res.authSetting['scope.bluetooth']) { resolve({ ok: true, errCode: 0, errMsg: '' }) } else { resolve({ ok: false, errCode: 30001, errMsg: 'getSetting fail', }) } }, fail(res) { log(res) resolve({ ok: false, errCode: res.errCode ? res.errCode : 30000, errMsg: res.errMsg ? res.errMsg : 'getSetting fail', }) }, }) }) } const authorize = () => { return new Promise(function (resolve, reject) { wx.authorize({ scope: 'scope.bluetooth', success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) // {"errMsg":"authorize:fail:auth deny"} resolve({ ok: false, errCode: 30000, errMsg: res.errMsg }) }, }) }) } const _openBluetoothAdapter = () => { return new Promise(function (resolve, reject) { wx.openBluetoothAdapter({ success(res) { log(res) // {errno: 0, errMsg: "openBluetoothAdapter:ok"} resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.errCode ? res.errCode : 30000, errMsg: res.errMsg, }) }, }) }) } const openBluetoothAdapter = async () => { await _openBluetoothAdapter() const systemInfo = wx.getSystemInfoSync() log(systemInfo) if (systemInfo.platform.toLowerCase() === 'android') { isAndroid = true } if (!systemInfo.bluetoothEnabled) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30001, errMsg: '请打开系统蓝牙开关', }) return } if (isAndroid && !systemInfo.locationEnabled) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30002, errMsg: '请打开系统定位开关', }) return } if (isAndroid && !systemInfo.locationAuthorized) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30003, errMsg: '请打开微信定位权限,允许微信使用您的位置信息', }) return } const setting = await getSetting() //小程序蓝牙权限 if (!setting.ok) { const authRes = await authorize() if (!authRes.ok) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30004, errMsg: '请打开小程序蓝牙开关,点击右上角三个点,然后点击设置', }) return } } wx.offBluetoothAdapterStateChange() wx.onBluetoothAdapterStateChange(res => { log(res) // {available: true, discovering: true} if (!res.available) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30005, errMsg: '蓝牙适配器不可用', }) } }) const openRes = await _openBluetoothAdapter() BluetoothAdapterStateChangeCallback(openRes) } const onBluetoothDeviceFound = cb => { wx.offBluetoothDeviceFound() wx.onBluetoothDeviceFound(res => { log(res) const device = res.devices[0] const name = device.name ? device.name : device.localName if (!name) { return } let id = device.deviceId let rssi = device.RSSI cb({ id, name, rssi }) }) } const startBluetoothDevicesDiscovery = () => { wx.startBluetoothDevicesDiscovery({ //services: [ecServerId], allowDuplicatesKey: true, powerLevel: 'high', complete(res) { log(res) }, }) } const stopBluetoothDevicesDiscovery = () => { wx.stopBluetoothDevicesDiscovery({ complete(res) { // {errno: 0, errMsg: "stopBluetoothDevicesDiscovery:ok", isDiscovering: false} log(res) }, }) } const onBLEConnectionStateChange = cb => { BLEConnectionStateChangeCallback = cb } const _createBLEConnection = () => { return new Promise(function (resolve, reject) { wx.createBLEConnection({ deviceId: DeviceId, success(res) { log(res) // {"errno":0,"errCode":0,"errMsg":"createBLEConnection:ok"} resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) // {"errno":1001,"errMsg":"createBLEConnection:fail parameter error: parameter.deviceId should be String instead of Undefined;"} resolve({ ok: false, errCode: res.errCode ? res.errCode : res.errno, errMsg: res.errMsg, }) }, }) }) } const getBLEDeviceServices = () => { return new Promise(function (resolve, reject) { wx.getBLEDeviceServices({ deviceId: DeviceId, success(res) { log(res) //{"services":[{"uuid":"0000FFF0-0000-1000-8000-00805F9B34FB","isPrimary":true}],"errCode":0,"errno":0,"errMsg":"getBLEDeviceServices:ok"} // {"errno":0,"deviceId":"7C7E20F2-CB75-6DA8-F8DF-FFF702B0D63F","services":[{"isPrimary":true,"uuid":"0000FFF0-0000-1000-8000-00805F9B34FB"}],"errMsg":"getBLEDeviceServices:ok","errCode":0} resolve({ ok: true, errCode: 0, errMsg: '', services: res.services, }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg }) }, }) }) } const getBLEDeviceCharacteristics = serviceId => { return new Promise(function (resolve, reject) { wx.getBLEDeviceCharacteristics({ deviceId: DeviceId, serviceId, success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '', characteristics: res.characteristics, }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg }) }, }) }) } const notifyBLECharacteristicValueChange = (serviceId, characteristicId) => { return new Promise(function (resolve, reject) { wx.notifyBLECharacteristicValueChange({ state: true, deviceId: DeviceId, serviceId, characteristicId, success(res) { log(res) // {"errCode":0,"errno":0,"errMsg":"notifyBLECharacteristicValueChange:ok"} resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg }) }, }) }) } const setBLEMTU = mtu => { return new Promise(function (resolve, reject) { wx.setBLEMTU({ deviceId: DeviceId, mtu, success(res) { log(res) // {"errMsg":"setBLEMTU:ok","errno":0,"errCode":0,"mtu":50} resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) // {"errCode":-1,"errno":1500104,"errMsg":"setBLEMTU:fail:internal error"} resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg }) }, }) }) } //和设备建立连接 const createBLEConnection = async id => { DeviceId = id wx.offBLEConnectionStateChange() wx.onBLEConnectionStateChange(async res => { log(res) // {"deviceId":"EC:22:05:13:78:49","connected":true} if (res.connected) { const servicesResult = await getBLEDeviceServices() if (!servicesResult.ok) { BLEConnectionStateChangeCallback(servicesResult) closeBLEConnection() return } for (const service of servicesResult.services) { if ((service.uuid.toUpperCase() === GattServerUUIDOption1) || (service.uuid.toUpperCase() === GattServerUUIDOption2)) { GattServerUUID = service.uuid } const characteristicsResult = await getBLEDeviceCharacteristics( service.uuid ) if (!characteristicsResult.ok) { BLEConnectionStateChangeCallback(characteristicsResult) closeBLEConnection() return } for (const characteristic of characteristicsResult.characteristics) { if ( characteristic.properties && characteristic.properties.notify ) { const notifyResult = await notifyBLECharacteristicValueChange( service.uuid, characteristic.uuid ) if (!notifyResult.ok) { BLEConnectionStateChangeCallback({ ok: false, errCode: 30000, errMsg: 'notify error', }) closeBLEConnection() return } } if ((characteristic.uuid.toUpperCase() === GattCharacteristicWriteUUIDOption1) || (characteristic.uuid.toUpperCase() === GattCharacteristicWriteUUIDOption2)) { GattCharacteristicWriteUUID = characteristic.uuid } } } if (isAndroid) { await setBLEMTU(247) } BLEConnectionStateChangeCallback({ ok: true, errCode: 0, errMsg: '', }) } else { BLEConnectionStateChangeCallback({ ok: false, errCode: 0, errMsg: 'disconnect', }) } }) const res = await _createBLEConnection() if (!res.ok) { BLEConnectionStateChangeCallback(res) } } //关闭当前连接 const closeBLEConnection = () => { wx.closeBLEConnection({ deviceId: DeviceId, complete(res) { log(res) }, }) } const onBLECharacteristicValueChange = cb => { wx.offBLECharacteristicValueChange() wx.onBLECharacteristicValueChange(res => { log(res) let x = new Uint8Array(res.value) log(x) let str = utf8BytesToStr(x) let strHex = '' for (let i = 0; i < x.length; i++) { strHex = strHex + x[i].toString(16).padStart(2, '0').toUpperCase() } log(str) log(strHex) cb(str, strHex) }) } const _writeBLECharacteristicValue = buffer => { return new Promise(function (resolve, reject) { wx.writeBLECharacteristicValue({ deviceId: DeviceId, serviceId: GattServerUUID, characteristicId: GattCharacteristicWriteUUID, value: buffer, success(res) { log(res) // {"errno":0,"errCode":0,"errMsg":"writeBLECharacteristicValue:ok"} resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.errCode, errMsg: res.errMsg }) }, }) }) } const writeBLECharacteristicValue = async (str, isHex) => { if (str.length === 0) return { ok: false, errCode: 30000, errMsg: 'data is null' } let buffer if (isHex) { buffer = new ArrayBuffer(str.length / 2) let x = new Uint8Array(buffer) for (let i = 0; i < x.length; i++) { x[i] = parseInt(str.substr(2 * i, 2), 16) } } else { buffer = new Uint8Array(strToUtf8Bytes(str)).buffer } return await _writeBLECharacteristicValue(buffer) } const utf8BytesToStr = utf8Bytes => { let unicodeStr = '' for (let pos = 0; pos < utf8Bytes.length; ) { let flag = utf8Bytes[pos] let unicode = 0 if (flag >>> 7 === 0) { unicodeStr += String.fromCharCode(utf8Bytes[pos]) pos += 1 } else if ((flag & 0xf0) === 0xf0) { unicode = (utf8Bytes[pos] & 0xf) << 18 unicode |= (utf8Bytes[pos + 1] & 0x3f) << 12 unicode |= (utf8Bytes[pos + 2] & 0x3f) << 6 unicode |= utf8Bytes[pos + 3] & 0x3f unicodeStr += String.fromCharCode(unicode) pos += 4 } else if ((flag & 0xe0) === 0xe0) { unicode = (utf8Bytes[pos] & 0x1f) << 12 unicode |= (utf8Bytes[pos + 1] & 0x3f) << 6 unicode |= utf8Bytes[pos + 2] & 0x3f unicodeStr += String.fromCharCode(unicode) pos += 3 } else if ((flag & 0xc0) === 0xc0) { //110 unicode = (utf8Bytes[pos] & 0x3f) << 6 unicode |= utf8Bytes[pos + 1] & 0x3f unicodeStr += String.fromCharCode(unicode) pos += 2 } else { unicodeStr += String.fromCharCode(utf8Bytes[pos]) pos += 1 } } return unicodeStr } const strToUtf8Bytes = str => { let bytes = [] for (let i = 0; i < str.length; ++i) { let code = str.charCodeAt(i) if (code >= 0x10000 && code <= 0x10ffff) { bytes.push((code >> 18) | 0xf0) // 第一个字节 bytes.push(((code >> 12) & 0x3f) | 0x80) bytes.push(((code >> 6) & 0x3f) | 0x80) bytes.push((code & 0x3f) | 0x80) } else if (code >= 0x800 && code <= 0xffff) { bytes.push((code >> 12) | 0xe0) bytes.push(((code >> 6) & 0x3f) | 0x80) bytes.push((code & 0x3f) | 0x80) } else if (code >= 0x80 && code <= 0x7ff) { bytes.push((code >> 6) | 0xc0) bytes.push((code & 0x3f) | 0x80) } else { bytes.push(code) } } return bytes } module.exports = { onBluetoothAdapterStateChange, openBluetoothAdapter, onBluetoothDeviceFound, startBluetoothDevicesDiscovery, stopBluetoothDevicesDiscovery, onBLEConnectionStateChange, createBLEConnection, closeBLEConnection, onBLECharacteristicValueChange, writeBLECharacteristicValue, }
4. 支付宝API文件
新建BLEWX.js文件
/** * 微信连接蓝牙API * @author RedEric * @date 2023年9月6日 */ const logEnable = false let isAndroid = false let BluetoothAdapterStateChangeCallback = () => { } let BLEConnectionStateChangeCallback = () => { } let DeviceId = '' let GattServerUUID = '' const GattServerUUIDOption1 = '0000FFF0-0000-1000-8000-00805F9B34FB' const GattServerUUIDOption2 = 'FFF0' let GattCharacteristicWriteUUID = '' const GattCharacteristicWriteUUIDOption1 = '0000FFF2-0000-1000-8000-00805F9B34FB' const GattCharacteristicWriteUUIDOption2 = 'FFF2' const log = data => { if (logEnable) { console.log('[eciot]:' + JSON.stringify(data)) } } const onBluetoothAdapterStateChange = cb => { BluetoothAdapterStateChangeCallback = cb } const getSetting = () => { return new Promise(function (resolve, reject) { my.getSetting({ success(res) { log(res) if (res.authSetting && res.authSetting.bluetooth) { resolve({ ok: true, errCode: 0, errMsg: '' }) } else { resolve({ ok: false, errCode: 30001, errMsg: 'getSetting fail', }) } }, fail(res) { log(res) resolve({ ok: false, errCode: res.error ? res.error : 30000, errMsg: res.errorMessage ? res.errorMessage : 'getSetting fail', }) }, }) }) } const authorize = async () => { return await _openBluetoothAdapter() } const _openBluetoothAdapter = () => { return new Promise(function (resolve, reject) { my.openBluetoothAdapter({ success(res) { log(res) if (res.isSupportBLE) { resolve({ ok: true, errCode: 0, errMsg: '' }) } else { resolve({ ok: false, errCode: 30001, errMsg: 'isSupportBLE is false' }) } }, fail(res) { log(res) resolve({ ok: false, errCode: res.error ? res.error : 30000, errMsg: res.errorMessage, }) }, }) }) } const openBluetoothAdapter = async () => { await _openBluetoothAdapter() const systemInfo = my.getSystemInfoSync() log(systemInfo) if (systemInfo.platform.toLowerCase() === 'android') { isAndroid = true } if (isAndroid && !systemInfo.bluetoothEnabled) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30001, errMsg: '请打开系统蓝牙开关', }) return } if (isAndroid && !systemInfo.locationEnabled) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30002, errMsg: '请打开系统定位开关', }) return } if (isAndroid && !systemInfo.locationAuthorized) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30003, errMsg: '请打开支付宝定位权限,允许支付宝使用您的位置信息', }) return } const setting = await getSetting() //小程序蓝牙权限 if (!setting.ok) { const authRes = await authorize() if (!authRes.ok) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30004, errMsg: '请打开小程序蓝牙开关,点击右上角三个点,然后点击设置', }) return } } my.offBluetoothAdapterStateChange() my.onBluetoothAdapterStateChange(res => { log(res) // {"available":false,"discovering":false,"NBPageUrl":"https://2021002131657266.hybrid.alipay-eco.com/index.html#pages/index/index"} if (!res.available) { BluetoothAdapterStateChangeCallback({ ok: false, errCode: 30005, errMsg: '蓝牙适配器不可用', }) } }) const openRes = await _openBluetoothAdapter() BluetoothAdapterStateChangeCallback(openRes) } const onBluetoothDeviceFound = cb => { my.offBluetoothDeviceFound() my.onBluetoothDeviceFound(res => { log(res) const device = res.devices[0] const name = device.name ? device.name : device.localName if (!name) { return } let id = device.deviceId let rssi = device.RSSI cb({ id, name, rssi }) }) } const startBluetoothDevicesDiscovery = () => { my.startBluetoothDevicesDiscovery({ //services: [ecServerId], allowDuplicatesKey: true, // powerLevel: 'high', complete(res) { log(res) }, }) } const stopBluetoothDevicesDiscovery = () => { my.stopBluetoothDevicesDiscovery({ complete(res) { log(res) }, }) } const onBLEConnectionStateChange = cb => { BLEConnectionStateChangeCallback = cb } const _createBLEConnection = () => { return new Promise(function (resolve, reject) { my.connectBLEDevice({ deviceId: DeviceId, success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.error, errMsg: res.errorMessage, }) }, }) }) } const getBLEDeviceServices = () => { return new Promise(function (resolve, reject) { my.getBLEDeviceServices({ deviceId: DeviceId, success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '', services: res.services, }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.error, errMsg: res.errorMessage }) }, }) }) } const getBLEDeviceCharacteristics = serviceId => { return new Promise(function (resolve, reject) { my.getBLEDeviceCharacteristics({ deviceId: DeviceId, serviceId, success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '', characteristics: res.characteristics, }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.error, errMsg: res.errorMessage }) }, }) }) } const notifyBLECharacteristicValueChange = (serviceId, characteristicId) => { return new Promise(function (resolve, reject) { my.notifyBLECharacteristicValueChange({ state: true, deviceId: DeviceId, serviceId, characteristicId, success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.error, errMsg: res.errorMessage }) }, }) }) } const setBLEMTU = mtu => { return new Promise(function (resolve, reject) { my.setBLEMTU({ deviceId: DeviceId, mtu, success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.error, errMsg: res.errorMessage }) }, }) }) } const createBLEConnection = async id => { console.log('创建连接') DeviceId = id my.offBLEConnectionStateChanged() my.onBLEConnectionStateChanged(async res => { log(res) // {"deviceId":"EC:22:05:13:78:49","connected":true} if (res.connected) { const servicesResult = await getBLEDeviceServices() if (!servicesResult.ok) { BLEConnectionStateChangeCallback(servicesResult) closeBLEConnection() return } for (const service of servicesResult.services) { if ((service.serviceId.toUpperCase() === GattServerUUIDOption1) || (service.serviceId.toUpperCase() === GattServerUUIDOption2)) { GattServerUUID = service.serviceId } const characteristicsResult = await getBLEDeviceCharacteristics( service.serviceId ) if (!characteristicsResult.ok) { BLEConnectionStateChangeCallback(characteristicsResult) closeBLEConnection() return } for (const characteristic of characteristicsResult.characteristics) { if ( characteristic.properties && characteristic.properties.notify ) { const notifyResult = await notifyBLECharacteristicValueChange( service.serviceId, characteristic.characteristicId ) if (!notifyResult.ok) { BLEConnectionStateChangeCallback({ ok: false, errCode: 30000, errMsg: 'notify error', }) closeBLEConnection() return } } if ((characteristic.characteristicId.toUpperCase() === GattCharacteristicWriteUUIDOption1) || (characteristic.characteristicId.toUpperCase() === GattCharacteristicWriteUUIDOption2)) { GattCharacteristicWriteUUID = characteristic.characteristicId } } } if (isAndroid) { await setBLEMTU(247) } BLEConnectionStateChangeCallback({ ok: true, errCode: 0, errMsg: '', }) } else { BLEConnectionStateChangeCallback({ ok: false, errCode: 0, errMsg: 'disconnect', }) } }) const res = await _createBLEConnection() if (!res.ok) { BLEConnectionStateChangeCallback(res) } } const closeBLEConnection = () => { my.disconnectBLEDevice({ deviceId: DeviceId, complete(res) { log(res) }, }) } const onBLECharacteristicValueChange = cb => { my.offBLECharacteristicValueChange() my.onBLECharacteristicValueChange(res => { log(res) let bytes = [] for (let i = 0; i < (res.value.length / 2); i++) { bytes.push(parseInt(res.value.substr(i * 2, 2), 16)) } let str = utf8BytesToStr(bytes) let strHex = res.value log(str) log(strHex) cb(str, strHex) }) } const _writeBLECharacteristicValue = buffer => { return new Promise(function (resolve, reject) { my.writeBLECharacteristicValue({ deviceId: DeviceId, serviceId: GattServerUUID, characteristicId: GattCharacteristicWriteUUID, value: buffer, // writeType: 'writeNoResponse', success(res) { log(res) resolve({ ok: true, errCode: 0, errMsg: '' }) }, fail(res) { log(res) resolve({ ok: false, errCode: res.error, errMsg: res.errorMessage }) }, }) }) } const writeBLECharacteristicValue = async (str, isHex) => { if (str.length === 0) return { ok: false, errCode: 30000, errMsg: 'data is null' } let buffer if (isHex) { buffer = new ArrayBuffer(str.length / 2) let x = new Uint8Array(buffer) for (let i = 0; i < x.length; i++) { x[i] = parseInt(str.substr(2 * i, 2), 16) } } else { buffer = new Uint8Array(strToUtf8Bytes(str)).buffer } return await _writeBLECharacteristicValue(buffer) } const utf8BytesToStr = utf8Bytes => { let unicodeStr = '' for (let pos = 0; pos < utf8Bytes.length;) { let flag = utf8Bytes[pos] let unicode = 0 if (flag >>> 7 === 0) { unicodeStr += String.fromCharCode(utf8Bytes[pos]) pos += 1 } else if ((flag & 0xf0) === 0xf0) { unicode = (utf8Bytes[pos] & 0xf) << 18 unicode |= (utf8Bytes[pos + 1] & 0x3f) << 12 unicode |= (utf8Bytes[pos + 2] & 0x3f) << 6 unicode |= utf8Bytes[pos + 3] & 0x3f unicodeStr += String.fromCharCode(unicode) pos += 4 } else if ((flag & 0xe0) === 0xe0) { unicode = (utf8Bytes[pos] & 0x1f) << 12 unicode |= (utf8Bytes[pos + 1] & 0x3f) << 6 unicode |= utf8Bytes[pos + 2] & 0x3f unicodeStr += String.fromCharCode(unicode) pos += 3 } else if ((flag & 0xc0) === 0xc0) { //110 unicode = (utf8Bytes[pos] & 0x3f) << 6 unicode |= utf8Bytes[pos + 1] & 0x3f unicodeStr += String.fromCharCode(unicode) pos += 2 } else { unicodeStr += String.fromCharCode(utf8Bytes[pos]) pos += 1 } } return unicodeStr } const strToUtf8Bytes = str => { let bytes = [] for (let i = 0; i < str.length; ++i) { let code = str.charCodeAt(i) if (code >= 0x10000 && code <= 0x10ffff) { bytes.push((code >> 18) | 0xf0) // 第一个字节 bytes.push(((code >> 12) & 0x3f) | 0x80) bytes.push(((code >> 6) & 0x3f) | 0x80) bytes.push((code & 0x3f) | 0x80) } else if (code >= 0x800 && code <= 0xffff) { bytes.push((code >> 12) | 0xe0) bytes.push(((code >> 6) & 0x3f) | 0x80) bytes.push((code & 0x3f) | 0x80) } else if (code >= 0x80 && code <= 0x7ff) { bytes.push((code >> 6) | 0xc0) bytes.push((code & 0x3f) | 0x80) } else { bytes.push(code) } } return bytes } module.exports = { onBluetoothAdapterStateChange, openBluetoothAdapter, onBluetoothDeviceFound, startBluetoothDevicesDiscovery, stopBluetoothDevicesDiscovery, onBLEConnectionStateChange, createBLEConnection, closeBLEConnection, onBLECharacteristicValueChange, writeBLECharacteristicValue, }
6. 如何使用
页面引入对应的API文件,然后调用API的方法即可
const BLEApi = require('../../common/utils/BLEUtil/BLEAPI.js') let _this; let deviceListData = [] export default { data() { return { deviceListDataShow: [] } }, onLoad() { _this = this setInterval(() => { _this.deviceListDataShow = JSON.parse(JSON.stringify(deviceListData)) }, 800) }, onShow() { setTimeout(() => { _this.openBluetoothAdapter() }, 100) }, methods: { listViewTap(id){ uni.showLoading('设备连接中') BLEApi.onBLEConnectionStateChange(res => { uni.hideLoading() if (res.ok) { BLEApi.stopBluetoothDevicesDiscovery() uni.navigateTo({ url: '../device/device' }) } else { uni.showModal({ title: '提示', content: '连接失败,errCode=' + res.errCode + ',errMsg=' + res.errMsg }) } }) BLEApi.createBLEConnection(id) }, openBluetoothAdapter() { BLEApi.onBluetoothAdapterStateChange(res => { if (res.ok) { console.log('Bluetooth adapter ok') _this.startBluetoothDevicesDiscovery() } else { uni.showModal({ title: '提示', content: `Bluetooth adapter error | ${res.errCode} | ${res.errMsg}` }) } }) BLEApi.openBluetoothAdapter() }, startBluetoothDevicesDiscovery() { console.log('start search') BLEApi.onBluetoothDeviceFound(res => { // if(res.id==="EC:22:05:13:78:49") // console.log(`id:${res.id},name:${res.name},rssi:${res.rssi}`) for (const item of deviceListData) { if (item.id === res.id) { item.name = res.name item.rssi = res.rssi return } } let manufacturer = '' if (res.name.length === 11 && res.name.startsWith('@')) { manufacturer = 'eciot' } if (res.name.length === 15 && res.name.startsWith('BT_')) { manufacturer = 'eciot' } deviceListData.push({ id: res.id, name: res.name, rssi: res.rssi, manufacturer, }) }) BLEApi.startBluetoothDevicesDiscovery() }, } }
7. 完整示例
安卓、支付宝、IOS、安卓都可以使用
未开启蓝牙 | 开启蓝牙,蓝牙列表 | 连接蓝牙,收发消息 |
源码地址:
https://download.csdn.net/download/qq_35921773/88306318