Найти устройства Bluetooth

Используя BluetoothAdapter , вы можете найти удаленные устройства Bluetooth либо путем обнаружения устройств, либо путем запроса списка сопряженных устройств.

Прежде чем пытаться найти устройства Bluetooth, убедитесь, что у вас есть соответствующие разрешения Bluetooth , и настройте свое приложение для Bluetooth .

Обнаружение устройств — это процедура сканирования, которая ищет в локальной области устройства с поддержкой Bluetooth и запрашивает некоторую информацию о каждом из них. Этот процесс иногда называют обнаружением, исследованием или сканированием. Находящееся поблизости устройство Bluetooth отвечает на запрос обнаружения только в том случае, если оно в данный момент принимает информационные запросы и является доступным для обнаружения. Если устройство доступно для обнаружения, оно отвечает на запрос на обнаружение, предоставляя некоторую информацию, например имя устройства, его класс и уникальный MAC-адрес. Используя эту информацию, устройство, выполняющее процесс обнаружения, может затем инициировать соединение с обнаруженным устройством.

Поскольку обнаруживаемые устройства могут раскрывать информацию о местонахождении пользователя, процесс обнаружения устройств требует доступа к местоположению. Если ваше приложение используется на устройстве под управлением Android 8.0 (уровень API 26) или более поздней версии, рассмотрите возможность использования API Companion Device Manager . Этот API выполняет обнаружение устройств от имени вашего приложения, поэтому вашему приложению не нужно запрашивать разрешения на определение местоположения .

При первом подключении к удаленному устройству пользователю автоматически предоставляется запрос на сопряжение. Когда устройство сопряжено, основная информация об этом устройстве, такая как имя устройства, класс и MAC-адрес, сохраняется и может быть прочитана с помощью API-интерфейсов Bluetooth. Используя известный MAC-адрес удаленного устройства, с ним можно инициировать соединение в любое время без выполнения обнаружения, при условии, что устройство все еще находится в пределах досягаемости.

Обратите внимание, что существует разница между сопряжением и подключением:

  • Соединение означает, что два устройства знают о существовании друг друга, имеют общий ключ связи, который можно использовать для аутентификации, и способны устанавливать зашифрованное соединение друг с другом.
  • Соединение означает, что устройства в настоящее время используют общий канал RFCOMM и могут передавать данные друг другу. Текущие API-интерфейсы Bluetooth требуют, чтобы устройства были сопряжены, прежде чем можно будет установить соединение RFCOMM. Сопряжение выполняется автоматически, когда вы инициируете зашифрованное соединение с API-интерфейсами Bluetooth.

В следующих разделах описывается, как найти сопряженные устройства и как обнаружить новые устройства с помощью функции обнаружения устройств.

Запросить сопряженные устройства

Прежде чем выполнять обнаружение устройств, стоит запросить набор сопряженных устройств, чтобы узнать, известно ли уже нужное устройство. Для этого вызовите getBondedDevices() . Возвращает набор объектов BluetoothDevice представляющих сопряженные устройства. Например, вы можете запросить все сопряженные устройства и получить имя и MAC-адрес каждого устройства, как показано в следующем фрагменте кода:

Котлин

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

Ява

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

Чтобы инициировать соединение с устройством Bluetooth, все, что необходимо от связанного объекта BluetoothDevice — это MAC-адрес, который вы получаете, вызывая getAddress() . Подробнее о создании подключения можно узнать в разделе «Подключение устройств Bluetooth» .

Обнаружение устройств

Чтобы начать обнаружение устройств, вызовите startDiscovery() . Процесс является асинхронным и возвращает логическое значение, указывающее, успешно ли началось обнаружение. Процесс обнаружения обычно включает в себя сканирование запроса продолжительностью около 12 секунд, за которым следует сканирование страницы каждого найденного устройства для получения его имени Bluetooth.

Чтобы получать информацию о каждом обнаруженном устройстве, ваше приложение должно зарегистрировать BroadcastReceiver для намерения ACTION_FOUND . Система транслирует это намерение для каждого устройства. Намерение содержит дополнительные поля EXTRA_DEVICE и EXTRA_CLASS , которые, в свою очередь, содержат BluetoothDevice и BluetoothClass соответственно. В следующем фрагменте кода показано, как можно зарегистрироваться для управления широковещательной рассылкой при обнаружении устройств:

Котлин

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

Ява

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

Чтобы инициировать соединение с устройством Bluetooth, вы вызываете getAddress() на BluetoothDevice , чтобы получить связанный MAC-адрес.

Включить возможность обнаружения

Чтобы сделать локальное устройство доступным для обнаружения другими устройствами, вызовите startActivityForResult(Intent, int) с намерением ACTION_REQUEST_DISCOVERABLE . При этом выдается запрос на включение режима обнаружения системы без необходимости перехода к приложению «Настройки», что остановило бы ваше собственное приложение. По умолчанию устройство становится доступным для обнаружения в течение двух минут. Вы можете определить другую продолжительность, до одного часа, добавив дополнительную EXTRA_DISCOVERABLE_DURATION .

Следующий фрагмент кода делает устройство доступным для обнаружения в течение пяти минут:

Котлин

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

Ява

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


Рис. 2. Диалоговое окно включения возможности обнаружения.

Отображается диалоговое окно, запрашивающее разрешение пользователя на возможность обнаружения устройства, как показано на рисунке 2. Если пользователь отвечает «Разрешить», то устройство становится доступным для обнаружения в течение указанного периода времени. Затем ваша активность получает вызов обратного вызова onActivityResult() с кодом результата, равным продолжительности обнаружения устройства. Если пользователь ответил «Отклонить» или произошла ошибка, код результата — RESULT_CANCELED .

Устройство молча остается в режиме обнаружения в течение отведенного времени. Чтобы получать уведомления об изменении режима обнаружения, зарегистрируйте BroadcastReceiver для намерения ACTION_SCAN_MODE_CHANGED . Это намерение содержит дополнительные поля EXTRA_SCAN_MODE и EXTRA_PREVIOUS_SCAN_MODE , которые предоставляют новый и старый режим сканирования соответственно. Возможные значения для каждого дополнения следующие:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
Устройство находится в режиме обнаружения.
SCAN_MODE_CONNECTABLE
Устройство не находится в режиме обнаружения, но все равно может получать соединения.
SCAN_MODE_NONE
Устройство не находится в режиме обнаружения и не может принимать соединения.

Если вы инициируете подключение к удаленному устройству, вам не нужно включать возможность обнаружения устройства. Включение возможности обнаружения необходимо только в том случае, если вы хотите, чтобы в вашем приложении размещался серверный сокет, который принимает входящие соединения, поскольку удаленные устройства должны иметь возможность обнаруживать другие устройства перед инициацией подключений к этим другим устройствам.