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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 14:15:53