Android蓝牙:获取已发现设备的UUID

Android蓝牙:获取已发现设备的UUID,android,bluetooth,Android,Bluetooth,由于我目前正在为Android开发一个小型蓝牙库,我正在尝试获取我在周围环境中发现的设备的所有服务UUID 当我的广播接收器获得Bluetooth设备。ACTION_FOUND意图时,我提取设备并调用: device.fetchUuidsWithSdp(); 这将导致BluetoothDevice.ACTION\u UUID针对找到的每个设备的意图,我使用相同的接收器处理它们: BluetoothDevice d = intent.getParcelableExtra(BluetoothDev

由于我目前正在为Android开发一个小型蓝牙库,我正在尝试获取我在周围环境中发现的设备的所有服务UUID

当我的广播接收器获得Bluetooth设备。ACTION_FOUND意图时,我提取设备并调用:

device.fetchUuidsWithSdp();
这将导致
BluetoothDevice.ACTION\u UUID
针对找到的每个设备的意图,我使用相同的接收器处理它们:

BluetoothDevice d = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Parcelable[] uuidExtra = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);

if(uuidExtra ==  null) {
    Log.e(TAG, "UUID = null");
}

if(d != null && uuidExtra != null)
    Log.d(TAG, d.getName() + ": " + uuidExtra.toString());
问题是,
uuidExtra
总是
null

如何获取周围设备的所有UUID

编辑:

我正在研究Nexus7。我尝试了在internet上找到的代码,这也给了我一个NullPointerException:

谢谢。

关于此项的

始终包含额外字段
BluetoothDevice.extra\u UUID

然而,就像你一样,我发现这不是真的

如果在设备发现仍在进行时调用
fetchUuidsWithSdp()
,则BluetoothDevice.EXTRA\u UUID可以为空


您应该等到收到
BluetoothAdapter.ACTION\u DISCOVERY\u FINISHED
后再调用
FetchUUIDSWithDP()

我想您需要与设备配对才能接收UUID。
至少,这就是我的遭遇。

下面的工作帮助我从远程设备获取记录

-0-
registerReceiver(..,
                new IntentFilter(BluetoothDevice.ACTION_UUID));
-一,- device.fetchUUIDSWITHDP()

-2-从broadcase接收器内部

   if (BluetoothDevice.ACTION_UUID.equals(action)) {
                        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                        Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
                        for (Parcelable ep : uuids) {
                            Utilities.print("UUID records : "+ ep.toString());
                        }
                    }
您还可以使用获取脱机缓存的UUID记录

 BluetoothDevice.getUuids();

下面是一个很好的示例,说明了如何从我为获取心率设备所做的服务中获取服务特征的UUID:

private class HeartRateBluetoothGattCallback extends BluetoothGattCallback {

    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {         
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            logMessage("CONNECTED TO " + gatt.getDevice().getName(), false, false);
            gatt.discoverServices();    
        } else if(newState == BluetoothProfile.STATE_DISCONNECTED) {
            logMessage("DISCONNECTED FROM " + gatt.getDevice().getName(), false, false);
            if(mIsTrackingHeartRate)
                handleHeartRateDeviceDisconnection(gatt);
        } 
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            logMessage("DISCOVERING SERVICES FOR " + gatt.getDevice().getName(), false, false);

