Rechercher des appareils Bluetooth

À l'aide de BluetoothAdapter, vous pouvez rechercher des appareils Bluetooth distants via la détection d'appareils ou en interrogeant la liste des appareils associés.

Assurez-vous de disposer des autorisations Bluetooth appropriées et de configurer votre application pour le Bluetooth avant de tenter de trouver des appareils Bluetooth.

La découverte d'appareils est une procédure de numérisation qui recherche dans la zone locale des appareils compatibles avec le Bluetooth et demande des informations sur chacun d'eux. Ce processus est parfois appelé "découverte", "interrogation" ou "analyse". Un appareil Bluetooth à proximité ne répond à une requête de découverte que s'il accepte actuellement les requêtes d'informations en étant détectable. Si un appareil est détectable, il répond à la requête de découverte en partageant certaines informations, telles que son nom, sa classe et son adresse MAC unique. À l'aide de ces informations, l'appareil qui effectue le processus de découverte peut ensuite choisir d'établir une connexion avec l'appareil détecté.

Étant donné que les appareils détectables peuvent révéler des informations sur la position de l'utilisateur, le processus de détection des appareils nécessite l'accès à la position. Si votre application est utilisée sur un appareil équipé d'Android 8.0 (niveau d'API 26) ou version ultérieure, envisagez d'utiliser plutôt l'API Companion Device Manager. Cette API effectue la découverte d'appareils pour le compte de votre application. Votre application n'a donc pas besoin de demander des autorisations d'accéder à la position.

Une fois qu'une connexion est établie avec un appareil distant pour la première fois, une demande d'association est automatiquement présentée à l'utilisateur. Lorsqu'un appareil est associé, les informations de base le concernant (comme son nom, sa classe et son adresse MAC) sont enregistrées et peuvent être lues à l'aide des API Bluetooth. À l'aide de l'adresse MAC connue d'un appareil distant, une connexion peut être établie avec lui à tout moment sans effectuer de découverte, à condition que l'appareil soit toujours à portée.

Notez qu'il existe une différence entre l'association et la connexion:

  • Associer deux appareils signifie qu'ils sont conscients de l'existence de l'autre, qu'ils disposent d'une clé d'association partagée pouvant être utilisée pour l'authentification et qu'ils peuvent établir une connexion chiffrée l'un avec l'autre.
  • Connecté signifie que les appareils partagent actuellement un canal RFCOMM et peuvent se transmettre des données. Les API Bluetooth actuelles exigent que les appareils soient associés avant qu'une connexion RFCOMM puisse être établie. L'association est effectuée automatiquement lorsque vous établissez une connexion chiffrée avec les API Bluetooth.

Les sections suivantes expliquent comment rechercher des appareils associés et comment en découvrir de nouveaux à l'aide de la découverte d'appareils.

Interroger les appareils associés

Avant d'effectuer la découverte d'appareils, il est utile d'interroger l'ensemble des appareils associés pour voir si l'appareil souhaité est déjà connu. Pour ce faire, appelez getBondedDevices(). Cela renvoie un ensemble d'objets BluetoothDevice représentant les appareils associés. Par exemple, vous pouvez interroger tous les appareils associés et obtenir le nom et l'adresse MAC de chacun d'eux, comme illustré dans l'extrait de code suivant:

Kotlin

val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
   val deviceName = device.name
   val deviceHardwareAddress = device.address // MAC address
}

Java

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) {
   // There are paired devices. Get the name and address of each paired device.
   for (BluetoothDevice device : pairedDevices) {
       String deviceName = device.getName();
       String deviceHardwareAddress = device.getAddress(); // MAC address
   }
}

Pour établir une connexion avec un appareil Bluetooth, l'objet BluetoothDevice associé ne nécessite que l'adresse MAC, que vous récupérez en appelant getAddress(). Pour en savoir plus sur la création d'une connexion, consultez Connecter des appareils Bluetooth.

Découvrir les appareils

Pour commencer à découvrir des appareils, appelez startDiscovery(). Le processus est asynchrone et renvoie une valeur booléenne indiquant si la découverte a bien commencé. Le processus de découverte implique généralement une analyse d'interrogation d'environ 12 secondes, suivie d'une analyse de page de chaque appareil détecté pour récupérer son nom Bluetooth.

