如何将Android应用连接至打印机?USB端口打印机应用开发咨询
Android 应用连接外部打印机的实现方法
嘿,我之前开发打印类应用时也遇到过这个问题——Android官方文档确实在「实际设备连接」这块讲得比较零散,没给太直接的步骤。我来给你梳理下USB和常见蓝牙打印机的具体实现方法,都是经过实际验证的:
USB打印机连接实现
1. 先配置权限和过滤规则
首先要在AndroidManifest.xml里声明USB相关权限,同时注册广播接收器监听设备连接:
<!-- 声明USB Host功能(非强制,根据设备情况) --> <uses-feature android:name="android.hardware.usb.host" android:required="false" /> <!-- USB权限申请 --> <uses-permission android:name="android.permission.USB_PERMISSION" /> <application ...> <!-- 监听USB设备插入的广播接收器 --> <receiver android:name=".UsbPrinterReceiver"> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <!-- 关联设备过滤文件 --> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/usb_device_filter" /> </receiver> </application>
然后在res/xml目录下创建usb_device_filter.xml,用来指定你要连接的打印机(可以通过VID/PID精准匹配,或者留空匹配所有USB设备):
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- 替换成你的打印机的VID和PID,可通过adb命令或设备手册获取 --> <usb-device vendor-id="1234" product-id="5678" /> <!-- 如果暂时不知道VID/PID,也可以用下面的通用匹配 --> <!-- <usb-device /> --> </resources>
2. 检测设备并请求权限
在你的Activity里,通过UsbManager枚举已连接的USB设备,识别出打印机后向用户申请权限:
private static final String ACTION_USB_PERMISSION = "com.your.package.USB_PERMISSION"; private void scanUsbPrinters() { UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList(); for (UsbDevice device : deviceList.values()) { // 这里可以通过设备名称、VID/PID判断是否是目标打印机 if (isTargetPrinter(device)) { // 构造权限请求的PendingIntent PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE); usbManager.requestPermission(device, permissionIntent); break; } } } // 自定义判断逻辑,比如根据设备名称或VID/PID private boolean isTargetPrinter(UsbDevice device) { return device.getVendorId() == 1234 && device.getProductId() == 5678; }
然后创建广播接收器UsbPrinterReceiver处理权限结果:
public class UsbPrinterReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if(device != null){ // 权限获取成功,开始连接打印机 ((YourActivity)context).connectToUsbPrinter(device); } } else { Log.d("UsbPrinter", "用户拒绝了USB权限"); } } } } }
3. 连接设备并发送打印数据
拿到权限后,就可以通过UsbDeviceConnection建立连接,发送打印指令(注意:不同打印机的指令集不同,比如热敏打印机常用ESC/POS指令):
private void connectToUsbPrinter(UsbDevice device) { // 通常打印机的第一个接口是打印相关的 UsbInterface usbInterface = device.getInterface(0); // 获取输出端点(Bulk类型) UsbEndpoint endpoint = usbInterface.getEndpoint(0); UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); UsbDeviceConnection connection = usbManager.openDevice(device); if (connection != null && connection.claimInterface(usbInterface, true)) { // 构造打印数据,这里以ESC/POS指令为例:打印文字+换行+切纸 byte[] printData = ("Hello, USB Printer!\n").getBytes(); // 添加切纸指令(ESC/POS:0x1B 0x69) byte[] cutCommand = {0x1B, 0x69}; byte[] fullData = ByteBuffer.allocate(printData.length + cutCommand.length) .put(printData) .put(cutCommand) .array(); // 发送数据 int bytesWritten = connection.bulkTransfer(endpoint, fullData, fullData.length, 5000); if (bytesWritten > 0) { Toast.makeText(this, "打印成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "打印失败", Toast.LENGTH_SHORT).show(); } // 用完记得释放资源 connection.releaseInterface(usbInterface); connection.close(); } else { Toast.makeText(this, "无法连接打印机", Toast.LENGTH_SHORT).show(); } }
蓝牙打印机连接实现
如果你的打印机是蓝牙连接的,流程类似但用蓝牙API:
1. 配置蓝牙权限
在AndroidManifest.xml里声明蓝牙权限(注意适配Android 12+的新权限):
<!-- 基础蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- Android 12+ 需要的连接权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" android:maxSdkVersion="33" /> <!-- 蓝牙搜索权限(Android 12+ 需单独申请) --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" android:maxSdkVersion="33" />
2. 搜索并配对蓝牙打印机
先开启蓝牙,然后搜索设备,找到目标打印机后配对(如果未配对):
private static final int REQUEST_ENABLE_BT = 1; private BluetoothAdapter bluetoothAdapter; private void initBluetooth() { bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) { Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show(); return; } // 开启蓝牙 if (!bluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } else { startScanPrinters(); } } private void startScanPrinters() { // 注册广播接收器监听搜索结果 BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 通过设备名称识别打印机 if (device.getName() != null && device.getName().contains("Printer")) { if (device.getBondState() != BluetoothDevice.BOND_BONDED) { // 未配对,发起配对请求 try { Method method = device.getClass().getMethod("createBond"); method.invoke(device); } catch (Exception e) { e.printStackTrace(); } } else { // 已配对,直接连接 connectToBluetoothPrinter(device); } } } } }; IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(bluetoothReceiver, filter); // 开始搜索蓝牙设备 bluetoothAdapter.startDiscovery(); }
3. 建立连接并打印
蓝牙打印机通常使用RFCOMM串口服务,用通用的串口UUID(00001101-0000-1000-8000-00805F9B34FB)连接:
private void connectToBluetoothPrinter(BluetoothDevice device) { // 注意:必须在子线程执行,避免ANR new Thread(() -> { try { // 获取RFCOMM套接字 BluetoothSocket socket = device.createRfcommSocketToServiceRecord( UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); socket.connect(); OutputStream outputStream = socket.getOutputStream(); // 发送打印数据(同样用ESC/POS指令) byte[] printData = ("Hello, Bluetooth Printer!\n").getBytes(); byte[] cutCommand = {0x1B, 0x69}; outputStream.write(printData); outputStream.write(cutCommand); outputStream.flush(); // 关闭资源 outputStream.close(); socket.close(); // 回到主线程提示结果 runOnUiThread(() -> Toast.makeText(this, "打印成功", Toast.LENGTH_SHORT).show()); } catch (IOException e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(this, "连接打印机失败", Toast.LENGTH_SHORT).show()); } }).start(); }
关键注意事项
- 指令集适配:不同品牌的打印机指令集可能不同,一定要参考打印机的官方手册,比如ESC/POS是热敏打印机的通用指令集,包含换行、加粗、切纸等命令。
- 线程处理:所有设备连接、数据发送的操作都必须放在子线程中,绝对不能在主线程执行,否则会触发ANR。
- 版本适配:不同Android版本的权限要求差异很大,比如Android 10+的USB权限弹窗逻辑,Android 12+的蓝牙分区权限,一定要做好适配。
内容的提问来源于stack exchange,提问作者Vadim Has




