You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 18:05:58