Flutter使用flutter_blue扫描BLE设备无结果,请求代码排查帮助
Flutter BLE扫描应用问题排查
我是蓝牙开发新手,首次尝试开发扫描并连接附近蓝牙设备的Flutter应用,使用flutter_blue包编写了扫描代码,但真机运行时无法发现附近两台设备,同时出现权限相关日志,麻烦帮忙排查问题。
代码实现
class _MyHomePageState extends State<MyHomePage> { final FlutterBlue flutterBlue = FlutterBlue.instance; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("BLE")), body: StreamBuilder<BluetoothState>( stream: flutterBlue.state, builder: (context, snapshot) { if (snapshot.data == BluetoothState.on) { return ScanForDevices(flutterBlue: flutterBlue); } else if (snapshot.hasError || snapshot.data == BluetoothState.unauthorized) { return Center(child: Text("Error")); } else { return Center(child: CircularProgressIndicator()); } }, ), ); } } class _ScanForDevicesState extends State<ScanForDevices> { late List<ScanResult> result; @override void initState() { super.initState(); widget.flutterBlue.startScan(); // scanning(); } scanning() { widget.flutterBlue.scanResults.listen((event) { for (ScanResult r in event) { result.add(r); print(r.device.id.toString() + "\n"); } }); } @override Widget build(BuildContext context) { return Scaffold( body: StreamBuilder<List<ScanResult>>( stream: FlutterBlue.instance.scanResults, builder: (context, snapshot) { if (snapshot.hasData) { return ListView( children: snapshot.data!.map((e) => ListTile( leading: IconButton( icon: Icon(Icons.present_to_all_sharp), onPressed: () { e.device.connect(timeout: Duration(seconds: 4)); }, ), subtitle: Text("${e.device.name }\n ${e.device.id.id}"), title: Text(e.device.id.toString()) )).toList(), ); } if (snapshot.hasError) { return Text("Error"); } else { return CircularProgressIndicator(); } }, ), ); } }
日志信息(翻译后)
权限被拒绝:ACCESS_COARSE_LOCATION
权限被拒绝:ACCESS_FINE_LOCATION
无法启动扫描:需要ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限
排查修复方案
1. 补全权限配置(核心问题)
从日志可以明确,扫描失败是因为缺少位置权限,Android平台要求BLE扫描必须获取位置权限:
- 在
android/app/src/main/AndroidManifest.xml中添加权限声明:<!-- 基础蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- 位置权限(BLE扫描必需) --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 12+ 新增权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> - 动态请求权限:使用
permission_handler包,在启动扫描前主动请求位置权限,示例代码:import 'package:permission_handler/permission_handler.dart'; // 在initState中添加权限请求 @override void initState() { super.initState(); requestPermissions(); } Future<void> requestPermissions() async { var status = await Permission.location.request(); if (status.isGranted) { widget.flutterBlue.startScan(timeout: Duration(seconds: 10)); } else { // 处理权限拒绝情况,提示用户开启权限 } }
2. 修复代码逻辑问题
- 初始化空列表:
result变量未初始化,直接调用result.add(r)会触发空指针异常,在initState中添加:result = []; - 统一实例使用:
StreamBuilder中使用FlutterBlue.instance.scanResults,建议改为传入的widget.flutterBlue.scanResults,保持实例一致性:stream: widget.flutterBlue.scanResults, - 添加扫描超时:避免持续扫描消耗电量,启动扫描时设置超时:
widget.flutterBlue.startScan(timeout: Duration(seconds: 10)); - 异常处理连接逻辑:连接设备时添加
try-catch捕获异常:onPressed: () async { try { await e.device.connect(timeout: Duration(seconds: 4)); // 连接成功后的业务逻辑 } catch (e) { print("连接失败:$e"); // 提示用户连接失败 } },
3. 设备端检查
- 确保测试设备蓝牙已正常开启,且目标BLE设备处于可广播/被发现状态;
- 针对Android 12+设备,需确认已授予
BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限。
内容的提问来源于stack exchange,提问作者Sana'a Al-ahdal
相关产品推荐
相关产品推荐

