Android BluetoothDevice.getName() return null

В какой-то момент BluetoothDevice.getName() возвращает null. Как я могу это исправить? remoteDeviceName может быть пустым в следующем коде. И мне нужно отличить мое устройство и другие устройства с помощью remoteDeviceName.

BluetoothAdapter.getDefaultAdapter().startLeScan(new LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, final int rssi,
                    byte[] scanRecord) {
                    String remoteDeviceName = device.getName();
                  Log.d("Scanning", "scan device " + remoteDeviceName);
            });

Ответ 1

Наконец, я нашел решение:

1. Для подключенного устройства:

Прочитать имя устройства из характеристики gatt org.bluetooth.characteristic.gap.device_name службы org.bluetooth.service.generic_access.

2. Для устройства не подключено:

    /**
     * Get device name from ble advertised data
     */
    private LeScanCallback mScanCb = new LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi,
            byte[] scanRecord) {
            final BleAdvertisedData badata = BleUtil.parseAdertisedData(scanRecord);
            String deviceName = device.getName();
            if( deviceName == null ){
                deviceName = badata.getName();
            }
    }


////////////////////// Helper Classes: BleUtil and BleAdvertisedData ///////////////
    final public class BleUtil {        
        private final static String TAG=BleUtil.class.getSimpleName();
        public static BleAdvertisedData parseAdertisedData(byte[] advertisedData) {      
            List<UUID> uuids = new ArrayList<UUID>();
            String name = null;
            if( advertisedData == null ){
                return new BleAdvertisedData(uuids, name);
            }

            ByteBuffer buffer = ByteBuffer.wrap(advertisedData).order(ByteOrder.LITTLE_ENDIAN);
            while (buffer.remaining() > 2) {
                byte length = buffer.get();
                if (length == 0) break;

                byte type = buffer.get();
                switch (type) {
                    case 0x02: // Partial list of 16-bit UUIDs
                    case 0x03: // Complete list of 16-bit UUIDs
                        while (length >= 2) {
                            uuids.add(UUID.fromString(String.format(
                                    "%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
                            length -= 2;
                        }
                        break;
                    case 0x06: // Partial list of 128-bit UUIDs
                    case 0x07: // Complete list of 128-bit UUIDs
                        while (length >= 16) {
                            long lsb = buffer.getLong();
                            long msb = buffer.getLong();
                            uuids.add(new UUID(msb, lsb));
                            length -= 16;
                         }
                        break;
                    case 0x09:
                        byte[] nameBytes = new byte[length-1];
                        buffer.get(nameBytes);
                        try {
                            name = new String(nameBytes, "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        buffer.position(buffer.position() + length - 1);
                        break;
                    }
                }
            return new BleAdvertisedData(uuids, name);
        }
    }


    public class BleAdvertisedData {
        private List<UUID> mUuids;
        private String mName;
        public BleAdvertisedData(List<UUID> uuids, String name){
            mUuids = uuids;
            mName = name;
        }

        public List<UUID> getUuids(){
            return mUuids;
        }

        public String getName(){
            return mName;
        }
    }

Ответ 2

BluetoothDevice.getName() может возвращать null, если имя не может быть определено. Это может быть связано с любым количеством факторов. Несмотря на это, имя является дружественным именем устройства и не должно использоваться для его отличия от других устройств. Вместо этого используйте аппаратный адрес через getAddress().

Ответ 3

В Marshmallow используйте ScanRecord.getDeviceName() для получения локального имени, встроенного в запись сканирования.

BluetoothDevice.getName() является ненадежным, если локальное имя включено в ответ сканирования, а не в ближайший рекламный пакет.

    @Override
    public void onScanResult(int callbackType, ScanResult scanResult) {
        super.onScanResult(callbackType, scanResult);

        // Retrieve device name via ScanRecord.
        String deviceName = scanResult.getScanRecord().getDeviceName();
    }

Ответ 4

Я обнаружил, что если вы запрашиваете имя устройства сразу после его получения при сканировании, он может вернуть значение null. Чтобы обойти это, я проверяю каждую секунду или около того на поток пользовательского интерфейса максимум 3 раза (так 3 секунды), и имя обычно разрешается к тому времени.

Обратите внимание, что в предоставленном фрагменте охватывающий класс реализует Runnable, поэтому я могу передать this в View.postDelayed(Runnable action, long delayMillis)

    private static final int MAX_NAME_CHECKS = 3;
    private static final int NAME_CHECK_PERIOD = 1000;

    int nameChecks;

    @Override
    public void run() {
        resolveName();
    }

    /**
     * Checks for the device name, for a maximum of {@link ViewHolder#MAX_NAME_CHECKS}
     * as the name may not have been resolved at binding.
     */
    private void resolveName() {
        if (device != null) {
            String name = device.getName();
            boolean isEmptyName = TextUtils.isEmpty(name);

            if (isEmptyName) deviceName.setText(R.string.unknown_device);
            else deviceName.setText(name);

            // Check later if device name is resolved
            if (nameChecks++ < MAX_NAME_CHECKS && isEmptyName)
                itemView.postDelayed(this, NAME_CHECK_PERIOD);
        }
    }

Ответ 5

Я пытался отобразить имя моего модуля Bluetooth RN4020 и столкнулся с той же проблемой. Нашел проблему в форуме Microchip:

Если вы включили личную службу или MLDP, максимальные байты устройства имя составляет 6 байтов из-за ограничения на полезную нагрузку рекламы в 31 байт.

Я установил имя устройства в 9 символов. Исправлена ​​проблема с установкой имени в 4 байта.

Если вы узнаете UUID своих пользовательских сервисов, чтобы узнать свое устройство, вы также можете подключиться к устройству и прочитать его имя (если в моем случае оно больше 6 байтов). Это также было предложено на форуме Microchips.

http://www.microchip.com/forums/m846328.aspx