web-dev-qa-db-fra.com

android BluetoothDevice.getName () return null

BluetoothDevice.getName () renvoie parfois null. Comment puis-je résoudre ce problème? RemoteDeviceName peut être nul dans le code suivant. Et j'ai besoin de distinguer mon appareil et les autres appareils par 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);
            });
13
maonanyue

Enfin, j'ai trouvé la solution:

1.Pour appareil connecté:

Lire le nom de périphérique à partir de la caractéristique gatt org.bluetooth.characteristic.gap.device_name of service org.bluetooth.service.generic_access .

2.Pour le périphérique non connecté:

    /**
     * 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;
        }
    }
13
maonanyue

BluetoothDevice.getName() peut retourner null si le nom n'a pas pu être déterminé. Cela pourrait être dû à un certain nombre de facteurs. Quoi qu'il en soit, le nom est friendly nom du périphérique et ne doit pas être utilisé pour le distinguer des autres périphériques. À la place, utilisez l'adresse matérielle via getAddress().

5
323go

Je sais que c'est vieux, mais cette réponse plus spécifique peut aider à répondre à certains cas.

En Bluetooth Low Energy, les données de publication et de réponse de numérisation ne sont nécessaires que pour avoir l'adresse Bluetooth. Les données de publication décrivent comment un point de terminaison BTLE client découvre un périphérique de service. Un client peut demander une réponse d'analyse et obtenir plus de données. Le nom de l'appareil est facultatif dans ces données. Cependant, la spécification BTLE requiert que tous les points d'extrémité Bluetooth Low Energy prennent en charge le service Generic Access qui est requis pour prendre en charge la caractéristique Nom du périphérique. Malheureusement, pour lire cette caractéristique, Android doit d’abord se connecter et faire une découverte de service. Si la réponse de publication/analyse ne fournit pas les informations, je ne crois pas qu'Android se connecte à l'appareil pour obtenir le nom. Au moins, je n'ai jamais vu d'indication de connexion sans que l'application demande spécifiquement une connexion. Ce n'est pas ce que vous voulez être obligé de faire si vous voulez prendre la décision de vous connecter.

Heureusement, la plupart des périphériques BTLE avec lesquels j'ai travaillé fournissent leur nom dans la réponse de publication ou d'analyse.

Une autre possibilité est que le périphérique place le nom dans la partie réponse de l'analyse de la publicité. Selon la manière dont on a configuré le scanner BTLE d'Android, on peut obtenir uniquement les données de publication et non la réponse de l'analyse. Dans ce cas, le nom ne sera pas trouvé si le périphérique le met dans la réponse d'analyse. Les paramètres de l'analyseur par défaut sont toutefois tels qu'une réponse d'analyse doit être reçue avant que les données d'analyse ne soient transmises à l'application.

1
Brian Reinhold

J'essayais d'afficher le nom de mon module Bluetooth RN4020 et je faisais face au même problème. Trouvé le problème dans le forum de Microchip:

Si vous avez activé service privé ou MLDP, le nombre maximal d'octets de nom de périphérique Est de 6 octets, en raison de la limitation de la charge utile de la publication de 31 octets.

J'avais défini le nom de l'appareil à 9 caractères. La définition du nom sur 4 octets a résolu le problème. 

Si vous reconnaissez les UUID de vos services personnalisés pour connaître votre appareil, vous pouvez également vous connecter à l'appareil et lire son nom (s'il est supérieur à 6 octets dans mon cas). Cela a également été suggéré dans le forum Microchips.

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

1
etrusks

Sur Marshmallow, utilisez ScanRecord.getDeviceName() pour récupérer le nom local incorporé dans l’analyse. 

BluetoothDevice.getName() n'est pas fiable si le nom local est inclus dans une réponse d'analyse plutôt que dans le paquet de publicité immédiate.

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

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

J'ai constaté que si vous interrogez le nom du périphérique immédiatement après son enregistrement lors de l'analyse, il risque de renvoyer null. Pour contourner ce problème, j'interroge un exécutable toutes les secondes environ sur le thread d'interface utilisateur au maximum 3 fois (donc 3 secondes), et le nom est généralement résolu à ce moment-là.

Remarque: dans l'extrait de code fourni, la classe englobante implémente Runnable, d'où la raison pour laquelle je peux passer this dans 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);
        }
    }
0
Tunji_D