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

Android通过服务UUID连接BLE设备遇IO错误,求解决方案

问题分析与解决方案

错误原因

你使用的createRfcommSocketToServiceRecord()是**经典蓝牙(BR/EDR)**的API,用于连接支持RFCOMM串口服务的设备,但BLE设备基于GATT协议工作,两类协议栈不兼容,因此必然抛出连接超时/失败的异常。

正确的BLE设备连接(通过服务UUID)

要通过服务UUID连接BLE设备,必须使用Android官方提供的BLE GATT API,完整流程如下:

1. 配置权限

在AndroidManifest.xml中添加蓝牙相关权限:

<!-- 低版本蓝牙权限(Android 11及以下) -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- Android 12+ 蓝牙扫描/连接权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 声明设备支持BLE -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

2. 初始化BLE适配器

获取蓝牙适配器并确保蓝牙已开启:

val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter

// 检查蓝牙状态,未开启则请求用户授权开启
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) {
    val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT) // REQUEST_ENABLE_BT为自定义请求码,如1
}

3. 扫描含目标服务UUID的BLE设备

启动扫描时指定服务UUID过滤,只获取包含目标服务的设备:

val targetServiceUuid = DeviceProfile.UUID_SERVICE // 你的目标服务UUID
val scanFilter = ScanFilter.Builder()
    .setServiceUuid(ParcelUuid(targetServiceUuid))
    .build()

val scanSettings = ScanSettings.Builder()
    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // 根据场景选择扫描模式
    .build()

// 启动扫描
bluetoothAdapter.bluetoothLeScanner.startScan(
    listOf(scanFilter),
    scanSettings,
    scanCallback
)

4. 处理扫描结果并发起GATT连接

实现ScanCallback捕获扫描到的设备,停止扫描并发起连接:

private val scanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult) {
        super.onScanResult(callbackType, result)
        // 找到目标设备,立即停止扫描
        bluetoothAdapter.bluetoothLeScanner.stopScan(this)
        // 发起GATT连接,第三个参数为连接回调
        result.device.connectGatt(this@YourActivity, false, gattCallback)
    }
}

5. 处理GATT连接与服务发现

实现BluetoothGattCallback处理连接状态、服务发现等关键事件:

private val gattCallback = object : BluetoothGattCallback() {
    override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
        super.onConnectionStateChange(gatt, status, newState)
        when (newState) {
            BluetoothProfile.STATE_CONNECTED -> {
                // 连接成功,触发服务发现
                gatt.discoverServices()
            }
            BluetoothProfile.STATE_DISCONNECTED -> {
                // 连接断开,可处理重连逻辑或资源清理
                gatt.close()
            }
        }
    }

    override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
        super.onServicesDiscovered(gatt, status)
        if (status == BluetoothGatt.GATT_SUCCESS) {
            // 获取目标服务
            val targetService = gatt.getService(DeviceProfile.UUID_SERVICE)
            targetService?.let { service ->
                // 可在此操作服务下的特征值(读、写、设置通知等)
                val targetCharacteristic = service.getCharacteristic(UUID.fromString("你的特征值UUID"))
                // 示例:读取特征值
                gatt.readCharacteristic(targetCharacteristic)
            }
        }
    }
}

关键澄清

你提到的“在经典蓝牙之上的GATT连接”存在概念误解:

  • GATT(通用属性配置文件)是BLE专属协议,经典蓝牙(BR/EDR)不支持GATT,两者属于独立的蓝牙协议栈,无法混合使用。
  • 若你的设备同时支持经典蓝牙和BLE,需明确其提供的服务类型:BLE服务用GATT API连接,经典蓝牙RFCOMM服务才用createRfcommSocketToServiceRecord()。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:02:06