С помощью BluetoothAdapter можно находить удаленные устройства Bluetooth, выполняя поиск или запрашивая список подключенных устройств.
Прежде чем искать устройства Bluetooth, убедитесь, что у вас есть необходимые разрешения Bluetooth и вы настроили приложение для работы с Bluetooth.
Обнаружение устройств – это процедура сканирования, которая ищет в локальной области устройства с поддержкой Bluetooth и запрашивает информацию о каждом из них. Этот процесс иногда называют обнаружением, запросом или сканированием. Устройство Bluetooth поблизости отвечает на запрос обнаружения, только если оно в данный момент принимает запросы на информацию, будучи видимым. Если устройство видимо, оно отвечает на запрос, передавая определенную информацию, например свое название, класс и уникальный MAC-адрес. На основе этой информации устройство, выполняющее поиск, может инициировать подключение к обнаруженному устройству.
Поскольку видимые устройства могут раскрывать информацию о местоположении пользователя, для процесса обнаружения устройств требуется доступ к местоположению. Если ваше приложение используется на устройстве с Android 8.0 (уровень API 26) или более поздней версии, рекомендуем использовать API менеджера подключенных устройств. Этот API выполняет поиск устройств от имени вашего приложения, поэтому ему не нужно запрашивать доступ к данным о местоположении.
При первом подключении к удаленному устройству пользователю автоматически предлагается установить связь. Когда устройство подключено, основная информация о нем, например название, класс и MAC-адрес, сохраняется и может быть прочитана с помощью Bluetooth API. Зная MAC-адрес удаленного устройства, можно в любой момент установить с ним соединение без поиска, если оно находится в зоне действия.
Обратите внимание, что между сопряжением и подключением есть разница:
- Сопряжение означает, что два устройства обнаружили друг друга, имеют общий ключ связи, который можно использовать для аутентификации, и могут устанавливать зашифрованное соединение друг с другом.
- Подключенными считаются устройства, которые используют один и тот же канал RFCOMM и могут обмениваться данными. Текущие API Bluetooth требуют, чтобы устройства были сопряжены до того, как будет установлено соединение RFCOMM. Установление связи выполняется автоматически, когда вы инициируете зашифрованное подключение с помощью Bluetooth API.
В следующих разделах описывается, как найти устройства, которые были сопряжены, и как обнаружить новые устройства с помощью функции обнаружения устройств.
Запрос подключенных устройств
Прежде чем выполнять поиск устройств, стоит запросить набор сопряженных устройств, чтобы узнать, известно ли уже нужное устройство. Для этого вызовите метод getBondedDevices().
Возвращает набор объектов BluetoothDevice, представляющих подключенные устройства. Например, вы можете запросить все подключенные устройства и получить название и MAC-адрес каждого из них, как показано в следующем фрагменте кода:
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 } }
Чтобы установить соединение с устройством Bluetooth, из связанного объекта BluetoothDevice нужен только MAC-адрес, который можно получить, вызвав getAddress(). Подробнее о том, как подключить устройство Bluetooth…
Поиск устройств
Чтобы начать поиск устройств, отправьте вызов
startDiscovery().
Процесс является асинхронным и возвращает логическое значение, указывающее, успешно ли запущен поиск. Процесс обнаружения обычно включает в себя сканирование запросов в течение примерно 12 секунд, а затем сканирование страниц каждого найденного устройства для получения его имени Bluetooth.
Чтобы получать информацию о каждом обнаруженном устройстве, приложение должно зарегистрировать BroadcastReceiver для намерения ACTION_FOUND. Система передает это намерение для каждого устройства. Намерение содержит дополнительные поля EXTRA_DEVICE и EXTRA_CLASS, которые, в свою очередь, содержат BluetoothDevice и BluetoothClass соответственно.
В следующем фрагменте кода показано, как зарегистрироваться для обработки трансляции при обнаружении устройств:
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); }
Чтобы инициировать подключение к устройству Bluetooth, вызовите getAddress() в BluetoothDevice, чтобы получить связанный MAC-адрес.
Включить видимость
Чтобы сделать локальное устройство видимым для других устройств, вызовите startActivityForResult(Intent, int) с намерением ACTION_REQUEST_DISCOVERABLE. Это позволяет включить режим видимости, не переходя в приложение "Настройки", что привело бы к остановке вашего приложения. По умолчанию устройство становится видимым на две минуты. Вы можете задать другую продолжительность (до пяти минут), добавив дополнительный параметр EXTRA_DISCOVERABLE_DURATION.
В следующем фрагменте кода устройство настраивается так, чтобы оно было видимым в течение пяти минут:
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);
Рисунок 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- Устройство не находится в режиме видимости и не может принимать подключения.
Если вы инициируете подключение к удаленному устройству, включать видимость устройства не нужно. Включать видимость нужно, только если вы хотите, чтобы приложение размещало серверный сокет, принимающий входящие подключения. Это связано с тем, что удаленные устройства должны иметь возможность обнаруживать другие устройства, прежде чем инициировать подключение к ним.