相同代码下蓝牙模块在Android 11正常,Android 11+扫描丢失设备
Android 11+ 蓝牙扫描丢失设备的解决方案
1. 修正权限配置
Android 12(API 31)及以上对蓝牙权限的管控更严格,需调整权限声明并确保运行时权限申请逻辑正确:
调整Manifest权限
为BLUETOOTH_SCAN添加权限标志,明确是否依赖位置信息扫描:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
如果你的BLE设备未广播服务UUID,必须依赖位置信息才能被发现,则移除android:usesPermissionFlags属性,但需确保已正确申请ACCESS_FINE_LOCATION权限。
动态申请运行时权限
启动扫描前,必须主动申请以下权限:
import 'package:permission_handler/permission_handler.dart'; Future<void> requestBlePermissions() async { final statuses = await [ Permission.bluetoothScan, Permission.bluetoothConnect, Permission.locationWhenInUse, ].request(); if (statuses.values.any((status) => status != PermissionStatus.granted)) { // 处理权限拒绝逻辑,比如弹窗提示用户开启权限 } }
2. 优化扫描参数
Android 12+对无过滤的蓝牙扫描(空UUID列表)有严格的频率限制,易导致设备丢失,可通过以下方式优化:
指定目标服务UUID扫描
如果你的BLE设备有固定服务UUID,启动扫描时传入该UUID,缩小扫描范围:
// 替换为你的设备实际服务UUID final targetUuid = Uuid.parse("0000FFE0-0000-1000-8000-00805F9B34FB"); bleScanner.startScan([targetUuid]);
调整扫描模式
使用低延迟扫描模式提升前台扫描效率:
bleScanner.startScan( [], scanMode: ScanMode.lowLatency, );
3. 适配Android 12+后台扫描限制
如果需要在后台持续扫描,需:
- 动态申请
ACCESS_BACKGROUND_LOCATION权限 - 使用前台服务承载扫描逻辑,避免系统限制扫描频率
4. 代码逻辑优化
管理扫描生命周期
页面销毁时停止扫描,避免资源泄漏:
@override void dispose() { bleScanner.stopScan(); super.dispose(); }
复用扫描器实例
当前代码每次创建页面都初始化新的BleScanner,易导致扫描冲突,建议改为全局单例或通过状态管理工具(如Riverpod)共享实例:
// Riverpod单例示例 final bleScannerProvider = Provider<BleScanner>((ref) { return BleScanner( ble: FlutterReactiveBle(), logMessage: (message) {}, ); });
内容的提问来源于stack exchange,提问作者Abdullah Saeed
相关产品推荐
相关产品推荐

