Flutter Blue Plus扫描BLE设备后无结果显示求助
解决Flutter Blue Plus扫描BLE设备scanResults为空的问题
以下是导致扫描不到设备的核心问题及对应修复方案:
1. 扫描时间过短且逻辑错误
你的scan()方法中设置扫描超时仅100毫秒,且启动扫描后立刻调用stopScan(),导致扫描根本来不及发现设备。同时startScan()会在超时后自动停止,无需手动调用stopScan()。
修复后的scan方法:
Future scan() async { // 确保蓝牙已开启 final state = await FlutterBluePlus.adapterState.first; if (state != BluetoothAdapterState.on) { print("蓝牙未开启,无法扫描"); return; } // 先停止之前的扫描(如果存在) if (FlutterBluePlus.isScanningNow) { await FlutterBluePlus.stopScan(); } // 启动扫描,延长超时时间至5秒 await FlutterBluePlus.startScan( timeout: const Duration(seconds: 5), androidUsesFineLocation: false, ); }
2. 权限请求不完整(适配Android 12+)
Android 12及以上版本对BLE新增了BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限,仅请求bluetooth权限不足以完成扫描;Android 11及以下版本还需要位置权限才能扫描BLE设备。
修复权限请求逻辑:
更新initializeBluetooth()方法:
Future<void> initializeBluetooth() async { Map<Permission, PermissionStatus> statuses; if (Platform.isAndroid) { if (await Permission.bluetooth.isDenied) { // 请求Android 12+所需蓝牙权限 statuses = await [ Permission.bluetooth, Permission.bluetoothScan, Permission.bluetoothConnect, ].request(); } // Android 11及以下需要位置权限 if (Platform.version.contains("11")) { if (await Permission.location.isDenied) { await Permission.location.request(); } } } else if (Platform.isIOS) { // iOS请求蓝牙权限 if (await Permission.bluetooth.isDenied) { await Permission.bluetooth.request(); } } // 检查蓝牙可用性 if (await FlutterBluePlus.isAvailable) { final state = await FlutterBluePlus.adapterState.first; if (state == BluetoothAdapterState.off) { if (Platform.isAndroid) { try { await FlutterBluePlus.turnOn(); } catch (e) { print("开启蓝牙失败: $e"); } } else if (Platform.isIOS) { // iOS无法通过代码开启蓝牙,引导用户手动操作 print("请手动开启蓝牙"); } } } else { print("设备不支持蓝牙"); } }
3. 修复Stream订阅与生命周期管理
你的subscription在类初始化时就创建,但未在控制器销毁时取消,可能导致内存泄漏。同时要确保订阅在蓝牙准备好后再监听。
修复控制器的订阅逻辑:
class BleConnexionController extends GetxController { late BluetoothDevice connectedDevice; Stream<List<ScanResult>> get scanResults => FlutterBluePlus.scanResults; StreamSubscription<List<ScanResult>>? _scanSubscription; // 改为可空类型 @override void onInit() { super.onInit(); initializeBluetooth().then((_) { // 蓝牙初始化完成后再订阅扫描结果 _scanSubscription = FlutterBluePlus.scanResults.listen( (results) { for (ScanResult r in results) { print('${r.device.remoteId}: "${r.device.localName}" found! rssi: ${r.rssi}'); } update(); // 通知GetBuilder更新UI }, onError: (e) => print("扫描错误: $e"), ); }); } @override void onClose() { // 销毁时取消订阅,避免内存泄漏 _scanSubscription?.cancel(); super.onClose(); } // ... 其他方法保持修改后的逻辑 }
4. 调整视图中的GetX控制器使用
GetView已自动提供控制器实例,无需在GetBuilder中再次init,否则会创建新的控制器实例,导致Stream监听失效。
修复后的View代码:
class BleConnexionView extends GetView<BleConnexionController> { const BleConnexionView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('BLE设备扫描'), centerTitle: true, ), body: GetBuilder<BleConnexionController>( // 移除init参数,使用GetView提供的控制器 builder: (controller) { return SingleChildScrollView( child: Column( children: [ const SizedBox(height: 20), Center( child: ElevatedButton( onPressed: () => controller.scan(), child: const Text("开始扫描"), ), ), StreamBuilder<List<ScanResult>>( stream: controller.scanResults, builder: (context, snapshot) { if (snapshot.hasData && snapshot.data!.isNotEmpty) { return ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), // 避免嵌套滚动冲突 itemCount: snapshot.data!.length, itemBuilder: (context, index) { final data = snapshot.data![index]; return Card( elevation: 2, child: ListTile( title: Text(data.device.localName.isEmpty ? "未知设备" : data.device.localName), subtitle: Text(data.device.remoteId.str), trailing: ElevatedButton( onPressed: () async { controller.connectedDevice = data.device; // controller.connectDevice().then((value) => Get.off(const HomePage())); }, child: const Text("连接"), ), ), ); }, ); } else if (snapshot.connectionState == ConnectionState.active) { return const Center(child: Text("扫描中...")); } else { return const Center(child: Text("未发现设备")); } }, ), ], ), ); }, ), ); } }
5. 配置AndroidManifest权限
在android/app/src/main/AndroidManifest.xml中添加必要权限:
<!-- 基础蓝牙权限(Android 11及以下) --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android 12+ 蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- Android 11及以下位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" /> <!-- 声明设备支持BLE --> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
完成以上修改后,重新运行应用,点击扫描按钮即可正常发现BLE设备。
内容的提问来源于stack exchange,提问作者Mohamed Farouk Ayadi
相关产品推荐
相关产品推荐

