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

Android USB直连激光打印机打印失败,求可行实现方案

Android USB 激光打印机直接打印问题解决方案

现有代码的核心问题

  • 权限请求是异步操作,你在checkInfo()中直接调用startPrinting()时,权限尚未授予,导致设备无法正常打开
  • 未筛选USB设备,遍历所有设备后仅取最后一个,没有判断是否为打印机
  • 错误选择USB端点:直接取第一个端点,未确认是**输出(OUT)**方向的端点(打印机需要向OUT端点发送数据)
  • 数据发送逻辑错误:UsbRequest使用时未向output_buffer写入要发送的数据,导致无内容传输
  • 广播接收器获取权限后未触发打印逻辑,权限授予后的处理代码为空

修复后的代码示例

public class MainActivity extends Activity {
    PendingIntent mPermissionIntent;
    Button btnCheck;
    TextView textInfo;
    UsbDevice targetPrinter;
    UsbManager manager;
    private static final String ACTION_USB_PERMISSION = "com.example.myapp.USB_PERMISSION";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnCheck = findViewById(R.id.check);
        textInfo = findViewById(R.id.info);
        btnCheck.setOnClickListener(v -> {
            textInfo.setText("");
            scanForPrinters();
        });
    }

    private void scanForPrinters() {
        manager = (UsbManager) getSystemService(Context.USB_SERVICE);
        mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        registerReceiver(mUsbReceiver, filter);

        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
        for (UsbDevice device : deviceList.values()) {
            // 通过USB设备类筛选打印机(类编号为7)
            if (device.getDeviceClass() == UsbConstants.USB_CLASS_PRINTER) {
                targetPrinter = device;
                manager.requestPermission(device, mPermissionIntent);
                return; // 找到第一个打印机设备,可根据需求调整为多选
            }
        }
        textInfo.setText("未找到USB连接的打印机");
    }

    private void startPrinting(final UsbDevice printerDevice) {
        new Thread(() -> {
            UsbDeviceConnection conn = null;
            UsbInterface usbInterface = null;
            try {
                // 获取打印机的第一个接口(通常打印机仅一个接口)
                usbInterface = printerDevice.getInterface(0);
                UsbEndpoint outEndpoint = null;
                // 寻找输出方向的端点
                for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
                    UsbEndpoint endpoint = usbInterface.getEndpoint(i);
                    if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                        outEndpoint = endpoint;
                        break;
                    }
                }
                if (outEndpoint == null) {
                    Log.e("PrintError", "未找到输出端点");
                    runOnUiThread(() -> textInfo.setText("未找到打印机输出端点"));
                    return;
                }

                // 打开设备并建立连接
                conn = manager.openDevice(printerDevice);
                if (conn == null) {
                    Log.e("PrintError", "无法打开打印机设备");
                    runOnUiThread(() -> textInfo.setText("无法打开打印机设备"));
                    return;
                }

                // 声明USB接口
                if (!conn.claimInterface(usbInterface, true)) {
                    Log.e("PrintError", "无法声明USB接口");
                    runOnUiThread(() -> textInfo.setText("无法声明USB接口"));
                    return;
                }

                // 准备打印数据(使用ESC/POS指令,大部分激光打印机支持)
                String printData = "\n这是测试打印内容\n\n" +
                        "----------------\n" +
                        "测试完成\n";
                byte[] dataBytes = printData.getBytes(StandardCharsets.UTF_8);

                // 使用bulkTransfer发送数据(更简单可靠)
                int transferred = conn.bulkTransfer(outEndpoint, dataBytes, dataBytes.length, 5000);
                if (transferred > 0) {
                    Log.i("PrintSuccess", "已传输 " + transferred + " 字节数据");
                    runOnUiThread(() -> textInfo.setText("打印请求已发送"));
                } else {
                    Log.e("PrintError", "数据传输失败,返回值:" + transferred);
                    runOnUiThread(() -> textInfo.setText("数据传输失败"));
                }

            } catch (Exception e) {
                Log.e("PrintException", "打印失败", e);
                runOnUiThread(() -> textInfo.setText("打印失败:" + e.getMessage()));
            } finally {
                // 释放资源
                if (conn != null && usbInterface != null) {
                    conn.releaseInterface(usbInterface);
                    conn.close();
                }
                try {
                    unregisterReceiver(mUsbReceiver);
                } catch (Exception e) {
                    Log.e("ResourceError", "释放接收器失败", e);
                }
            }
        }).start();
    }

    private final BroadcastReceiver mUsbReceiver = new 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 && device.equals(targetPrinter)) {
                            startPrinting(device);
                        }
                    } else {
                        Log.d("PrintError", "权限被拒绝:" + device);
                        runOnUiThread(() -> textInfo.setText("打印机权限被拒绝"));
                    }
                }
            }
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            unregisterReceiver(mUsbReceiver);
        } catch (Exception ignored) {}
    }
}

修复说明

  • 增加打印机设备筛选逻辑,通过USB设备类编号精准识别打印机
  • 权限请求完成后在广播接收器中触发打印,确保权限已授予
  • 正确寻找输出方向的USB端点,避免发送到错误端点
  • 使用更稳定的bulkTransfer方法发送数据,简化实现逻辑
  • 补充错误处理和UI反馈,便于排查问题
  • 修复资源释放逻辑,避免内存泄漏

可用实现库推荐

  • USB Printer Library:针对Android USB打印封装的轻量库,支持ESC/POS指令集,兼容大部分激光、热敏打印机,无需手动处理USB权限和端点逻辑
  • Android Print Framework:Android 4.4及以上系统自带的打印框架,系统自动处理设备发现和权限,只需构建打印文档即可,缺点是依赖打印机厂商驱动支持,部分小众设备可能不兼容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:47:33