支付宝微信小程序连接蓝牙兼容IOS和安卓(开源)

简介: 支付宝微信小程序连接蓝牙兼容IOS和安卓(开源)

支付宝微信小程序连接蓝牙兼容IOS和安卓(开源)

1. 前言

最近被支付宝的蓝牙和IOS的蓝牙整破防了,太多兼容性问题,磕磕绊绊终于把支付宝小程序和微信小程序的蓝牙问题给解决了。该方案完美解决

  1. 安卓微信小程序
  2. IOS微信小程序
  3. 安卓支付宝小程序
  4. 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


目录
打赏
0
0
0
0
81
分享
相关文章
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
86 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
71 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
68 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
218 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
197 67
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
深入探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】 本文将带领读者深入了解Apple最新推出的SwiftUI框架,这一革命性的用户界面构建工具为iOS开发者提供了一种声明式、高效且直观的方式来创建复杂的用户界面。通过分析SwiftUI的核心概念、主要特性以及在实际项目中的应用示例,我们将展示如何利用SwiftUI简化UI代码,提高开发效率,并保持应用程序的高性能和响应性。无论你是iOS开发的新手还是有经验的开发者,本文都将为你提供宝贵的见解和实用的指导。
178 66
|
3月前
|
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
151 11

热门文章

最新文章

  • 1
    苹果app上架-ios上架苹果商店app store 之苹果支付In - App Purchase内购配置-优雅草卓伊凡
    57
  • 2
    苹果app上架app store 之苹果开发者账户在mac电脑上如何使用钥匙串访问-发行-APP发布证书ios_distribution.cer-优雅草卓伊凡
    46
  • 3
    uniapp云打包ios应用证书的获取方法,生成指南
    49
  • 4
    iOS|解决 setBrightness 调节屏幕亮度不生效的问题
    124
  • 5
    iOS|记一名 iOS 开发新手的前两次 App 审核经历
    29
  • 6
    iOS各个证书生成细节
    44
  • 7
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    218
  • 8
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    66
  • 9
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    86
  • 10
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    68