web-dev-qa-db-fra.com

Enregistrer le récepteur de diffusion de manière dynamique ne fonctionne pas - BluetoothDevice.ACTION_FOUND

L'utilisation de la classe Log pour suivre l'exécution montre que la méthode onReceive() ne s'appelle pas, pourquoi?

Enregistrer le récepteur de diffusion de manière dynamique

 private void discoverDevices () {
    Log.e("MOHAB","BEFORE ON RECEIVE");

     mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            Log.e("MOHAB","ON RECEIVE");
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // Add the name and address to an array adapter to show in a ListView
                Bluetooth b = new Bluetooth(device.getName(),device.getAddress());
                list.add(b);
            }
        }
    };
    Log.e("MOHAB","create intentFilter");
    // Register the BroadcastReceiver
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy

}
12
Error

Qu'est-ce que vous avez manqué, c'est que vous devez démarrer une récupération de périphérique

D'abord, procurez-vous l'adaptateur Bluetooth

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

Après cela, vous commencez la découverte en appelant

mBtAdapter.startDiscovery();

Vous devriez également lire les détails ici, par exemple: à propos de cancelDiscovery()http://developer.Android.com/reference/Android/bluetooth/BluetoothAdapter.html#startDiscovery%28%29

P.S. En outre, il est suggéré d'utiliser context.getSystemService(Context.BLUETOOTH_SERVICE) pour obtenir l'adaptateur Bluetooth sur l'API 18+, selon la documentation officielle.

Pour obtenir un BluetoothAdapter représentant l’adaptateur Bluetooth local, lors de l'exécution sur JELLY_BEAN_MR1 et inférieur, appelez le statique méthode getDefaultAdapter (); lors de l'exécution sur JELLY_BEAN_MR2 et supérieur, récupérez-le via getSystemService (Class) avec BLUETOOTH_SERVICE.

Edit: Rappelez-vous que vous devez disposer de BLUETOOTH_ADMIN permission pour _startDiscovery()

7
Derek Fung

Outre le fait que à partir d'Android 6.0, vous devez disposer de l'autorisation ACCESS_COARSE_LOCATION pour recevoir ACTION_FOUND (comme @siniux déjà mentionné), il existe un autre élément connexe:

ACCESS_COARSE_LOCATION fait partie des autorisations dangereuses que vous devez demander explicitement à l'utilisateur au moment de l'exécution (autre amélioration de la sécurité fournie avec la version 6.0).

Pour diagnostiquer, vous pouvez exécuter adb logcat | grep BroadcastQueue et voir quelque chose comme ceci:

W/BroadcastQueue: Permission Denial: receiving Intent { 
    act=Android.bluetooth.device.action.FOUND flg=0x10 (has extras) } 
    to ProcessRecord{9007:com.examplepackage} (pid=9007, uid=10492) 
    requires Android.permission.ACCESS_COARSE_LOCATION due to sender
    com.Android.bluetooth (uid 1002)

Ainsi, la procédure correcte pour la découverte de périphérique BT sur Marshmallow est la suivante:

  1. Avoir l'autorisation ACCESS_COARSE_LOCATION dans le manifeste avec les autorisations Bluetooth habituelles:

    <uses-permission Android:name="Android.permission.BLUETOOTH" />
    <uses-permission Android:name="Android.permission.BLUETOOTH_ADMIN" />
    <uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
    
  2. Assurez-vous de disposer de l'autorisation d'exécution pour ACCESS_COARSE_LOCATION

    protected void checkLocationPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
    
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_COARSE_LOCATION);
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
        switch (requestCode) {
        case REQUEST_COARSE_LOCATION: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                proceedDiscovery(); // --->
            } else {
                //TODO re-request
            }
            break;
        }
    }
    

    }

  3. Enregistrez un récepteur de diffusion pour ACTION_FOUND et appelez BluetoothAdapter.startDiscovery()

    protected void proceedDiscovery() {
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
        registerReceiver(mReceiver, filter);
    
        mBluetoothAdapter.startDiscovery();
    }
    

