react native如何发送蓝牙命令
使用react-native-ble-plx插件import { createContext, useState, useEffect, useContext, useRef } from react; import { BleManager } from react-native-ble-plx; import * as Location from expo-location; import { Platform, PermissionsAndroid, ToastAndroid, Dimensions } from react-native; import { Buffer } from craftzdog/react-native-buffer; // 创建蓝牙上下文 const BlueToothContext createContext(); // 蓝牙状态枚举 export const BluetoothState { UNKNOWN: unknown, POWERED_OFF: poweredOff, POWERED_ON: poweredOn, RESETTING: resetting, UNAUTHORIZED: unauthorized, UNSUPPORTED: unsupported, }; //请求蓝牙权限 const requestBluetoothPermission async () { if (Platform.OS ios) { return true; } if (Platform.OS android PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION) { const apiLevel parseInt(Platform.Version.toString(), 10); if (apiLevel 31) { const granted await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION); return granted PermissionsAndroid.RESULTS.GRANTED; } if (PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT) { const result await PermissionsAndroid.requestMultiple([ PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN, PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT, PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION ]); return ( result[android.permission.BLUETOOTH_CONNECT] PermissionsAndroid.RESULTS.GRANTED result[android.permission.BLUETOOTH_SCAN] PermissionsAndroid.RESULTS.GRANTED result[android.permission.ACCESS_FINE_LOCATION] PermissionsAndroid.RESULTS.GRANTED ); } } return false; }; // 蓝牙Provider组件 export const BlueToothProvider ({ children }) { // 蓝牙状态 const [bluetoothStatus, setBluetoothStatus] useState(BluetoothState.UNKNOWN); // BLE管理器实例 const [manager, setManager] useState(null); // 设备列表 const [devices, setDevices] useState([]); // 已连接设备 const connectedDeviceRef useRef(null); // const [connectedDevice, setConnectedDevice] useState(null); //已连接设备的设备ID const connectedDeviceIDRef useRef([F9, 06, 78]); // 扫描状态 const [isScanning, setIsScanning] useState(false); // 连接状态 const [isConnecting, setIsConnecting] useState(false); // 错误信息 const [error, setError] useState(null); //可写入 const writableCharacteristic useRef({}); //可监听 const monitorCharacteristic useRef({}); // 监听器订阅列表 const monitorSubscriptions useRef(null); //指令-响应映射 const instructionResponseMap useRef(new Map()); //消息提示 const showToast (message) { ToastAndroid.showWithGravityAndOffset( message, ToastAndroid.SHORT, ToastAndroid.TOP, 0, -${Dimensions.get(window).height / 2} ); }; // 初始化BLE管理器 useEffect(() { const bleManager new BleManager(); setManager(bleManager); // 监听蓝牙状态变化 const subscription bleManager.onStateChange((state) { let newStatus BluetoothState.UNKNOWN; switch (state) { case PoweredOn: newStatus BluetoothState.POWERED_ON; break; case PoweredOff: newStatus BluetoothState.POWERED_OFF; break; case Resetting: newStatus BluetoothState.RESETTING; break; case Unauthorized: newStatus BluetoothState.UNAUTHORIZED; break; case Unsupported: newStatus BluetoothState.UNSUPPORTED; break; default: newStatus BluetoothState.UNKNOWN; } setBluetoothStatus(newStatus); }, true); // 请求位置权限Android需要 const requestLocationPermission async () { const { status } await Location.requestForegroundPermissionsAsync(); if (status ! granted) { setError(需要位置权限才能使用蓝牙功能); } }; requestLocationPermission(); return () { subscription.remove(); bleManager.destroy(); }; }, []); // 开始扫描设备 const startScan async () { if (!manager || isScanning) return; const hasPermission await requestBluetoothPermission(); if (!hasPermission) return; // 检查蓝牙状态 if (bluetoothStatus ! BluetoothState.POWERED_ON) { const errorMessage bluetoothStatus BluetoothState.POWERED_OFF ? 蓝牙未开启请先开启蓝牙 : 蓝牙状态异常; setError(errorMessage); return; } try { // 立即停止之前可能正在进行的扫描 if (isScanning) { manager.stopDeviceScan(); } setDevices([ ]); setIsScanning(true); setError(null); // 记录本次扫描中发现的设备ID const discoveredDeviceIds new Set(); // 开始扫描过滤指定服务可选 manager.startDeviceScan(null, null, (error, device) { if (error) { const errorMessage error.reason || error.message || 蓝牙扫描失败; setError(errorMessage); setIsScanning(false); return; } if (device) { // 记录设备ID discoveredDeviceIds.add(device.id); // 更新设备列表添加或更新设备 setDevices(prevDevices { // 检查是否已存在相同id的设备 const deviceIndex prevDevices.findIndex(d d.id device.id); if (deviceIndex 0) { // 更新已存在的设备 const updatedDevices [...prevDevices]; updatedDevices[deviceIndex] device; return updatedDevices; } else { // 添加新设备 return [...prevDevices, device]; } }); } }); // 扫描10秒后停止并清理离线设备 setTimeout(() { stopScan(); // 清理离线设备只保留本次扫描中发现的设备 setDevices(prevDevices { return prevDevices.filter(device discoveredDeviceIds.has(device.id)); }); }, 10000); } catch (err) { setError(启动扫描失败); setIsScanning(false); } }; // 停止扫描设备 const stopScan () { if (manager isScanning) { manager.stopDeviceScan(); setIsScanning(false); } }; //刷新设备列表 const refreshDevices () { stopScan(); startScan(); }; // 连接到设备 const connectToDevice (deviceId) { if (!manager || isConnecting) return; return new Promise(async (resolve, reject) { setIsConnecting(true); setError(null); try { // 1.查找设备 const device await manager.connectToDevice(deviceId); //设置设备的mtu const result await manager.requestMTUForDevice(deviceId, 512); // 2.发现服务 const discoveredDevice await device.discoverAllServicesAndCharacteristics(); // 3. 获取服务列表 const servicesList await discoveredDevice.services(); // 4. 获取每个服务的特征 const allCharacteristics []; for (const service of servicesList) { const serviceCharacteristics await discoveredDevice.characteristicsForService( service.uuid ); allCharacteristics.push(...serviceCharacteristics); } //可写入 let target allCharacteristics.find(item item.isWritableWithResponse item.isWritableWithoutResponse); writableCharacteristic.current target; //可监听 let monitorTarget allCharacteristics.find(item item.isNotifiable); monitorCharacteristic.current monitorTarget; // 设置连接监听器 manager.onDeviceDisconnected(deviceId, (error, disconnectedDevice) { if (disconnectedDevice?.id deviceId) { connectedDeviceRef.current null; setError(设备已断开连接); } }); connectedDeviceRef.current device; //开启监听器 const monitorStarted monitorDevice(monitorCharacteristic.current.serviceUUID, monitorCharacteristic.current.uuid); setIsConnecting(false); resolve(device); return device; } catch (err) { setError(err.message); setIsConnecting(false); reject(连接失败); return null; } }); }; //储存已连接设备的设备ID const setConnectedDeviceID (deviceId) { connectedDeviceIDRef.current deviceId; }; // 断开设备连接 const disconnectFromDevice async () { if (!connectedDeviceRef.current) return; try { // 取消所有监听器 monitorSubscriptions.current.remove(); monitorSubscriptions.current null; await connectedDeviceRef.current.cancelConnection(); connectedDeviceRef.current null; // 清空特征引用 writableCharacteristic.current {}; monitorCharacteristic.current {}; // 清空已连接设备ID connectedDeviceIDRef.current null; } catch (err) { setError(err.message); } }; // 写入数据到设备, 服务id、特征id、指令 const writeToDevice (serviceId, characteristicId, data) { return new Promise((resolve, reject) { if (!connectedDeviceRef.current) { reject(未连接到任何设备); showToast(未连接到任何设备); return false; } //数据重构 const buffer data.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16); }); const typedArray new Uint8Array(buffer); let value Buffer.from(typedArray).toString(base64); connectedDeviceRef.current.writeCharacteristicWithResponseForService( serviceId, characteristicId, value ).then((res) { resolve(true); }).catch(err { console.log(写入数据失败, err); reject(err.message || 写入数据失败); setError(err.message || 写入数据失败); }); }); }; // 读取设备数据 const readFromDevice async (serviceId, characteristicId) { if (!connectedDeviceRef.current) { showToast(未连接到任何设备); return null; } try { const characteristic await connectedDeviceRef.current.readCharacteristicForService( serviceId, characteristicId ); return characteristic.value; } catch (err) { setError(err.message); return null; } }; // 监听设备数据通知 const monitorDevice (serviceId, characteristicId) { if (!connectedDeviceRef.current) { showToast(未连接到任何设备); return false; } if (!serviceId || !characteristicId) { setError(服务ID和特征ID不能为空); return false; } try { // 如果已有订阅先移除 if (monitorSubscriptions.current) { monitorSubscriptions.current.remove(); } const subscription connectedDeviceRef.current.monitorCharacteristicForService( serviceId, characteristicId, (error, characteristic) { if (error) { const errorMessage error.reason || error.message || 设备通知监听失败; setError(errorMessage); } else { let result characteristic.value; console.log(接收到通知, result); //找到对应的callback并执行 const key result.substring(6, 8); let callback instructionResponseMap.current.get(key); if (callback) { callback(result); } } }, ); // 保存订阅到列表以便后续管理 monitorSubscriptions.current subscription; return true; } catch (err) { const errorMessage err.reason || err.message || 设备通知监听失败; setError(errorMessage); return false; } }; // 发送指令 const sendInstruction (data, callback, sendSuccessCallback) { // 存储回调函数 //取data下标6-7作为key const key data.substring(6, 8); instructionResponseMap.current.set(key, callback); console.log(开始发送指令, data); return new Promise((resolve, reject) { writeToDevice(writableCharacteristic.current.serviceUUID, writableCharacteristic.current.uuid, data).then(res { sendSuccessCallback sendSuccessCallback(res); resolve(res); }).catch(err { reject(err || 发送指令失败); }); }); }; // 上下文值 const contextValue { bluetoothStatus, manager, devices, connectedDeviceRef, isScanning, isConnecting, error, startScan, stopScan, refreshDevices, connectToDevice, disconnectFromDevice, writeToDevice, readFromDevice, monitorDevice, sendInstruction, setConnectedDeviceID, connectedDeviceIDRef }; return ( BlueToothContext.Provider value{contextValue} {children} /BlueToothContext.Provider ); }; // 自定义Hook用于使用蓝牙上下文 export const useBlueToothContext () { const context useContext(BlueToothContext); if (!context) { throw new Error(useBlueToothContext must be used within a BlueToothProvider); } return context; };1.关键地方命令如何转格式发送给蓝牙设备//数据重构(data: AA5502560157) const buffer data.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16); }); const typedArray new Uint8Array(buffer); let value Buffer.from(typedArray).toString(base64); //qlUCVgFX1.其中原始的data是十六进制数字拼接的字符串0xAA、0x55、0x02、0x56、0x01、0x57 - AA55025601572.先转为十进制的数组:buffer [170, 85 2 86 1 87]3.然后通过new Uint8Array处理二进制数据4.最后转为base64发给蓝牙设备