Flutter Android端前台服务终止导致BLE连接断开问题求助
Android端Flutter BLE后台恢复自动断开问题解决方案
问题概述
用flutter_reactive_ble连接BLE设备时,Android端在后台恢复(锁屏后切回、切换应用返回)时会自动断开连接,iOS端无此异常。排查发现应用后台恢复时后台服务会触发service.stopSelf(),进而触发BLE连接断开逻辑,用flutter_background_service后问题依旧。
环境信息
System: Android Flutter Version: 3.16.7 Package Versions: flutter_reactive_ble: v5.3.1 flutter_background_service : v5.0.5
解决方案
1. 防止后台服务被误停止
检查应用生命周期相关代码,确认是否在后台恢复时错误发送了stopService事件给后台服务。修改后台服务逻辑,增加防护判断:
@pragma('vm:entry-point') void onStart(ServiceInstance service) async { DartPluginRegistrant.ensureInitialized(); if (service is AndroidServiceInstance) { service.on('setAsForeground').listen((event) { service.setAsForegroundService(); }); service.on('setAsBackground').listen((event) { service.setAsBackgroundService(); }); } // 增加验证逻辑,避免误触发停止 service.on('stopService').listen((event) { // 可根据实际需求添加判断条件,比如仅在指定场景下停止服务 // 示例:if (event['forceStop'] == true) service.stopSelf(); }); }
2. 配置前台服务权限与运行模式
Android对后台进程限制严格,BLE长连接必须依赖前台服务才能稳定运行:
- 在
AndroidManifest.xml中添加必要权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- 启动后台服务后直接设置为前台模式,避免被系统回收:
// 启动服务后立即调用 await FlutterBackgroundService().invoke("setAsForeground");
3. 优化BLE连接,添加自动重连
修改flutter_reactive_ble连接代码,开启自动重连并增加异常重连逻辑:
StreamSubscription<ConnectionStateUpdate>? deviceStream; // 封装连接方法,方便重复调用 void connectToBleDevice(Device device, int index) { deviceStream = flutterReactiveBle .connectToDevice( id: device.id, connectionTimeout: const Duration(seconds: 5), // 启用系统自动重连 autoConnect: true) .listen( (connectionState) { if (connectionState.connectionState == DeviceConnectionState.connected) { // 连接成功后的业务处理 } else if (connectionState.connectionState == DeviceConnectionState.disconnected) { print("BLE Disconnect is disconnected"); // 延迟2秒后尝试重连,可根据需求调整时长或增加重连次数限制 Future.delayed(const Duration(seconds: 2), () { connectToBleDevice(device, index); }); onDisconnect(index, true); } }, onError: (error) { print("BLE Disconnect connection error = $error"); // 连接出错时同样触发重连 Future.delayed(const Duration(seconds: 2), () { connectToBleDevice(device, index); }); }, ); }
提示:
autoConnect: true会让系统在设备可连接时自动尝试重连,但要确保设备处于可被扫描到的状态。
4. 监听应用生命周期,主动恢复连接
在应用从后台切回前台时,检查BLE连接状态,若已断开则主动重建:
// 在StatefulWidget的生命周期方法中监听 @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.resumed) { // 检查当前设备连接状态,若未连接则触发重连 if (currentConnectionState != DeviceConnectionState.connected) { connectToBleDevice(currentDevice, currentIndex); } } }
5. 后台服务持有BLE连接实例
把BLE连接实例放在后台服务中初始化和管理,避免因UI层生命周期销毁导致连接断开:
@pragma('vm:entry-point') void onStart(ServiceInstance service) async { DartPluginRegistrant.ensureInitialized(); FlutterReactiveBle flutterReactiveBle = FlutterReactiveBle(); StreamSubscription<ConnectionStateUpdate>? deviceStream; // 监听UI层发送的连接指令 service.on('connectDevice').listen((event) { String deviceId = event['deviceId']; deviceStream = flutterReactiveBle.connectToDevice( id: deviceId, connectionTimeout: const Duration(seconds: 5), autoConnect: true, ).listen((state) { // 把连接状态同步给UI层 service.sendEvent(event: { 'connectionState': state.connectionState.name, 'deviceId': deviceId, }); }); }); // 监听UI层发送的断开指令 service.on('disconnectDevice').listen((event) { deviceStream?.cancel(); }); if (service is AndroidServiceInstance) { service.on('setAsForeground').listen((event) { service.setAsForegroundService(); }); service.on('setAsBackground').listen((event) { service.setAsBackgroundService(); }); } service.on('stopService').listen((event) { deviceStream?.cancel(); service.stopSelf(); }); }
这样BLE连接由后台服务持有,不受UI页面销毁或后台切换的影响。
内容的提问来源于stack exchange,提问作者Naografix
相关产品推荐
相关产品推荐

