Android 13蓝牙连接失败:read failed socket超时/关闭错误求助
蓝牙连接失败报错:read failed, socket might closed or timeout 的解决方法
核心报错分析
connect_error, read failed, socket might closed or timeout, read ret: -1, java.io.IOException: read failed, socket might closed or timeout, read ret: -1
该报错常见于SPP蓝牙连接场景,结合你提供的BluetoothPrintService.java代码,问题通常源于Socket创建兼容性、权限缺失、连接时序或流读取逻辑异常,以下是针对性修复方案:
修复方案
1. 替换Socket创建方式(解决设备兼容性问题)
部分老旧蓝牙打印机对系统默认的createRfcommSocketToServiceRecord方法兼容性较差,改用反射获取Rfcomm通道的方式创建Socket,同时保留原方法作为降级方案:
修改ConnectThread构造方法:
public ConnectThread(BluetoothDevice device, boolean secure) { mmDevice = device; BluetoothSocket tmp = null; mSocketType = secure ? "Secure" : "Insecure"; try { // 优先尝试反射方式创建Socket if (secure) { Method method = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class}); tmp = (BluetoothSocket) method.invoke(device, 1); } else { Method method = device.getClass().getMethod("createInsecureRfcommSocket", new Class[]{int.class}); tmp = (BluetoothSocket) method.invoke(device, 1); } } catch (Exception e) { // 反射失败时降级到原方法 try { if (secure) { tmp = device.createRfcommSocketToServiceRecord(SPP_UUID); } else { tmp = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID); } } catch (IOException e2) { Log.e(TAG, "Socket Type: " + mSocketType + " create() failed", e2); } } mmSocket = tmp; }
2. 补全蓝牙相关权限
在AndroidManifest.xml中添加完整的蓝牙权限,并在运行时动态申请敏感权限:
<!-- 基础蓝牙权限 --> <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" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- 部分设备搜索蓝牙需要位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
3. 给连接添加超时控制
原代码中mmSocket.connect()是无超时的阻塞调用,易因设备响应慢触发超时。通过线程池+Future实现超时控制:
修改ConnectThread的run方法:
public void run() { Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType); setName("ConnectThread" + mSocketType); mAdapter.cancelDiscovery(); // 用线程池实现连接超时控制 ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Boolean> future = executor.submit(() -> { try { mmSocket.connect(); return true; } catch (IOException e) { return false; } }); try { // 设置10秒连接超时 if (!future.get(10, TimeUnit.SECONDS)) { throw new IOException("Connection timeout"); } } catch (Exception e) { try { mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2); } Log.e(TAG, "Connection Failed", e); connectionFailed(); executor.shutdownNow(); return; } executor.shutdown(); synchronized (BluetoothPrintService.this) { mConnectThread = null; } connected(mmSocket, mmDevice, mSocketType); }
4. 修复输入流读取逻辑
原代码中未处理mmInStream.read(buffer)返回-1的情况(输入流正常关闭的标识),导致误触发connectionLost:
修改ConnectedThread的run方法:
public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; while (true) { try { bytes = mmInStream.read(buffer); if (bytes == -1) { // 输入流正常关闭,主动触发连接断开逻辑 connectionLost(); break; } byte[] rcvData = Arrays.copyOf(buffer, bytes); mHandler.obtainMessage(WoosimPrnMng.MESSAGE_READ, bytes, -1, rcvData).sendToTarget(); } catch (IOException e) { Log.e(TAG, "Connection Lost", e); connectionLost(); break; } } }
额外排查点
- 确认目标蓝牙设备的SPP服务UUID是否为
00001101-0000-1000-8000-00805F9B34FB,部分设备可能使用自定义UUID,需通过蓝牙调试工具验证。 - 检查设备是否已完成配对,部分打印机要求先配对再建立连接。
- 用其他蓝牙设备(如手机)测试,排除目标设备自身故障。
内容的提问来源于stack exchange,提问作者YuvrajsinhJadeja
相关产品推荐
相关产品推荐