            if(mDesiredHeartRateDevice != null && 
                    gatt.getDevice().getAddress().equals(mDesiredHeartRateDevice.getBLEDeviceAddress())) {

                if(subscribeToHeartRateGattServices(gatt)) {

                    mIsTrackingHeartRate = true;
                    setDeviceScanned(getDiscoveredBLEDevice(gatt.getDevice().getAddress()), DiscoveredBLEDevice.CONNECTED);
                    broadcastHeartRateDeviceConnected(gatt.getDevice());

                } else
                    broadcastHeartRateDeviceFailedConnection(gatt.getDevice());

            } else {
                parseGattServices(gatt);
                disconnectGatt(getDiscoveredBLEDevice(gatt.getDevice().getAddress()));
            }
        }   
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        if(characteristic.getUuid().equals(UUID.fromString(HEART_RATE_VALUE_CHAR_READ_ID))) {
            int flag = characteristic.getProperties();
            int format = -1;

            if ((flag & 0x01) != 0) 
                format = BluetoothGattCharacteristic.FORMAT_UINT16;
            else 
                format = BluetoothGattCharacteristic.FORMAT_UINT8;

            Integer heartRateValue = characteristic.getIntValue(format, 1);
            if(heartRateValue != null)
                broadcastHeartRateValue(heartRateValue);
            else
                Log.w(SERVICE_NAME, "UNABLE TO FORMAT HEART RATE DATA");
        }
    };

};

private void parseGattServices(BluetoothGatt gatt) {
    boolean isHeartRate = false;
    for(BluetoothGattService blueToothGattService : gatt.getServices()) {
        logMessage("GATT SERVICE: " + blueToothGattService.getUuid().toString(), false, false);
        if(blueToothGattService.getUuid().toString().contains(HEART_RATE_DEVICE_SERVICE_CHARACTERISTIC_PREFIX))
            isHeartRate = true;
    }   

    if(isHeartRate) {
        setDeviceScanned(getDiscoveredBLEDevice(gatt.getDevice().getAddress()), DiscoveredBLEDevice.IS_HEART_RATE);
        broadcastHeartRateDeviceFound(getDiscoveredBLEDevice(gatt.getDevice().getAddress()));
    } else 
        setDeviceScanned(getDiscoveredBLEDevice(gatt.getDevice().getAddress()), DiscoveredBLEDevice.NOT_HEART_RATE);
}

private void handleHeartRateDeviceDisconnection(BluetoothGatt gatt) {
    broadcastHeartRateDeviceDisconnected(gatt.getDevice());
    gatt.close();

    clearoutHeartRateData();
    scanForHeartRateDevices();
}

private void disconnectGatt(DiscoveredBLEDevice device) {
    logMessage("CLOSING GATT FOR " + device.getBLEDeviceName(), false, false);
    device.getBlueToothGatt().close();
    device.setBlueToothGatt(null);
    mInDiscoveryMode = false;
}

private boolean subscribeToHeartRateGattServices(BluetoothGatt gatt) {
    for(BluetoothGattService blueToothGattService : gatt.getServices()) {
        if(blueToothGattService.getUuid().toString().contains(HEART_RATE_DEVICE_SERVICE_CHARACTERISTIC_PREFIX)) {
            mHeartRateGattService = blueToothGattService;

            for(BluetoothGattCharacteristic characteristic : mHeartRateGattService.getCharacteristics()) {
                logMessage("CHARACTERISTIC UUID = " + characteristic.getUuid().toString(), false, false);

                for(BluetoothGattDescriptor descriptor :characteristic.getDescriptors()) {
                    logMessage("DESCRIPTOR UUID = " + descriptor.getUuid().toString(), false, false);
                }

                if(characteristic.getUuid().equals(UUID.fromString(HEART_RATE_VALUE_CHAR_READ_ID))) {
                    gatt.setCharacteristicNotification(characteristic, true);
                    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HEART_RATE_VALUE_CHAR_DESC_ID));
                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                    return gatt.writeDescriptor(descriptor);
                }
            }

            break; //break out of master for-loop
        }
    }

    return false;
}
注意:此解决方案适用于
CLASSIC
蓝牙,而不是
BLE
。对于
BLE
检查如何发送 外围侧广告客户中的制造商特定数据

获取UUID的问题是,您只有一个蓝牙适配器,并且我们不能有使用适配器的并行api调用

正如Eddie所指出的,等待
BluetoothAdapter.ACTION\u DISCOVERY\u完成
,然后调用
FetchUuidWithDP()

