Используя 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
- Устройство не находится в режиме обнаружения и не может принимать соединения.
Если вы инициируете подключение к удаленному устройству, вам не нужно включать возможность обнаружения устройства. Включение возможности обнаружения необходимо только в том случае, если вы хотите, чтобы в вашем приложении размещался серверный сокет, который принимает входящие соединения, поскольку удаленные устройства должны иметь возможность обнаруживать другие устройства перед инициацией подключений к этим другим устройствам.