Trovare dispositivi Bluetooth

Con BluetoothAdapter, puoi trovare dispositivi Bluetooth remoti tramite il rilevamento dei dispositivi o eseguendo una query sull'elenco dei dispositivi accoppiati.

Assicurati di disporre delle autorizzazioni relative al Bluetooth appropriate e di configurare la tua app per il Bluetooth prima di tentare di trovare i dispositivi Bluetooth.

Il rilevamento dei dispositivi è una procedura di scansione che cerca dispositivi dotati di Bluetooth nell'area locale e richiede alcune informazioni su ciascuno. Questo processo è a volte indicato come scoperta, richiesta di informazioni o scansione. Un dispositivo Bluetooth nelle vicinanze risponde a una richiesta di rilevamento solo se sta accettando richieste di informazioni in quanto rilevabile. Se un dispositivo è rilevabile, risponde alla richiesta di rilevamento condividendo alcune informazioni, come il nome del dispositivo, la sua classe e il suo indirizzo MAC univoco. Utilizzando queste informazioni, il dispositivo che sta eseguendo il processo di rilevamento può quindi scegliere di avviare una connessione al dispositivo rilevato.

Poiché i dispositivi rilevabili potrebbero rivelare informazioni sulla posizione dell'utente, la procedura di rilevamento dei dispositivi richiede l'accesso alla posizione. Se la tua app viene utilizzata su un dispositivo con Android 8.0 (livello API 26) o versioni successive, valuta la possibilità di utilizzare invece l'API Companion Device Manager. Questa API esegue il rilevamento dei dispositivi per conto della tua app, pertanto l'app non deve richiedere le autorizzazioni di accesso alla posizione.

Una volta stabilita una connessione con un dispositivo remoto per la prima volta, viene presentata automaticamente all'utente una richiesta di accoppiamento. Quando un dispositivo è accoppiato, le relative informazioni di base, come il nome, la classe e l'indirizzo MAC, vengono salvate e possono essere lette utilizzando le API Bluetooth. Utilizzando l'indirizzo MAC noto per un dispositivo remoto, è possibile avviare una connessione con il dispositivo in qualsiasi momento senza eseguire il rilevamento, supponendo che il dispositivo sia ancora nel raggio d'azione.

Tieni presente che c'è una differenza tra essere accoppiati ed essere connessi:

  • L'accoppiamento significa che due dispositivi sono a conoscenza dell'esistenza reciproca, dispongono di una chiave di collegamento condivisa che può essere utilizzata per l'autenticazione e sono in grado di stabilire una connessione criptata tra loro.
  • Per essere connessi significa che i dispositivi attualmente condividono un canale RFCOMM e sono in grado di trasmettere dati tra loro. Le attuali API Bluetooth richiedono l'accoppiamento dei dispositivi prima di poter stabilire una connessione RFCOMM. L'accoppiamento viene eseguito automaticamente quando avvii una connessione criptata con le API Bluetooth.

Le seguenti sezioni descrivono come trovare i dispositivi accoppiati e ne scoprire di nuovi utilizzando la funzionalità di rilevamento dei dispositivi.

Esegui query su dispositivi accoppiati

Prima di eseguire il rilevamento dei dispositivi, vale la pena eseguire una query sull'insieme di dispositivi accoppiati per verificare se il dispositivo desiderato è già noto. Per farlo, chiama il numero getBondedDevices(). Viene restituito un insieme di oggetti BluetoothDevice che rappresentano i dispositivi accoppiati. Ad esempio, puoi eseguire query su tutti i dispositivi accoppiati e ottenere il nome e l'indirizzo MAC di ciascun dispositivo, come illustrato nel seguente snippet di codice:

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
   }
}

Per avviare una connessione con un dispositivo Bluetooth, tutto ciò che serve dall'oggetto BluetoothDevice associato è l'indirizzo MAC, che puoi recuperare chiamando getAddress(). Puoi scoprire di più sulla creazione di una connessione nell'articolo Connettere dispositivi Bluetooth.

Scopri i dispositivi

Per iniziare a rilevare i dispositivi, chiama il numero startDiscovery(). Il processo è asincrono e restituisce un valore booleano che indica se il rilevamento è stato avviato correttamente. Il processo di rilevamento solitamente prevede una scansione di circa 12 secondi, seguita da una scansione di pagina di ciascun dispositivo trovato per recuperare il nome Bluetooth.

Per ricevere informazioni su ogni dispositivo rilevato, la tua app deve registrare un elemento BroadcastReceiver per l'intent ACTION_FOUND. Il sistema trasmette questo intent per ciascun dispositivo. L'intent contiene i campi aggiuntivi EXTRA_DEVICE e EXTRA_CLASS, che a loro volta contengono rispettivamente un BluetoothDevice e un BluetoothClass. Il seguente snippet di codice mostra come registrarti per gestire la trasmissione quando vengono rilevati i dispositivi:

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);
}

Per avviare una connessione con un dispositivo Bluetooth, chiama getAddress() sul BluetoothDevice per recuperare l'indirizzo MAC associato.

Attiva rilevabilità

Per rendere il dispositivo locale rilevabile da altri dispositivi, chiama startActivityForResult(Intent, int) con l'intent ACTION_REQUEST_DISCOVERABLE. Viene inviata una richiesta per abilitare la modalità rilevabile del sistema senza dover accedere all'app Impostazioni, che interromperà la tua app. Per impostazione predefinita, il dispositivo diventa rilevabile per due minuti. Puoi definire una durata diversa, fino a un'ora, aggiungendo EXTRA_DISCOVERABLE_DURATION.

Il seguente snippet di codice imposta il dispositivo per essere rilevabile per cinque minuti:

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);


Figura 2: la finestra di dialogo di attivazione della rilevabilità.

Viene visualizzata una finestra di dialogo che richiede l'autorizzazione dell'utente per rendere il dispositivo rilevabile, come mostrato nella figura 2. Se l'utente risponde "Consenti", il dispositivo diventa rilevabile per il periodo di tempo specificato. La tua attività riceve quindi una chiamata al callback di onActivityResult(), con il codice risultato uguale alla durata del rilevamento del dispositivo. Se l'utente ha risposto "Rifiuta" o se si è verificato un errore, il codice risultato è RESULT_CANCELED.

Il dispositivo rimane in modalità rilevabile per il tempo allocato. Per ricevere una notifica quando la modalità rilevabile è stata modificata, registra un BroadcastReceiver per l'intent ACTION_SCAN_MODE_CHANGED. Questo intent contiene i campi aggiuntivi EXTRA_SCAN_MODE e EXTRA_PREVIOUS_SCAN_MODE, che forniscono rispettivamente la nuova e la vecchia modalità di scansione. I valori possibili per ciascun valore aggiuntivo sono i seguenti:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
Il dispositivo è in modalità rilevabile.
SCAN_MODE_CONNECTABLE
Il dispositivo non è in modalità rilevabile, ma può comunque ricevere connessioni.
SCAN_MODE_NONE
Il dispositivo non è in modalità rilevabile e non può ricevere connessioni.

Se avvii la connessione a un dispositivo remoto, non è necessario abilitare la rilevabilità del dispositivo. L'attivazione della rilevabilità è necessaria solo se vuoi che la tua app ospiti un socket del server che accetti le connessioni in entrata, in quanto i dispositivi remoti devono essere in grado di rilevare altri dispositivi prima di avviare connessioni a questi dispositivi.