但这仍然不能保证为所有设备获取UUID。除此之外,用户还必须等待后续对
fetchUUIDSWithDP()
的每次调用完成,然后为另一个设备调用此方法

请参见下面的代码--

ArrayList mDeviceList=new ArrayList();
专用最终广播接收器mReceiver=新广播接收器(){
公共void onReceive(上下文、意图){
String action=intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(ACTION)){
BluetoothDevice设备=(BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_设备);
mDeviceList.add(设备);
}else if(BluetoothAdapter.ACTION\u DISCOVERY\u FINISHED.equals(ACTION)){
//发现已完成,请在列表中的第一个设备上调用FetchUUIDSWITHDP。
如果(!mDeviceList.isEmpty()){
BluetoothDevice=mDeviceList.remove(0);
布尔结果=device.fetchUUIDSWITHDP();
}
}else if(BluetoothDevice.ACTION_UUID.equals(ACTION)){
//这时我们可以确信fetchUuidsWithSdp已经完成。
//因此,获取UUID并在列表中的另一个设备上调用FetchUUIDSWithDP
BluetoothDeviceExtra=intent.getParcelableExtra(BluetoothDevice.EXTRA\u设备);
Parcelable[]uuidExtra=intent.getParcelableArrayExtra(蓝牙设备.EXTRA\UUID);
System.out.println(“DeviceExtra地址-”+DeviceExtra.getAddress());
如果(uuidExtra!=null){
用于(可包裹p:uuidExtra){
系统输出打印项次(“uuidExtra-”+p);
}
}否则{
System.out.println(“uuidExtra仍然为空”);
}
如果(!mDeviceList.isEmpty()){
BluetoothDevice=mDeviceList.remove(0);
布尔结果=device.fetchUUIDSWITHDP();
}
}
}
}
更新:最新的android版本(mm及以上)将触发与每个设备的配对过程

device.getUUID()使用此选项以parceluid的形式获取该配对设备的所有uuid;示例代码如下:-

private void get_uuid_from_paired_devices(){
        Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
        for (BluetoothDevice device: pairedDevices){

            for (ParcelUuid uuid: device.getUuids()){
                String uuid_string = uuid.toString();
                Log.d(TAG, "uuid : "+uuid_string);
            }
        }
    }
private void从配对设备()获取{
Set pairedDevices=bluetoothAdapter.getBondedDevices();
用于(蓝牙设备:pairedDevices){
for(parceluid-uuid:device.getUuids()){
字符串uuid_String=uuid.toString();
Log.d(标记“uuid:+uuid_字符串);
}
}
}

即使在调用
fetchUUIDSWITHDP()
之前等待设备发现完成,我也会遇到同样的问题。这在某些情况下对我有效。当从我的三星Galaxy Nexus 2发现设备时,我只能在我的HTC One(M7)上接收服务,而不能从我的MacBook Pro上接收服务(结果为空)。编辑:如果
fetchUUIDSWithDP()
工作与否,则似乎完全是随机的,无论我在过程中的哪个点调用它。这就像魅力一样。对于我们认为行为是随机的场景,请参见下面的答案。即使我添加了
filter.addAction(BluetoothAdapter.ACTION\u DISCOVERY\u FINISHED),也不会调用ACTION\u FINISHED我面临着确切的情况!你找到解决办法了吗?你能帮帮我吗?我相信这个问题是针对蓝牙经典,而不是蓝牙乐。。。就像你提到的“服务”、“特征”、“gatt”和心率设备一样。有趣的是,我仍然得到空值:(确保注册意图。哪个动作触发配对过程?fetchUuidWithDP()?
private void get_uuid_from_paired_devices(){
        Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
        for (BluetoothDevice device: pairedDevices){

            for (ParcelUuid uuid: device.getUuids()){
                String uuid_string = uuid.toString();
                Log.d(TAG, "uuid : "+uuid_string);
            }
        }
    }