Encontrar dispositivos Bluetooth

Com o BluetoothAdapter, é possível encontrar dispositivos remotos Bluetooth pela descoberta de dispositivos ou consultando a lista de dispositivos pareados.

Verifique se você tem as permissões de Bluetooth adequadas e configure seu app para usar o Bluetooth antes de tentar encontrar dispositivos Bluetooth.

A descoberta de dispositivos é um procedimento de verificação que procura dispositivos com Bluetooth na área local e solicita algumas informações sobre cada um deles. Esse processo às vezes é chamado de descoberta, consulta ou verificação. Um dispositivo Bluetooth próximo responde a uma solicitação de descoberta somente se estiver aceitando solicitações de informações sendo detectável. Se um dispositivo for detectável, ele vai responder à solicitação de descoberta compartilhando algumas informações, como o nome, a classe e o endereço MAC exclusivo do dispositivo. Com essas informações, o dispositivo que está executando o processo de descoberta pode optar por iniciar uma conexão com o dispositivo descoberto.

Como dispositivos detectáveis podem revelar informações sobre a localização do usuário, o processo de descoberta de dispositivos requer acesso à localização. Caso seu app esteja sendo usado em um dispositivo com o Android 8.0 (nível 26 da API) ou versões mais recentes, considere usar a API Companion Device Manager. Essa API realiza a descoberta de dispositivos em nome do seu app. Assim, ele não precisa solicitar permissões de localização.

Depois que uma conexão com um dispositivo remoto é feita pela primeira vez, uma solicitação de pareamento é apresentada automaticamente ao usuário. Quando um dispositivo é pareado, as informações básicas dele, como nome, classe e endereço MAC, são salvas e podem ser lidas usando as APIs Bluetooth. Com o endereço MAC conhecido de um dispositivo remoto, é possível iniciar uma conexão com ele a qualquer momento sem executar a descoberta, desde que o dispositivo ainda esteja dentro do alcance.

Lembre-se de que há uma diferença entre estar pareado e estar conectado:

  • Estar pareado significa que os dois dispositivos estão cientes da existência um do outro, têm uma chave de link compartilhada que pode ser usada para autenticação e podem estabelecer uma conexão criptografada entre si.
  • Estar conectado significa que os dispositivos compartilham um canal RFCOMM e são capazes de transmitir dados entre si. As APIs Bluetooth atuais exigem que os dispositivos estejam pareados antes de estabelecer uma conexão RFCOMM. O pareamento é realizado automaticamente quando você inicia uma conexão criptografada com as APIs Bluetooth.

As seções a seguir descrevem como encontrar dispositivos que foram pareados e como descobrir novos dispositivos usando a descoberta de dispositivos.

Consultar dispositivos pareados

Antes de realizar a descoberta de dispositivos, vale a pena consultar o conjunto de dispositivos pareados para ver se o dispositivo desejado já é conhecido. Para fazer isso, chame o método getBondedDevices(). Isso retorna um conjunto de objetos BluetoothDevice que representa dispositivos pareados. Por exemplo, é possível consultar todos os dispositivos pareados e conseguir o nome e o endereço MAC de cada dispositivo, conforme demonstra o snippet de código a seguir:

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

Para iniciar uma conexão com um dispositivo Bluetooth, tudo o que é necessário do objeto BluetoothDevice associado é o endereço MAC, que você extrai chamando getAddress(). Saiba mais sobre como criar uma conexão em Conectar dispositivos Bluetooth.

Descobrir dispositivos

Para começar a descobrir dispositivos, chame startDiscovery(). O processo é assíncrono e retorna um valor booleano que indica se a descoberta foi iniciada com êxito. O processo de descoberta geralmente envolve uma verificação de cerca de 12 segundos, seguida por uma verificação de páginas de cada dispositivo encontrado para recuperar o nome Bluetooth.

Para receber informações sobre cada dispositivo descoberto, seu app precisa registrar um BroadcastReceiver para a intent ACTION_FOUND. O sistema transmite esse intent para cada dispositivo. A intent contém os campos extras EXTRA_DEVICE e EXTRA_CLASS, que por sua vez contêm um BluetoothDevice e um BluetoothClass, respectivamente. O snippet de código a seguir mostra como se registrar para processar a transmissão quando dispositivos são descobertos:

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

Para iniciar uma conexão com um dispositivo Bluetooth, chame getAddress() no BluetoothDevice para recuperar o endereço MAC associado.

Ativar a detecção do dispositivo

Para tornar o dispositivo local detectável para outros dispositivos, chame startActivityForResult(Intent, int) com a intent ACTION_REQUEST_DISCOVERABLE. Isso emite uma solicitação para ativar o modo detectável do sistema sem precisar navegar até o app Configurações, o que interromperia seu próprio app. Por padrão, o dispositivo fica detectável por dois minutos. Adicione o extra EXTRA_DISCOVERABLE_DURATION para definir uma duração diferente, de até uma hora.

O snippet de código a seguir define o dispositivo como detectável por cinco minutos:

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:caixa de diálogo de ativação da detecção do dispositivo.

Uma caixa de diálogo vai aparecer solicitando a permissão do usuário para tornar o dispositivo detectável, conforme mostrado na Figura 2. Se o usuário responder "Permitir", o dispositivo vai se tornar detectável pelo período especificado. Em seguida, a atividade recebe uma chamada para o callback onActivityResult(), com o código de resultado igual à duração em que o dispositivo fica detectável. Se o usuário tiver respondido "Negar" ou se ocorrer um erro, o código do resultado será RESULT_CANCELED.

O dispositivo permanecerá silenciosamente no modo detectável pelo tempo especificado. Para receber uma notificação quando o modo detectável mudar, registre um BroadcastReceiver para a intent ACTION_SCAN_MODE_CHANGED. Essa intent contém os campos extras EXTRA_SCAN_MODE e EXTRA_PREVIOUS_SCAN_MODE, que fornecem o modo de verificação novo e o antigo, respectivamente. Os valores possíveis para cada extra são estes:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
O dispositivo está no modo detectável.
SCAN_MODE_CONNECTABLE
O dispositivo não está no modo detectável, mas ainda pode receber conexões.
SCAN_MODE_NONE
O dispositivo não está no modo detectável e não pode receber conexões.

Se você estiver iniciando a conexão com um dispositivo remoto, não precisará ativar a detecção do dispositivo. Isso só é necessário quando você quer que o app hospede um soquete de servidor que aceite conexões de entrada, já que os dispositivos remotos precisam ser capazes de descobrir outros dispositivos antes de iniciar conexões com eles.