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

Android 11-14蓝牙连接报错:java.io.IOException: read failed求助

Android蓝牙连接ODB2设备抛出read failed错误排查

错误信息

java.io.IOException: read failed, socket might closed or timeout, read ret: -1
    at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:816)
    at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:830)
    at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:442)

连接代码(基于官方示例)

class ConnectThread(private val device: BluetoothDevice,private val  bluetoothAdapter: BluetoothAdapter?) : Thread() {
    private val uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
    private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
        device.createRfcommSocketToServiceRecord(uuid)
    }

    override fun run() {
        bluetoothAdapter?.cancelDiscovery()

        mmSocket?.use { socket ->
            socket.connect()
        }
    }

    fun cancel() {
        try {
            mmSocket?.close()
        } catch (e: IOException) {
            Log.e("TAG", "Could not close the client socket", e)
        }
    }
}

AndroidManifest权限配置

<!--BLUETOOTH PERMISSION-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>

<!--LOCATION PERMISSION-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

已尝试但无效的方案

  • 测试多个静态UUID(fa87c0d0-afac-11de-8a39-0800200c9a66、00001101-0000-1000-8000-00805F9B34FB等)
  • 每次连接生成新UUID
  • 针对不同设备类型使用对应UUID
  • 更换多种蓝牙设备(电视、PC、音响等)测试
  • 在Android API 29-34版本的设备上验证
  • 切换使用createRfcommSocketToServiceRecord和createInsecureRfcommSocketToServiceRecord

每次连接均会触发错误,设备显示连接几秒后断开。


可行的排查/解决方向

1. 强制指定RFCOMM通道号

多数ODB2设备使用固定的RFCOMM通道(常见为通道1),绕过UUID匹配逻辑,直接通过反射创建指定通道的Socket:

private fun createRfcommSocket(device: BluetoothDevice, channel: Int): BluetoothSocket? {
    return try {
        val method = device.javaClass.getMethod("createRfcommSocket", Int::class.java)
        method.invoke(device, channel) as BluetoothSocket
    } catch (e: Exception) {
        Log.e("TAG", "Failed to create RFCOMM socket", e)
        null
    }
}

在ConnectThread中替换Socket初始化逻辑,依次尝试通道1、2、3等常见值。

2. 增加连接超时控制

为Socket设置超时时间,避免无限阻塞,同时捕获超时异常做处理:

override fun run() {
    bluetoothAdapter?.cancelDiscovery()
    mmSocket?.let { socket ->
        try {
            socket.soTimeout = 10000 // 设置10秒超时
            socket.connect()
            // 连接成功后的业务逻辑
        } catch (e: java.net.SocketTimeoutException) {
            Log.e("TAG", "Connection timed out", e)
            socket.close()
        } catch (e: IOException) {
            Log.e("TAG", "Connection failed", e)
            socket.close()
        }
    }
}

3. 确认设备配对状态

确保ODB2设备已完成系统级配对,且配对时正确输入PIN码(ODB2设备常用PIN:0000或1234)。未正确配对的设备会出现连接后秒断的情况。

4. 修正权限适配逻辑

  • Android 12+(API 31+)需动态申请BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限,仅在Manifest声明无效。
  • 经典蓝牙(RFCOMM)连接无需定位权限,可移除不必要的定位权限声明,避免权限冲突干扰连接流程。

5. 避免复用旧Socket实例

原代码中Lazy初始化的Socket会在连接失败后复用旧实例,导致后续连接失败。需每次连接都创建新的Socket:

class ConnectThread(private val device: BluetoothDevice,private val  bluetoothAdapter: BluetoothAdapter?) : Thread() {
    private val uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
    private var mmSocket: BluetoothSocket? = null

    override fun run() {
        bluetoothAdapter?.cancelDiscovery()
        // 每次连接创建新Socket
        mmSocket = device.createInsecureRfcommSocketToServiceRecord(uuid)
        mmSocket?.use { socket ->
            try {
                socket.connect()
                // 连接成功逻辑
            } catch (e: IOException) {
                Log.e("TAG", "Connection failed", e)
            }
        }
    }

    fun cancel() {
        try {
            mmSocket?.close()
        } catch (e: IOException) {
            Log.e("TAG", "Could not close the client socket", e)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 16:33:20