React Native集成RFID阅读器与标签的技术实现问题咨询
React Native RFID阅读器集成技术支持
我正在React Native中开发RFID阅读器、标签与设备的集成功能,需求如下:
- 完成RFID阅读器与设备的蓝牙连接
- 当RFID标签进入感应范围时,读取标签数据并在UI展示
- UI包含Start、Stop、Reset按钮,点击Start时先检测范围内是否有RFID标签,再启动扫描并展示数据
当前代码已实现基础连接,点击Start按钮后可与阅读器集成并读取标签数据,但需要进一步的技术优化支持。
实现代码
import React, {useState, useEffect} from 'react'; import { Text, View, ScrollView, TouchableOpacity, Modal, FlatList, SafeAreaView, PermissionsAndroid, NativeModules, NativeEventEmitter, useColorScheme, StyleSheet, Platform, Alert, } from 'react-native'; import BleManager from 'react-native-ble-manager'; import {Colors} from 'react-native/Libraries/NewAppScreen'; import {Buffer} from 'buffer'; import encodeUtf8 from 'encode-utf8'; const BleManagerModule = NativeModules.BleManager; const BleManagerEmitter = new NativeEventEmitter(BleManagerModule); const BleConnectDevice = () => { const [isScanning, setIsScanning] = useState(false); const [devices, setDevices] = useState([]); const [connectedDevices, setConnectedDevices] = useState([]); const [modalVisible, setModalVisible] = useState(false); const [readData, setReadData] = useState(''); const isDarkMode = useColorScheme() === 'dark'; const characteristic = 'ffe1'; const service = 'ffe0'; useEffect(() => { BleManager.enableBluetooth() .then(() => { console.log('Bluetooth is turned on!'); }) .catch(error => { console.error('Bluetooth enable error:', error); }); if (Platform.OS === 'android') { requestPermissions(); } }, []); const requestPermissions = async () => { try { const granted = await PermissionsAndroid.requestMultiple([ PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN, PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT, PermissionsAndroid.PERMISSIONS.BLUETOOTH_ADVERTISE, ]); if ( granted['android.permission.ACCESS_FINE_LOCATION'] === PermissionsAndroid.RESULTS.GRANTED && granted['android.permission.BLUETOOTH_SCAN'] === PermissionsAndroid.RESULTS.GRANTED && granted['android.permission.BLUETOOTH_CONNECT'] === PermissionsAndroid.RESULTS.GRANTED && granted['android.permission.BLUETOOTH_ADVERTISE'] === PermissionsAndroid.RESULTS.GRANTED ) { console.log('All permissions granted'); } else { console.log('Permissions denied'); } } catch (err) { console.warn('Permission request error:', err); } }; useEffect(() => { BleManager.start({showAlert: false}).then(() => { console.log('BleManager initialized'); }); const handleDiscoverPeripheral = peripheral => { if (!peripheral.name) { peripheral.name = 'NO NAME'; } setDevices(prevDevices => { const deviceExists = prevDevices.find( device => device.id === peripheral.id, ); if (deviceExists) { return prevDevices; } else { return [...prevDevices, peripheral]; } }); }; BleManagerEmitter.addListener( 'BleManagerDiscoverPeripheral', handleDiscoverPeripheral, ); return () => { BleManagerEmitter.removeListener( 'BleManagerDiscoverPeripheral', handleDiscoverPeripheral, ); }; }, []); useEffect(() => { const stopListener = BleManagerEmitter.addListener( 'BleManagerStopScan', () => { setIsScanning(false); console.log('Scan is stopped'); }, ); return () => { stopListener.remove(); }; }, []); const startScan = () => { if (!isScanning) { BleManager.scan([], 5, true) .then(() => { console.log('Scanning...'); setIsScanning(true); setModalVisible(true); }) .catch(error => { console.error('Scan error:', error); }); } }; const stopScan = () => { if (isScanning) { BleManager.stopScan() .then(() => { console.log('Stopped scanning'); setIsScanning(false); }) .catch(error => { console.error('Stop scan error:', error); }); } }; const resetScan = () => { setDevices([]); setConnectedDevices([]); setReadData(''); console.log('Reset complete'); }; const connectToDevice = device => { BleManager.connect(device.id) .then(() => { return BleManager.retrieveServices(device.id); }) .then(peripheralInfo => { console.log('Services and characteristics:', peripheralInfo); setModalVisible(false); setConnectedDevices(prevDevices => [...prevDevices, device]); }) .then(() => { return BleManager.startNotification(device.id, service, characteristic); }) .then(() => { BleManagerEmitter.addListener( 'BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic, ); }) .catch(error => { console.log('Error connecting to device:', error); }); }; const handleUpdateValueForCharacteristic = data => { console.log('Received data from characteristic', data); const buffer = Buffer.from(data.value); const sensorData = buffer.toString('ascii'); console.log('Received data:', sensorData); setReadData(sensorData); Alert.alert('Received data: ' + sensorData); }; const disconnectFromDevice = device => { BleManager.disconnect(device.id) .then(() => { console.log('Disconnected from ' + device.name); setConnectedDevices(prevDevices => prevDevices.filter(d => d.id !== device.id), ); }) .catch(error => { console.log('Disconnection error', error); }); }; const readDataFromDevice = (deviceId, serviceUUID, characteristicUUID) => { BleManager.startNotification(deviceId, serviceUUID, characteristicUUID); BleManager.read(deviceId, serviceUUID, characteristicUUID) .then(() => { console.log('Started notifications.'); }) .then(readData => { console.log(readData, 'readdddd'); // const buffer = Buffer.from(readData); // console.log(buffer, 'bufferrr'); // const sensorData = buffer.toString('ascii'); // console.log(sensorData, 'sensorrr'); // setReadData(sensorData); }) .catch(error => { console.error('Notification error:', error); }); BleManager.addListener( 'BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic, // data => { // console.log('Received2333 data:', decodeData(data.value)); // // Update UI with received data // }, ); }; const decodeData = encodedData => { // Convert received data to its original format return encodedData; }; const sendCom = async peripheral => { const data = encodeUtf8('1'); // convert data to bytes BleManager.retrieveServices(peripheral) .then(() => { BleManager.startNotification(peripheral, service, characteristic); }) .then(() => { BleManager.writeWithoutResponse( peripheral.id, service, characteristic, data, ); console.log(`Sent: ${data}`); }) .catch(error => { console.log(`Error writing ${characteristic}: ${error}`); }); }; return ( <SafeAreaView style={styles.container}> <ScrollView contentContainerStyle={{flex: 1}}> <Text style={styles.title}>React Native BLE Manager</Text> <View style={styles.deviceList}> {connectedDevices.length > 0 ? ( connectedDevices.map(device => ( <View key={device.id} style={styles.connectedDevice}> <View> <Text style={styles.deviceName}>{device.name}</Text> <Text style={styles.deviceId}>{device.id}</Text> </View> <TouchableOpacity activeOpacity={0.5} onPress={() => disconnectFromDevice(device)} style={styles.disconnectButton}> <Text style={styles.buttonText}>Disconnect</Text> </TouchableOpacity> </View> )) ) : ( <TouchableOpacity activeOpacity={0.5} onPress={startScan} style={styles.scanButton}> <Text style={styles.buttonText}>Scan</Text> </TouchableOpacity> )} </View> {connectedDevices.length > 0 && ( <View style={styles.buttonWrap}> <TouchableOpacity activeOpacity={0.5} onPress={readDataFromDevice( connectedDevices[0]?.id, '0000ffe0-0000-1000-8000-00805f9b34fb', '0000ffe1-0000-1000-8000-00805f9b34fb', )} style={[styles.resetButton, {backgroundColor: '#0a84ff'}]}> <Text style={styles.buttonText}>Start</Text> </TouchableOpacity> <TouchableOpacity activeOpacity={0.5} onPress={stopScan} style={styles.stopButton}> <Text style={styles.buttonText}>Stop</Text> </TouchableOpacity> <TouchableOpacity activeOpacity={0.5} onPress={resetScan} style={styles.resetButton}> <Text style={styles.buttonText}>Reset</Text> </TouchableOpacity> </View> )} <Modal visible={modalVisible} animationType="slide"> <SafeAreaView style={styles.modalContainer}> <FlatList data={devices} renderItem={({item}) => ( <TouchableOpacity style={styles.deviceContainer} onPress={() => connectToDevice(item)}> <Text style={styles.deviceName}>{item.name}</Text> <Text style={styles.deviceId}>{item.id}</Text> </TouchableOpacity> )} keyExtractor={item => item.id} /> <TouchableOpacity activeOpacity={0.5} onPress={() => setModalVisible(false)} style={styles.scanButton}> <Text style={styles.buttonText}>Close</Text> </TouchableOpacity> </SafeAreaView> </Modal> <View style={styles.dataContainer}> <Text style={styles.dataText}>Received Data:</Text> <Text style={styles.dataText}>{readData}</Text> </View> </ScrollView> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { flex: 1, padding: 24, backgroundColor: Colors.lighter, }, title: { fontSize: 24, fontWeight: '600', color: Colors.black, textAlign: 'center', marginBottom: 24, }, deviceList: { marginBottom: 24, }, connectedDevice: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 16, backgroundColor: '#f0f0f0', borderRadius: 8, marginBottom: 16, }, deviceContainer: { padding: 16, backgroundColor: '#f0f0f0', borderRadius: 8, marginBottom: 16, }, deviceName: { fontSize: 18, fontWeight: '600', color: Colors.black, }, deviceId: { fontSize: 12, color: Colors.dark, }, scanButton: { padding: 16, backgroundColor: '#007aff', borderRadius: 8, alignItems: 'center', }, stopButton: { padding: 16, backgroundColor: '#ff3b30', borderRadius: 8, alignItems: 'center', }, resetButton: { padding: 16, backgroundColor: '#ffcc00', borderRadius: 8, alignItems: 'center', }, buttonText: { color: '#fff', fontWeight: '600', }, buttonWrap: { flexDirection: 'row', justifyContent: 'space-around', marginBottom: 24, }, disconnectButton: { padding: 8, backgroundColor: '#ff3b30', borderRadius: 8, }, modalContainer: { flex: 1, padding: 24, backgroundColor: Colors.lighter, }, dataContainer: { marginTop: 16, padding: 16, backgroundColor: '#f0f0f0', borderRadius: 8, }, dataText: { fontSize: 16, color: Colors.black, }, }); export default BleConnectDevice;
针对性优化方案
1. Start按钮触发逻辑修复
当前代码中Start按钮的onPress直接执行readDataFromDevice,会导致组件挂载时自动触发该方法,而非点击时触发。需改为箭头函数包裹:
<TouchableOpacity activeOpacity={0.5} onPress={() => readDataFromDevice( connectedDevices[0]?.id, '0000ffe0-0000-1000-8000-00805f9b34fb', '0000ffe1-0000-1000-8000-00805f9b34fb', )} style={[styles.resetButton, {backgroundColor: '#0a84ff'}]}> <Text style={styles.buttonText}>Start</Text> </TouchableOpacity>
2. 标签存在检测逻辑补充
按照需求,Start按钮点击时需先检测范围内是否有RFID标签。可通过向阅读器发送查询指令(需匹配阅读器协议),监听响应判断是否存在标签:
const checkForTags = async (deviceId) => { // 替换为阅读器支持的查询标签指令 const queryCommand = encodeUtf8('CHECK_TAGS'); await BleManager.writeWithoutResponse(deviceId, service, characteristic, queryCommand); // 后续通过handleUpdateValueForCharacteristic回调判断是否有标签返回 }; // 修改Start按钮触发逻辑 const handleStart = async () => { const deviceId = connectedDevices[0]?.id; if (!deviceId) return; await checkForTags(deviceId); // 若检测到标签,启动数据读取 readDataFromDevice(deviceId, '0000ffe0-0000-1000-8000-00805f9b34fb', '0000ffe1-0000-1000-8000-00805f9b34fb'); };
3. 重复监听问题修复
connectToDevice和readDataFromDevice中重复添加了特征值更新监听,会导致回调多次触发。建议在组件挂载时统一添加监听,卸载时移除:
useEffect(() => { const valueUpdateListener = BleManagerEmitter.addListener( 'BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic, ); return () => { valueUpdateListener.remove(); }; }, []);
4. 数据解析优化
RFID标签数据多为十六进制或特定编码,当前ASCII解析可能导致乱码,需根据阅读器协议调整解析逻辑:
const handleUpdateValueForCharacteristic = data => { console.log('Received raw data:', data.value); // 十六进制转字符串示例 const hexString = Buffer.from(data.value).toString('hex');
相关产品推荐
相关产品推荐

