Android USB OTG连接Zebra打印机:bulkTransfer返回值问题求助
USB OTG连接Zebra打印机的Android实现
最近我尝试在Android设备上通过USB OTG连接Zebra打印机,根据官方文档,UsbDeviceConnection#bulkTransfer的返回值规则是:成功时返回传输的数据长度(非负,包括0),失败时返回负值。下面是我完整的实现代码,包含设备枚举、权限申请、打印逻辑等核心部分:
package in.silentsudo.andoidprinter.usbprinter; import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Map; import in.silentsudo.andoidprinter.R; public class MainActivity extends Activity { private UsbManager mUsbManager; private UsbDevice mUsbDevice; private PendingIntent mPermissionIntent; private UsbDeviceConnection usbConnection; UsbEndpoint usbWriterEndpoint; UsbInterface usbInterface; private static final String ACTION_USB_PERMISSION = "in.silentsudo.usbprinter.USB_PERMISSION"; private StringBuffer logBuffer = new StringBuffer(); private TextView textView; private Button button; protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.activity_main); textView = findViewById(R.id.txt_status); button = findViewById(R.id.btn_print); addLog("Creating usbConnection"); mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); String usbManagerString = mUsbManager == null ? "USBManager is null" : "USB manager is valid"; addLog(usbManagerString); } @Override protected void onResume() { super.onResume(); mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(mUsbReceiver, filter); addLog("Registered received with filter :" + ACTION_USB_PERMISSION); if (mUsbManager != null) { if (mUsbManager.getDeviceList() != null && mUsbManager.getDeviceList().size() > 0) { addLog("Total usb devices: " + mUsbManager.getDeviceList().size()); for (Map.Entry<String, UsbDevice> entry : mUsbManager.getDeviceList().entrySet()) { addLog(" " + entry.getKey() + " -> " + entry.getValue().getSerialNumber()); mUsbDevice = entry.getValue(); // 申请设备权限 mUsbManager.requestPermission(mUsbDevice, mPermissionIntent); } } else { addLog("No device connected"); } } addLog("Waiting for usbConnection"); addLog("Setting up interfaces"); setUpInterfaces(); } @Override protected void onPause() { super.onPause(); unregisterReceiver(mUsbReceiver); if (usbConnection != null) { usbConnection.releaseInterface(usbInterface); usbConnection.close(); } } public void setUpInterfaces() { if (mUsbDevice != null) { int interfaceCount = mUsbDevice.getInterfaceCount(); addLog(mUsbDevice.getSerialNumber() + " has total " + interfaceCount + " Interface count"); for (int i = 0; i < interfaceCount; i++) { final UsbInterface usbInterface = mUsbDevice.getInterface(i); addLog(" usb at index " + i + " " + getInterfaceDataAsString(usbInterface)); final int endpointCount = usbInterface.getEndpointCount(); addLog(" " + usbInterface.getId() + " has total " + endpointCount + " endpoints"); // 遍历所有端点,找到输出类型的端点(更通用的写法) for(int j=0; j<endpointCount; j++){ UsbEndpoint endpoint = usbInterface.getEndpoint(j); printUsbEndPointAsString(endpoint); // 判断是否为输出端点(用于写入数据到打印机) if(endpoint.getDirection() == UsbEndpoint.DIRECTION_OUT){ usbWriterEndpoint = endpoint; this.usbInterface = usbInterface; addLog("Selected output endpoint: " + endpoint.getAddress()); break; } } } } } final String THREAD_TAG = "BG THREAD:-> "; public boolean connectAndClaim() { if(mUsbDevice == null || usbInterface == null) return false; usbConnection = mUsbManager.openDevice(mUsbDevice); if (usbConnection != null) { Log.e("Connection:", " connected"); addLog("Device connected"); // 声明接口,获取访问权限 boolean claimed = usbConnection.claimInterface(usbInterface, true); addLog("Interface claimed: " + claimed); return claimed; } addLog("Failed to open device connection"); return false; } public void writeToPrinter(final String contentToBeWritten) { // 先确保连接并声明接口成功 if(!connectAndClaim()){ addLog("Failed to connect or claim interface, cannot print"); return; } Thread thread = new Thread(new Runnable() { @Override public void run() { try { addLog(THREAD_TAG + "Writing to usbConnection"); addLog(THREAD_TAG + " Content to be written `" + contentToBeWritten + "`"); addLog(THREAD_TAG + " Content size`" + contentToBeWritten.length() + "`"); byte[] bytes = contentToBeWritten.getBytes(); int transferResult = usbConnection.bulkTransfer(usbWriterEndpoint, bytes, bytes.length, 50000); if(transferResult >=0){ addLog(THREAD_TAG + "Successfully transferred " + transferResult + " bytes"); } else { addLog(THREAD_TAG + "Transfer failed, error code: " + transferResult); } addLog(THREAD_TAG + "Written to usbConnection"); } catch (Exception e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String exceptionAsString = sw.toString(); addLog(THREAD_TAG + exceptionAsString); } finally { // 打印完成后释放资源 if(usbConnection != null){ usbConnection.releaseInterface(usbInterface); usbConnection.close(); } } } }); thread.start(); } private void printUsbEndPointAsString(UsbEndpoint point) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(point.toString()); stringBuilder.append(", type: ").append(getEndpointType(point.getType())); stringBuilder.append(", direction: ").append(point.getDirection() == UsbEndpoint.DIRECTION_OUT ? "OUT" : "IN"); stringBuilder.append(", address: ").append(point.getAddress()); addLog(" Endpoint info: " + stringBuilder.toString()); } private String getEndpointType(int type){ switch (type){ case UsbEndpoint.TYPE_BULK: return "BULK"; case UsbEndpoint.TYPE_CONTROL: return "CONTROL"; case UsbEndpoint.TYPE_INTERRUPT: return "INTERRUPT"; default: return "UNKNOWN"; } } private String getInterfaceDataAsString(UsbInterface usbInterface) { return "ID: " + usbInterface.getId() + ", Class: " + usbInterface.getInterfaceClass(); } private void addLog(String log) { logBuffer.append(log).append("\n"); // 确保在主线程更新UI textView.post(() -> textView.setText(logBuffer.toString())); Log.d("USB_PRINTER", log); } private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 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 (device != null) { if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { addLog("Permission granted for device: " + device.getSerialNumber()); mUsbDevice = device; setUpInterfaces(); } else { addLog("Permission denied for device: " + device.getSerialNumber()); } } } } } }; }
关键实现优化说明:
- 权限申请逻辑补充:在枚举到设备后主动调用
requestPermission申请访问权限,配合广播接收器处理权限结果,确保能合法访问打印机。 - 端点选择优化:不再固定选择index=1的端点,而是遍历所有端点找到**输出类型(DIRECTION_OUT)**的端点,适配更多型号的Zebra打印机。
- 资源管理完善:在打印完成后主动关闭连接、释放接口,避免资源泄漏;在
onPause中也完善了资源释放逻辑。 - 结果判断清晰化:对
bulkTransfer的返回值做了明确的成功/失败判断,方便排查传输问题。 - 日志输出增强:补充了端点类型、方向等关键信息的日志,便于调试时确认设备接口是否匹配。
内容的提问来源于stack exchange,提问作者silentsudo
相关产品推荐
相关产品推荐

