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

如何通过UUID实现与简易BLE蓝牙按钮的成功通信

BLE自拍按钮与APP通信问题:通知无法激活
  • 设备可正常配对连接,但代码实现通信时通知设置始终失效
  • 已完成设备发现与MAC地址连接,通过第三方BLE应用获取了疑似UUID,但遍历所有UUID均无法激活按钮按压通知
  • 使用RxAndroidBle3库开发,尝试通过写入人机接口特征的CCCD来开启通知,无效果

现有实现代码

package com.example.androidcounterapp

import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothGattDescriptor
import android.content.ContentValues.TAG
import android.content.Context
import android.util.Log
import com.polidea.rxandroidble3.RxBleClient
import com.polidea.rxandroidble3.RxBleDevice
import io.reactivex.rxjava3.disposables.Disposable
import java.util.UUID

class BluetoothConnection {

    val serviceUuidUUID = UUID.fromString("00001812-0000-1000-8000-00805f9b34fb")
    val characteristicUUID = UUID.fromString("00002a4d-0000-1000-8000-00805f9b34fb")
    val cccdUUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")

    inner class ConnectThread(
        private val context: Context,
        private val macAddress: String,
        private val bluetoothAdapter: BluetoothAdapter
    ) : Thread() {

        private val rxBleClient: RxBleClient by lazy(LazyThreadSafetyMode.NONE) {
            RxBleClient.create(context)
        }

        private var connectionDisposable: Disposable? = null

        @SuppressLint("MissingPermission")
        private fun connectAndSetupNotification(
            device: RxBleDevice,
            characteristicUUID: UUID,
            cccdUUID: UUID,
        ) {

            Log.i(TAG, "Entered connectAndSetupNotification")

            connectionDisposable = device.establishConnection(false)
                .flatMap { rxBleConnection ->

                    Log.i(TAG, "GATT connection established")


                    rxBleConnection.setupNotification(characteristicUUID)
                        .flatMap { notificationObservable ->
                            val enableNotificationValue = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
                            val descriptor = BluetoothGattDescriptor(
                                cccdUUID,
                                BluetoothGattDescriptor.PERMISSION_WRITE
                            ).apply {
                                value = enableNotificationValue
                            }

                            rxBleConnection.writeDescriptor(descriptor, enableNotificationValue)
                                .andThen(notificationObservable)
                        }
                }
                .subscribe(
                    { notificationData ->
                        Log.i(TAG, "Notification data: ${notificationData.joinToString(", ")}")
                        val readableValue = CharacteristicConverter.convert(notificationData)
                        Log.i(TAG, "Readable value: $readableValue")
                    },
                    { throwable ->
                        Log.e(TAG, "Error occurred while setting up notification", throwable)
                    }
                )
        }

        @SuppressLint("MissingPermission")
        override fun run() {

            bluetoothAdapter.cancelDiscovery()
            Log.i(TAG, "Trying to connect")
            val device = rxBleClient.getBleDevice(macAddress)
            connectAndSetupNotification(device, characteristicUUID, cccdUUID)
        }

        fun cancel() {
            connectionDisposable?.dispose()
        }
    }
}

排查与修复建议

1. 修正RxAndroidBle通知设置逻辑

RxAndroidBle的setupNotification()方法已经内置了CCCD写入逻辑,无需手动创建Descriptor并写入,重复操作可能导致冲突。简化后的代码:

@SuppressLint("MissingPermission")
private fun connectAndSetupNotification(
    device: RxBleDevice,
    characteristicUUID: UUID,
) {
    Log.i(TAG, "Entered connectAndSetupNotification")
    connectionDisposable = device.establishConnection(false)
        .flatMap { rxBleConnection ->
            Log.i(TAG, "GATT connection established")
            // 直接调用setupNotification,内部自动处理CCCD写入
            rxBleConnection.setupNotification(characteristicUUID)
                .flatMap { it }
        }
        .subscribe(
            { notificationData ->
                Log.i(TAG, "Notification data: ${notificationData.joinToString(", ")}")
                val readableValue = CharacteristicConverter.convert(notificationData)
                Log.i(TAG, "Readable value: $readableValue")
            },
            { throwable ->
                Log.e(TAG, "Error occurred while setting up notification", throwable)
            }
        )
}

2. 确认目标特征的属性

用BLE调试工具(如nRF Connect)查看设备的特征属性:

  • 确认目标特征支持Notify或Indicate属性
  • 定位按钮按压事件对应的特征(通常是按钮按下时主动发送数据的可通知特征)

3. 遍历所有服务与特征排查

由于设备无文档,连接成功后遍历所有服务和特征,打印UUID并逐个测试通知:

@SuppressLint("MissingPermission")
private fun discoverAllServicesAndCharacteristics(device: RxBleDevice) {
    device.establishConnection(false)
        .flatMapSingle { it.discoverServices() }
        .subscribe(
            { services ->
                services.forEach { service ->
                    Log.i(TAG, "Service UUID: ${service.uuid}")
                    service.characteristics.forEach { characteristic ->
                        val hasNotify = (characteristic.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0
                        Log.i(TAG, "Characteristic UUID: ${characteristic.uuid}, Support Notify: $hasNotify")
                        // 对支持Notify的特征逐个测试
                        if (hasNotify) {
                            connectAndSetupNotification(device, characteristic.uuid)
                        }
                    }
                }
            },
            { throwable -> Log.e(TAG, "Discover services error", throwable) }
        )
}

4. 检查权限与连接参数

  • Android 12+需确保已申请BLUETOOTH_CONNECT、BLUETOOTH_SCAN权限
  • 连接时可尝试设置autoConnect = true,提升连接稳定性:device.establishConnection(true)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 18:05:14