Pour recevoir des informations sur chaque appareil détecté, votre application doit enregistrer un BroadcastReceiver pour l'intent ACTION_FOUND. Le système diffuse cet intent pour chaque appareil. L'intent contient les champs supplémentaires EXTRA_DEVICE et EXTRA_CLASS, qui contiennent à leur tour un BluetoothDevice et un BluetoothClass, respectivement. L'extrait de code suivant montre comment vous pouvez vous enregistrer pour gérer la diffusion lorsque des appareils sont détectés:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
   ...

   // Register for broadcasts when a device is discovered.
   val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
   registerReceiver(receiver, filter)
}

// Create a BroadcastReceiver for ACTION_FOUND.
private val receiver = object : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       val action: String = intent.action
       when(action) {
           BluetoothDevice.ACTION_FOUND -> {
               // Discovery has found a device. Get the BluetoothDevice
               // object and its info from the Intent.
               val device: BluetoothDevice =
                       intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
               val deviceName = device.name
               val deviceHardwareAddress = device.address // MAC address
           }
       }
   }
}

override fun onDestroy() {
   super.onDestroy()
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...

   // Register for broadcasts when a device is discovered.
   IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
   registerReceiver(receiver, filter);
}

// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
   public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();
       if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           // Discovery has found a device. Get the BluetoothDevice
           // object and its info from the Intent.
           BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
           String deviceName = device.getName();
           String deviceHardwareAddress = device.getAddress(); // MAC address
       }
   }
};

@Override
protected void onDestroy() {
   super.onDestroy();
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver);
}

Pour établir une connexion avec un appareil Bluetooth, vous appelez getAddress() sur BluetoothDevice pour récupérer l'adresse MAC associée.

Améliorer la visibilité

Pour rendre l'appareil local visible par d'autres appareils, appelez startActivityForResult(Intent, int) avec l'intent ACTION_REQUEST_DISCOVERABLE. Cette requête permet d'activer le mode visible du système sans avoir à accéder à l'application Paramètres, ce qui arrêterait votre propre application. Par défaut, l'appareil devient visible pendant deux minutes. Vous pouvez définir une durée différente, jusqu'à cinq minutes, en ajoutant l'élément supplémentaire EXTRA_DISCOVERABLE_DURATION.

L'extrait de code suivant définit l'appareil comme détectable pendant cinq minutes:

Kotlin

val requestCode = 1;
val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
   putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivityForResult(discoverableIntent, requestCode)

Java

int requestCode = 1;
Intent discoverableIntent =
       new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(discoverableIntent, requestCode);


Figure 2:Boîte de dialogue permettant d'activer la visibilité

Une boîte de dialogue s'affiche, demandant l'autorisation de l'utilisateur pour rendre l'appareil détectable, comme illustré dans la figure 2. Si l'utilisateur répond "Autoriser", l'appareil devient détectable pendant la durée spécifiée. Votre activité reçoit ensuite un appel au rappel onActivityResult(), avec le code de résultat égal à la durée pendant laquelle l'appareil est détectable. Si l'utilisateur a répondu "Refuser" ou si une erreur s'est produite, le code de résultat est RESULT_CANCELED.

L'appareil reste en mode découverte de manière silencieuse pendant la durée allouée. Pour être averti lorsque le mode de visibilité a changé, enregistrez un BroadcastReceiver pour l'intent ACTION_SCAN_MODE_CHANGED. Cet intent contient les champs supplémentaires EXTRA_SCAN_MODE et EXTRA_PREVIOUS_SCAN_MODE, qui fournissent respectivement le nouveau et l'ancien mode de numérisation. Les valeurs possibles pour chaque extra sont les suivantes:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
L'appareil est en mode visible.
SCAN_MODE_CONNECTABLE
L'appareil n'est pas en mode découverte, mais peut toujours recevoir des connexions.
SCAN_MODE_NONE
L'appareil n'est pas en mode visible et ne peut pas recevoir de connexions.

Si vous lancez la connexion à un appareil distant, vous n'avez pas besoin d'activer la visibilité de l'appareil. L'activation de la visibilité n'est nécessaire que lorsque vous souhaitez que votre application héberge un socket serveur qui accepte les connexions entrantes, car les appareils distants doivent pouvoir détecter d'autres appareils avant d'établir des connexions avec eux.