无法通过UUID找到BLE服务(代码中的UUID是正确的)
我最初用Python做这个BLE项目,但在Android权限方面遇到了问题,于是尝试用原生Kotlin编写一个Android应用(说实话……这种感觉)。它的核心是运行一个线程,重复按ID轮询某个特定的特征,并通过UDP发送数据。
到目前为止,它是在查找并连接设备:
val device = bluetoothAdapter.getRemoteDevice(targetDeviceAddress)
bluetoothGatt = device.connectGatt(context, false, gattCallback)
这触发了 onConnectionStateChange()。我知道这是因为蓝牙设备在此时有响应。
这会调用 gatt.discoverServices(),进而触发 onServicesDiscovered():
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
val service = gatt.getService(UUID.fromString(targetServiceUuid))
if (service != null) {
targetCharacteristic = service.getCharacteristic(UUID.fromString(targetCharacteristicUuid))
_status.value = BleStatus.Connected
} else {
_status.value = BleStatus.Error("Service not found")
}
} else {
_status.value = BleStatus.Error("Service discovery failed")
}
}
我之所以知道进入这个函数,是因为应用的状态框里会闪现“Service not found”。这是此字符串唯一出现的地方——所以它肯定是在尝试获取该服务(基于 targetServiceUuid,我已经通过列出设备的服务来验证),但没有找到。
也就是说——据我所知,我请求的是正确的服务UUID,但没有任何返回,我已经想不出办法。
在此之前,应用还请求Manifest.permission.BLUETOOTH_SCAN、Manifest.permission.BLUETOOTH_CONNECT和 Manifest.permission.ACCESS_FINE_LOCATION权限(我也在设置里检查了应用权限——它确实拥有“位置”和“附近设备”权限,因此我相信失败并非由于权限不足)。
这是OnePlus(Oppo)手机,Android 14。设备是BBC Micro:bit。
我到底还缺少什么?谢谢。
FURTHER INFORMATION:
补充信息:
经过进一步日志记录,我发现micro:bit的服务在电脑端的报告与手机端不同。
去掉无关结果,电脑端运行的python+bleak脚本报告说 e95d0753-251d-470a-a062-fa1922dfa9a8 (Handle: 40): MicroBit Accelerometer Service 存在。
但这个UUID在 Android环境中缺失。
Kotlin日志代码看起来是这样的:
val uuid = UUID.fromString(targetServiceUuid)
val lsb = uuid.getLeastSignificantBits()
val msb = uuid.getMostSignificantBits()
Log.i("mb2o", "targetServiceUuid string = %s".format(targetServiceUuid))
Log.i("mb2o", "lsb hex = %s".format(lsb.toHexString()))
Log.i("mb2o", "msb hex = %s".format(msb.toHexString()))
// this is poorly factored but will delete later
val srvIter = gatt.getServices().iterator()
while (srvIter.hasNext()) {
var srvc = srvIter.next()
Log.i("mb2o", "service = %s".format(srvc.uuid))
}
并输出
targetServiceUuid string = e95d0753-251d-470a-a062-fa1922dfa9a8
lsb hex = a062fa1922dfa9a8
msb hex = e95d0753251d470a
service = 00001800-0000-1000-8000-00805f9b34fb
service = 00001801-0000-1000-8000-00805f9b34fb
service = 0000fe59-0000-1000-8000-00805f9b34fb
service = e97dd91d-251d-470a-a062-fa1922dfa9a8
service = 0000180a-0000-1000-8000-00805f9b34fb
service = e95d93af-251d-470a-a062-fa1922dfa9a8
e95d93af-251d-470a-a062-fa1922dfa9a8 与之非常接近,但它对应的是micro:bit的事件服务,而不是加速度计。
这是一个令人困惑的结果。也许事件服务在这里会起作用。
解决方案
我对在onServicesDiscovered中查找特征时遇到的困难记得很模糊,曾经因为某些我记不清的原因需要把hibits和 lobits分别测试。不过这是我的代码:
public void onServicesDiscovered(BluetoothGatt gatt, int status)
{
int n, k;
long lobits, hibits;
List<BluetoothGattService> servicelist;
List<BluetoothGattCharacteristic> clist;
BluetoothGattCharacteristic bchar;
if (status == BluetoothGatt.GATT_SUCCESS)
{
servicelist = gatt.getServices();
for (n = 0; n < servicelist.size(); ++n)
{
lobits = servicelist.get(n).getUuid().getLeastSignificantBits();
hibits = servicelist.get(n).getUuid().getMostSignificantBits();
if (hibits == 0x1122334455667788L && lobits == 0x99aabbccddeeffffL)
{ // FOUND service 112233445566778899aabbccddeeffff
clist = servicelist.get(n).getCharacteristics();
for (k = 0; k < clist.size(); ++k)
{
bchar = clist.get(k);
hibits = bchar.getUuid().getMostSignificantBits();
if (hibits == 0x1122334455667788L)
{
lobits = bchar.getUuid().getLeastSignificantBits();
if (lobits == 0x99aabbccddeeff00L)
{
// FOUND characteristic bchar 112233445566778899aannccddeeff00
}
}
}
}
}
}
}