Flutter用bluetooth_print后台打印小票失败,startScan调用报错求解决
解决Flutter蓝牙打印后台报错问题
核心原因
安卓系统的后台进程限制会导致Flutter引擎在APP退到后台后被暂停,bluetooth_print插件的MethodChannel依赖Flutter引擎运行,此时调用原生方法就会出现找不到实现的错误。另外,普通后台服务插件可能未正确绑定Flutter引擎,或者没处理蓝牙权限的后台访问限制。
具体解决方案
1. 配置安卓后台权限
- 在
AndroidManifest.xml中添加必要权限:<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" /> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> - 引导用户关闭APP的电池优化,避免系统强制杀死后台进程,可在APP首次启动时弹窗提示用户手动操作。
2. 用前台服务绑定Flutter引擎
安卓高版本(API 26+)对普通后台服务限制严格,必须用前台服务保持进程存活,同时要确保Flutter引擎在服务内初始化:
- 自定义安卓原生前台服务,在服务中初始化Flutter引擎并注册
bluetooth_print的MethodChannel:- 创建继承自
FlutterService的服务类:class PrintBackgroundService : FlutterService() { private lateinit var flutterEngine: FlutterEngine override fun onCreate() { super.onCreate() flutterEngine = FlutterEngine(this) flutterEngine.dartExecutor.executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ) // 注册插件通道,关联原生实现 MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "bluetooth_print/methods") .setMethodCallHandler { call, result -> when (call.method) { "startScan" -> { // 调用bluetooth_print原生扫描逻辑 result.success(null) } // 其他蓝牙操作方法同理处理 } } // 启动前台服务,显示常驻通知 val notification = NotificationCompat.Builder(this, "print_channel") .setContentTitle("订单打印服务") .setContentText("正在监听新订单") .setSmallIcon(R.drawable.ic_notification) .build() startForeground(1, notification) } } - 在
AndroidManifest.xml中注册服务:<service android:name=".PrintBackgroundService" android:foregroundServiceType="connectedDevice" />
- 创建继承自
- Flutter端启动前台服务后,将打印逻辑放在服务绑定的Isolate中执行,避免依赖主引擎。
3. 调整Firebase通知处理逻辑
收到Firebase通知时,不要直接在Flutter端触发打印,而是通过原生通知接收器启动前台服务,由服务内的Flutter引擎执行打印:
- 在安卓原生的
FirebaseMessagingService中处理通知:class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 判断为订单通知时启动打印服务 val intent = Intent(this, PrintBackgroundService::class.java) intent.putExtra("order_data", remoteMessage.data) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent) } else { startService(intent) } } } - 在前台服务中接收订单数据,调用蓝牙打印逻辑。
4. 规避UI线程依赖
bluetooth_print部分方法可能依赖UI线程,后台时UI线程会被挂起,要确保打印逻辑在后台线程执行,且不依赖Flutter的UI上下文。
额外注意事项
- 测试使用安卓真机,模拟器后台行为与真机存在差异。
- 针对API 31+版本,需动态申请
BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限,并明确告知用户权限用途。
内容的提问来源于stack exchange,提问作者Flutter Dev
相关产品推荐
相关产品推荐