_ {Ce qui est drôle avec ACTION_NAME_CHANGED. Bien que la version 6.0 ne vous fournisse pas ACTION_FOUND sans l’autorisation pour un emplacement approximatif, vous obtiendrez quand même des événements ACTION_NAME_CHANGED, qui sont généralement associés à ACTION_FOUND lors de la découverte des périphériques. C'est à dire. vous obtenez les deux événements, donc sans permission, vous pouvez toujours gérer ACTION_NAME_CHANGED pour à peu près le même comportement. (Gourous, corrigez-moi si je me trompe)

36
Ivan Bartsov

J'avais un problème similaire avec un récepteur de radiodiffusion . Puis j'ai trouvé ceci: https://developer.Android.com/about/versions/Marshmallow/Android-6.0-changes.html#behavior- identifiant du matériel

Fondamentalement, sur 6.0, vous devez utiliser l'autorisation d'emplacement pour rechercher des périphériques Bluetooth. 

13
siniux

je ne sais pas si votre code est correct pour obtenir un périphérique Bluetooth. Voici ce que je ressens à propos de votre code est. Intialiser et enregistrer BroadcastReceiver dans une fonction est une mauvaise idée. vous devriez le faire en dehors de la méthode onCreate() . voici ce que vous devez faire dans votre code

comme pour enregistrer Reciver qui doit être fait dans onCreate() comme ceci 

registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));

suivi d'initialisation ou de réception

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("MOHAB","ON RECEIVE");
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // Add the name and address to an array adapter to show in a ListView
                Bluetooth b = new Bluetooth(device.getName(),device.getAddress());
                list.add(b);
            }
        }
    };

annuler l'enregistrement dans onPause() ne pas oublier que

et dans votre discoverDevices(), renvoyez la list de périphériques ajoutés par reciver pour chaque appel de cette réaction;

4
Jolson Da Costa

Selon les réponses des experts, vous pouvez vérifier les points suivants pour que ACTION_FOUND fonctionne avec Android 6 et les versions ultérieures, 1. En plus de définir les autorisations de BLUETOOTH et BLUETOOTH_ADMIN, essayez 

<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />

Parfois, ces deux ne sont peut-être pas nécessaires, mais cela a fonctionné pour moi. Aussi, vous devez rechercher les autorisations des utilisateurs de manière dynamique en utilisant les codes

int MY_PERMISSIONS_REQUEST = 200;
int permissions=ContextCompat.checkSelfPermission (this,Manifest.permission.ACCESS_FINE_LOCATION);
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                MY_PERMISSIONS_REQUEST);

Maintenant, écrivez vos codes pour effectuer l'opération requise. J'ai ajouté une méthode startDiscovery () juste après ceci . Cela fonctionnera sûrement pour vous ... Bon codage ...

1
Jilson

J'ai constaté que le périphérique sur lequel je développais (Galaxy S4) devait être redémarré avant que les émissions ne continuent à être reçues. 

Cependant, dans mon cas, je les recevais sans problème jusqu'à ce qu'ils (de manière aléatoire?) Cessent d'être reçus et peu importe ce que j'ai fait (fermer l'application, réinstaller l'application), les émissions ne sont pas reçues.

0
TheIT

En publiant ceci comme réponse, je ne peux pas commenter avec mon niveau actuel de représentant.

Avez-vous la permission Bluetooth inclure dans votre AndroidManifest.xml?

<uses-permission Android:name="Android.permission.BLUETOOTH"/>
<uses-permission Android:name="Android.permission.BLUETOOTH_ADMIN"/>

Sinon, essayez (et recherchez) chacun séparément, car je ne me souviens pas de l'importance de chacun.

Si vous en avez, veuillez inclure plus de code afin qu’il soit possible de diagnostiquer votre problème.

0
lkjsdf23