Android(Kotlin)通过UUID连接蓝牙设备报错的解决咨询
解决Android Kotlin蓝牙连接报错
read failed, socket might closed or timeout, read ret: -1的方案 核对UUID准确性
这个错误最常见的原因是UUID不匹配。不要默认使用通用SPP UUID(00001101-0000-1000-8000-00805F9B34FB),必须和蓝牙设备端暴露的服务UUID完全一致。可以通过以下方式获取正确UUID:- 调用
BluetoothDevice.getUuids()遍历已配对设备的支持UUID; - 用蓝牙调试工具(如nRF Connect)扫描设备服务,查看目标服务的UUID。
- 调用
配置并申请正确的蓝牙权限
不同Android版本的蓝牙权限要求差异很大,务必配置齐全:- Android 12+:Manifest中添加
BLUETOOTH_CONNECT、BLUETOOTH_SCAN权限,且在运行时动态申请; - Android 11及以下:Manifest中添加
BLUETOOTH、BLUETOOTH_ADMIN、ACCESS_FINE_LOCATION权限,同样需要动态申请位置权限(蓝牙扫描依赖位置服务)。
示例Manifest权限配置:
<!-- Android 12+ 权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- 旧版本兼容权限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-feature android:name="android.hardware.bluetooth" android:required="true" />- Android 12+:Manifest中添加
在独立线程中执行连接操作
蓝牙连接属于耗时IO操作,绝对不能在主线程执行,否则会触发ANR或超时错误。推荐用协程在IO调度器中处理:CoroutineScope(Dispatchers.IO).launch { try { val socket = device.createRfcommSocketToServiceRecord(targetUuid) socket.connect() // 连接成功后的读写逻辑 } catch (e: IOException) { // 错误处理:关闭socket、重试等 e.printStackTrace() socket?.close() } }注意:连接失败后必须关闭当前socket,再尝试重新连接,避免资源泄漏。
确认设备配对与连接状态
- 确保目标设备已完成配对:未配对设备需先调用
device.createBond()触发配对流程(需用户确认弹窗),配对完成后再尝试连接; - 检查设备是否处于可连接模式:部分蓝牙设备(如打印机、手环)需要手动进入配对/连接状态才能被外部设备连接。
- 确保目标设备已完成配对:未配对设备需先调用
适配特殊设备的反射连接方案
部分设备不支持标准的createRfcommSocketToServiceRecord()方法,可尝试通过反射获取RFCOMM通道连接:private fun createRfcommSocketViaReflection(device: BluetoothDevice): BluetoothSocket? { return try { val method = device.javaClass.getMethod("createRfcommSocket", Int::class.java) method.invoke(device, 1) as BluetoothSocket } catch (e: Exception) { e.printStackTrace() null } }使用该方法创建socket后再调用
connect()尝试连接。手动控制连接超时
Android原生connect()方法没有超时参数,可通过协程的withTimeoutOrNull手动控制超时时间,避免无限等待:CoroutineScope(Dispatchers.IO).launch { val socket = device.createRfcommSocketToServiceRecord(targetUuid) val isConnected = withTimeoutOrNull(10000) { // 10秒超时 socket.connect() true } if (isConnected == null) { socket.close() // 处理超时逻辑 } else { // 连接成功 } }
内容的提问来源于stack exchange,提问作者Christian Fiorenzo
相关产品推荐
相关产品推荐

