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

Flutter如何实现蓝牙设备选中后自动连接、打印完成后自动断开

Flutter蓝牙热敏打印机自动连接/断开实现方案

以下是针对你需求的最小改动方案,所有修改位置都做了标注:

一、核心修改点

1. 下拉选中设备自动连接

找到DropdownButton组件的onChanged回调,修改为选中设备后直接触发连接逻辑,同时先断开已有连接避免冲突。
同时优化_connect、_disconnect方法为异步,确保状态同步正确。

2. 打印完成自动断开

修改打印按钮的点击回调,等待打印任务完成后延迟几秒(确保打印机接收完所有数据)再自动触发断开操作。

二、修改后的完整代码

import 'dart:io';
import 'dart:typed_data';
import 'package:blue_thermal_printer_example/testprint.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:blue_thermal_printer/blue_thermal_printer.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final BlueThermalPrinter bluetooth = BlueThermalPrinter.instance;

  List<BluetoothDevice> _devices = [];
  BluetoothDevice? _device;
  bool _connected = false;
  String? pathImage;
  late TestPrint testPrint;

  @override
  void initState() {
    super.initState();
    initPlatformState();
    initSavetoPath();
    testPrint = TestPrint();
  }

  Future<void> initSavetoPath() async {
    const filename = 'yourlogo.png';
    var bytes = await rootBundle.load("assets/images/yourlogo.png");
    String dir = (await getApplicationDocumentsDirectory()).path;
    writeToFile(bytes, '$dir/$filename');
    setState(() {
      pathImage = '$dir/$filename';
    });
  }

  Future<void> initPlatformState() async {
    bool isConnected = await bluetooth.isConnected;
    List<BluetoothDevice> devices = [];
    try {
      devices = await bluetooth.getBondedDevices();
    } on PlatformException catch (e) {
      show('获取设备列表失败:$e');
    }

    bluetooth.onStateChanged().listen((state) {
      if (!mounted) return;
      switch (state) {
        case BlueThermalPrinter.CONNECTED:
          setState(() {
            _connected = true;
          });
          break;
        case BlueThermalPrinter.DISCONNECTED:
          setState(() {
            _connected = false;
          });
          break;
        default:
          print(state);
          break;
      }
    });

    if (!mounted) return;
    setState(() {
      _devices = devices;
    });

    if (isConnected) {
      setState(() {
        _connected = true;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('蓝牙热敏打印机'),
        ),
        body: Container(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: ListView(
              children: <Widget>[
                Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    const SizedBox(
                      width: 10,
                    ),
                    const Text(
                      '选择设备:',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(
                      width: 30,
                    ),
                    Expanded(
                      // 下拉选择自动连接修改点
                      child: DropdownButton<BluetoothDevice>(
                        isExpanded: true,
                        items: _getDeviceItems(),
                        onChanged: (value) async {
                          setState(() => _device = value);
                          if (_connected) {
                            await _disconnect();
                          }
                          _connect();
                        },
                        value: _device,
                        hint: const Text('请选择打印机'),
                      ),
                    ),
                  ],
                ),
                const SizedBox(
                  height: 10,
                ),
                Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: <Widget>[
                    ElevatedButton(
                      style: ElevatedButton.styleFrom(backgroundColor: Colors.brown),
                      onPressed: () {
                        initPlatformState();
                      },
                      child: const Text(
                        '刷新设备',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    const SizedBox(
                      width: 20,
                    ),
                    ElevatedButton(
                      style: ElevatedButton.styleFrom(
                          backgroundColor: _connected ? Colors.red : Colors.green),
                      onPressed: _connected ? _disconnect : _connect,
                      child: Text(
                        _connected ? '断开连接' : '手动连接',
                        style: const TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
                Padding(
                  padding:
                  const EdgeInsets.only(left: 10.0, right: 10.0, top: 50),
                  child: ElevatedButton(
                    style: ElevatedButton.styleFrom(backgroundColor: Colors.brown),
                    // 打印完成自动断开修改点
                    onPressed: () async {
                      if (_device == null) {
                        show('请先选择打印机');
                        return;
                      }
                      if (!_connected) {
                        show('打印机未连接');
                        return;
                      }
                      if (pathImage == null) {
                        show('资源加载中,请稍后再试');
                        return;
                      }
                      // 等待打印完成,需确保TestPrint的sample方法是异步返回Future
                      await testPrint.sample(pathImage!);
                      // 延迟2秒确保数据传输完成,可根据打印内容长度调整
                      await Future.delayed(const Duration(seconds: 2));
                      await _disconnect();
                      show('打印完成,已自动断开连接');
                    },
                    child: const Text('打印测试',
                        style: TextStyle(color: Colors.white)),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  List<DropdownMenuItem<BluetoothDevice>> _getDeviceItems() {
    List<DropdownMenuItem<BluetoothDevice>> items = [];
    if (_devices.isEmpty) {
      items.add(const DropdownMenuItem(
        value: null,
        child: Text('暂无可用设备'),
      ));
    } else {
      for (var device in _devices) {
        items.add(DropdownMenuItem(
          value: device,
          child: Text(device.name ?? '未知设备'),
        ));
      }
    }
    return items;
  }

  // 优化后的连接方法
  Future<void> _connect() async {
    if (_device == null) {
      show('未选择任何设备');
      return;
    }
    bool isConnected = await bluetooth.isConnected;
    if (!isConnected) {
      try {
        await bluetooth.connect(_device!);
        if (mounted) {
          setState(() => _connected = true);
        }
        show('连接成功');
      } catch (e) {
        if (mounted) {
          setState(() => _connected = false);
        }
        show('连接失败:$e');
      }
    }
  }

  // 优化后的断开方法
  Future<void> _disconnect() async {
    await bluetooth.disconnect();
    if (mounted) {
      setState(() => _connected = false);
    }
  }

  Future<void> writeToFile(ByteData data, String path) {
    final buffer = data.buffer;
    return File(path).writeAsBytes(
        buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
  }

  Future show(
      String message, {
        Duration duration = const Duration(seconds: 3),
      }) async {
    await Future.delayed(const Duration(milliseconds: 100));
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            message,
            style: const TextStyle(
              color: Colors.white,
            ),
          ),
          duration: duration,
        ),
      );
    }
  }
}

三、注意事项

  • 请确保TestPrint类中的sample方法为异步方法,返回Future<void>,否则无法正确等待打印完成,示例如下:
// TestPrint类中的sample方法修改示例
Future<void> sample(String pathImage) async {
  // 原有打印逻辑,所有调用blue_thermal_printer的方法前加await
  await BlueThermalPrinter.instance.printNewLine();
  await BlueThermalPrinter.instance.printImage(pathImage);
  // ...其他打印逻辑
}
  • 打印后的延迟时间可根据实际打印内容长度调整,打印二维码、长文本时建议调长到3-5秒
  • 已适配空安全语法,如果你使用的是旧版Flutter可移除空安全相关符号(?、!、late、super.key)

内容的提问来源于stack exchange,提问作者Newbie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 17:27:01