Alipay WeChat 애플릿은 Bluetooth에 연결되며 IOS 및 Android(오픈 소스)와 호환됩니다.

Alipay WeChat 애플릿은 Bluetooth에 연결되며 IOS 및 Android(오픈 소스)와 호환됩니다.

1. 소개

​ 최근 알리페이의 블루투스와 IOS의 블루투스가 고장이 나서 호환성 문제가 너무 많아 우여곡절 끝에 알리페이 애플릿과 위챗 애플릿의 블루투스 문제가 드디어 해결되었습니다. 솔루션은 완벽합니다

  1. 안드로이드 위챗 애플릿
  2. IOS 위챗 애플릿
  3. 안드로이드 알리페이 애플릿
  4. IOS Alipay 애플릿
    의 블루투스 연결 문제

2. 솔루션

​ Alipay와 WeChat의 API가 다르기 때문에 메시지를 받은 후 파싱하는 방법도 다르기 때문에 Alipay와 WeChat용으로 APIJS 파일 2개를 작성합니다. js.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, 안드로이드에서 사용 가능

블루투스가 켜져 있지 않음 블루투스, 블루투스 목록 켜기 블루투스에 연결하여 메시지 보내고 받기
이미지-20230906145610318 이미지-20230906145643075 이미지-20230906145722583

소스 주소:

https://download.csdn.net/download/qq_35921773/88306318

추천

출처blog.csdn.net/qq_35921773/article/details/132715906