Android 11及以下版本React Native Bluetooth Classic设备发现异常问题
问题原因分析
- 权限请求逻辑不兼容低版本
Android 11(API 30)及以下不存在BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限,尝试请求这些不存在的权限时,系统会直接返回NEVER_ASK_AGAIN。你的权限判断逻辑将该状态等同于授权通过,但实际位置权限可能未正确获取,导致扫描因权限不足卡住。 startDiscovery调用方式问题
低版本Android中蓝牙扫描依赖位置权限,若权限未完全授予,startDiscovery会静默阻塞而非抛出异常;此外,部分版本中该方法需配合事件监听完成扫描,直接用await可能导致主线程冻结。
解决办法
1. 修复权限请求逻辑,按Android版本区分权限
根据系统版本动态构建需要请求的权限列表,避免在低版本请求不存在的蓝牙权限:
import { Platform } from 'react-native'; const getNeededPermissions = () => { const permissions = []; if (Platform.Version >= 31) { // Android 12+ 请求新蓝牙权限 permissions.push( 'android.permission.BLUETOOTH_SCAN', 'android.permission.BLUETOOTH_CONNECT' ); } else { // Android 11及以下 请求位置权限(蓝牙扫描依赖) permissions.push( 'android.permission.ACCESS_FINE_LOCATION', 'android.permission.ACCESS_COARSE_LOCATION' ); // BLUETOOTH和BLUETOOTH_ADMIN属于正常权限,无需动态请求 } return permissions; }; const requestAccessFineLocationPermission = async () => { const neededPermissions = getNeededPermissions(); const granted = await PermissionsAndroid.requestMultiple(neededPermissions); let isGranted = true; if (Platform.Version >= 31) { isGranted = granted['android.permission.BLUETOOTH_SCAN'] === PermissionsAndroid.RESULTS.GRANTED && granted['android.permission.BLUETOOTH_CONNECT'] === PermissionsAndroid.RESULTS.GRANTED; } else { isGranted = granted['android.permission.ACCESS_FINE_LOCATION'] === PermissionsAndroid.RESULTS.GRANTED && granted['android.permission.ACCESS_COARSE_LOCATION'] === PermissionsAndroid.RESULTS.GRANTED; } setGranted(isGranted); };
2. 调整设备发现逻辑,增加权限校验与事件监听
调用startDiscovery前先确保权限已授予,改用事件监听处理扫描结果,避免await阻塞主线程:
import { DeviceEventEmitter } from 'react-native'; let discoveryListener = null; const startDeviceDiscovery = async () => { const available = await RNBluetoothClassic.isBluetoothAvailable(); const enabled = await RNBluetoothClassic.isBluetoothEnabled(); if (!available || !enabled) { await RNBluetoothClassic.requestBluetoothEnabled(); return; } // 先校验权限是否已授予 if (!granted) { await requestAccessFineLocationPermission(); if (!granted) { console.log("权限不足,无法扫描设备"); setLoading(false); return; } } try { setLoading(true); setLoadingText('正在扫描设备...'); // 先获取已配对设备 const paired = await RNBluetoothClassic.getBondedDevices(); setAvailableDevices([...paired]); // 注册扫描事件监听,接收新发现的未配对设备 if (discoveryListener) { discoveryListener.remove(); } discoveryListener = DeviceEventEmitter.addListener( 'BLUETOOTH_DISCOVERY', (device) => { // 避免重复添加设备 setAvailableDevices(prev => { const exists = prev.some(d => d.address === device.address); return exists ? prev : [...prev, device]; }); } ); // 启动扫描 await RNBluetoothClassic.startDiscovery(); // 扫描10秒后自动停止 setTimeout(async () => { await RNBluetoothClassic.stopDiscovery(); if (discoveryListener) { discoveryListener.remove(); discoveryListener = null; } setLoading(false); setLoadingText(''); }, 10000); } catch (err) { console.log(err); setLoading(false); setLoadingText(''); if (discoveryListener) { discoveryListener.remove(); discoveryListener = null; } } };
3. 优化AndroidManifest配置(可选)
确保新蓝牙权限仅对高版本生效,避免低版本系统混淆:
<!-- Request Bluetooth permissions for devices on API 31+ --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" android:maxSdkVersion="33" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" android:maxSdkVersion="33" />
内容的提问来源于stack exchange,提问作者Valentin Emil Cudelcu
相关产品推荐
相关产品推荐

