Usando o BluetoothAdapter
,
é possível encontrar dispositivos Bluetooth remotos pela descoberta de dispositivos ou
consultando a lista de dispositivos pareados.
Confira se você tem as permissões de Bluetooth adequadas e configure seu app para 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 por perto só vai responder a uma solicitação de descoberta se estiver aceitando solicitações de informações. Se um dispositivo estiver 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. Usando essas informações, o dispositivo que está realizando o processo de descoberta pode escolher iniciar uma conexão com o dispositivo descoberto.
Como os dispositivos detectáveis podem revelar informações sobre a localização do usuário, o processo de detecção de dispositivos exige acesso à localização. Se o app estiver sendo usado em um dispositivo com o Android 8.0 (nível 26 da API) ou mais recente, use a API Companion Device Manager. Essa API realiza a descoberta de dispositivos em nome do app, para que ele não precise solicitar permissões de localização.
Quando uma conexão é estabelecida com um dispositivo remoto pela primeira vez, uma solicitação de pareamento é apresentada automaticamente ao usuário. Quando um dispositivo é pareado, as informações básicas sobre ele, como o nome, a classe e o endereço MAC, são salvas e podem ser lidas usando as APIs do Bluetooth. Usando o endereço MAC conhecido de um dispositivo remoto, uma conexão pode ser iniciada com ele a qualquer momento sem realizar a descoberta, desde que o dispositivo ainda esteja no alcance.
Lembre-se de que há uma diferença entre estar pareado e estar conectado:
- Estar pareado significa que dois dispositivos sabem da existência um do outro, têm uma chave de link compartilhada que pode ser usada para autenticação e são capazes de estabelecer uma conexão criptografada entre si.
- Estar conectado significa que os dispositivos compartilham um canal RFCOMM e podem transmitir dados entre si. As APIs atuais do Bluetooth exigem que os dispositivos sejam pareados antes que uma conexão RFCOMM possa ser estabelecida. O pareamento é realizado automaticamente quando você inicia uma conexão criptografada com as APIs Bluetooth.
As seções a seguir descrevem como encontrar dispositivos 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
emparelhados para saber se o dispositivo desejado já é conhecido. Para fazer isso,
chame o método getBondedDevices()
.
Isso retorna um conjunto de
objetos BluetoothDevice
que representam dispositivos pareados. Por exemplo, é possível consultar todos os dispositivos pareados e
receber o nome e o endereço MAC de cada um deles, conforme demonstrado no snippet de código
abaixo:
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ê recupera 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 indicando se
a descoberta foi iniciada. O processo de descoberta geralmente envolve uma
verificação de consulta de cerca de 12 segundos, seguida por uma verificação de página de cada dispositivo encontrado
para recuperar o nome do Bluetooth.
Para receber informações sobre cada dispositivo descoberto, o 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 abaixo mostra como se registrar para processar a transmissão
quando os 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 por 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. É possível definir uma
duração diferente, de até cinco minutos, adicionando o
extra
EXTRA_DISCOVERABLE_DURATION
.
O snippet de código abaixo 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 capacidade de descoberta.
Uma caixa de diálogo é mostrada, 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 ficar detectável pelo período especificado. Sua atividade vai receber uma chamada para o callback
onActivityResult()
, com o código de resultado igual à duração em que o dispositivo é
detectável. Se o usuário responder "Negado" ou se ocorrer um erro, o código
de resultado será RESULT_CANCELED
.
O dispositivo permanecerá silenciosamente no modo detectável pelo tempo especificado. Para receber
notificações quando o modo de descoberta 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 antigo, respectivamente. Os valores possíveis para cada
extra são os seguintes:
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 será necessário ativar a detecção do dispositivo. Ativar a detectabilidade é necessário apenas quando você quer que o app hospede um socket de servidor que aceite conexões de entrada, já que os dispositivos remotos precisam detectar outros dispositivos antes de iniciar conexões com eles.