Використання bluetooth в android

Платформа Android надає розробнику багаті комунікаційні можливості. Для роботи з Bluetooth до складу Android входить потужний API, що дозволяє легко проводити сканування навколишнього простору на предмет наявності готових до з'єднання пристроїв, передачу даних між пристроями та багато іншого.

Робота з Bluetooth складається з чотирьох етапів: установка налаштувань bluetooth адаптера, пошук доступних для з'єднання пристроїв, установка з'єднання, передача даних.

Огляд Android Bluetooth API

Bluetooth API розташовується в пакетеandroid.bluetooth. До його складу входить кілька класів:

В рамках цієї статті ми не будемо заглиблюватися в суть роботи з медичними bluetooth пристроями і зосередимося на перших чотирьох класах.

Установка налаштувань Bluetooth адаптера з Android

Якщо Ви вирішили задіяти в своїй програмі можливості Bluetooth модуля, вам необхідно, перш за все, підключити відповідний пакет API.

Крім цього необхідно дати додатком дозвіл на використання Bluetooth модуля. Для цього в маніфест програми потрібно додати рядок

Якщо Ви збираєтеся використовувати критичні з точки зору безпеки можливості, наприклад, змінити ім'я пристрою, то потрібно дати більш потужні дозволу BLUETOOTH_ADMIN:

При використанні дозволу BLUETOOTH_ADMIN, необхідно також вказувати і BLUETOOTH.

Навіть якщо ваш апарат оснащений Bluetooth модулем, він може бути недоступний, оскільки користувач просто відключив його. Для перевірки доступності Bluetooth служить метод isEnabled (). У разі, якщо модуль відключений, можна запропонувати користувачеві включити його.

Якщо користувач погодився на включення адаптера, в змінну enableBtIntent буде записано значення RESULT_OK. В іншому випадку - RESULT_CANCELED.

Якщо додаток має дозвіл BLUETOOTH_ADMIN, ви можете змінити ім'я Bluetooth пристрою за допомогою методу

для відображення стану адаптера служить метод BluetoothAdapter.getState (). Цей метод може повертати одне з наступних значень:

STATE_TURNING_ON
STATE_ON
STATE_TURNING_OFF
STATE_OFF

Часто з метою економії заряду батареї Bluetooth вимкнений за замовчуванням. Наступних код створює повідомлення, в якому буде сповіщати про стан адаптера:

Організація пошуку доступних bluetooth пристроїв

За допомогою класу BluetoothAdapter, Ви можете знайти віддалене bluetooth пристрій, запустивши сканування або надіславши запит список спарених пристроїв.

Необхідно розрізняти поняття спарених і з'єднаних пристроїв. Сприяння пристрої просто знають про існування один одного, мають посилання-ключ, яку можуть використовувати для аутентифікації, і здатні створити шифрування з'єднання один з одним. Сполучені пристрої поділяють один радіоканал і можуть передавати дані один одному. Поточна реалізація bluetooth API вимагає, щоб пристрої були спарені перед з'єднанням. (Парування виконується автоматично, коли ви починаєте шифрування з'єднання через Bluetooth API)

Запит на з'єднання зі спареним пристроєм

Пошук пристроїв

Для того, щоб почати сканування радіодіапазону на предмет наявності доступних пристроїв просто викличте метод startDiscovery (). Сканування відбувається в окремому асинхронному потоці. Метод повертає true, якщо запуск сканування пройшов успішно. Зазвичай процес сканування займає близько 10-15 секунд. Щоб отримати інформацію про знайдені пристроях Ваше застосування повинне зареєструвати BroadcastReceiver для ІНТЕНТ ACTION_FOUND. Цей Интент викликається для кожного знайденого пристрою. Интент містить додаткові поля EXTRA_DEVICE і EXTRA_CLASS, які містять об'єкти BluetoothDevice і BluetoothClass відповідно.

Включення Bluetooth з програми

Якщо ви хочете отримати повідомлення, при зміні режиму видимості Вашого пристрою, зареєструйте BroadcastReceiver для ІНТЕНТ ACTION_SCAN_MODE_CHANGED. Додаткові поля EXTRA_SCAN_MODE і EXTRA_PREVIOUS_SCAN_MODE дозволяють отримати інформацію про новий і старому стані відповідно. Вони можуть набувати значень SCAN_MODE_CONNECTABLE_DISCOVERABLE, SCAN_MODE_CONNECTABLE або SCAN_MODE_NONE. Перше значення вказує на те, що пристрій перебуває в зоні видимості. Друге - пристрій не доступно для пошуку, але здатне приймати з'єднання. Третє - не доступно для пошуку і не може приймати з'єднання.

з'єднання пристроїв

При з'єднанні пристроїв одне з них повинно вести себе як сервер, тобто утримувати відкритий BluetoothServerSocket. Мета сервера - чекати запиту на вхідне з'єднання, і коли воно підтверджено, створити BluetoothSocket. Після цього BluetoothServerSocket можна закрити. Розглянемо поетапно процедуру з'єднання з точки зору сервера:

  1. Отримати BluetoothServerSocket викликавши метод listenUsingRfcommWithServiceRecord (String, UUID). Перший параметр методу є ідентифікаційне ім'я вашого сервісу. Система автоматично додасть його в базу Service Discovery Protocol (SDP). Зазвичай в якості цього параметра просто вказують назву програми. Другий параметр також ідентифікує сервіс. Цей параметр використовується клієнтом при підтвердженні з'єднання.
  2. Починаємо прослуховувати запит на з'єднання через метод accept (). Це блокуючий метод, який повертає результат або коли з'єднання підтверджено, або коли сталося виняток. З'єднання вважається підтвердженим, коли віддалений пристрій пошле запит на з'єднання з UUID, зазначеним при реєстрації серверного сокета. У разі успіху, accept () повертає налаштований на з'єднання BluetoothSocket.
  3. Якщо Ви хочете прийняти додаткове з'єднання, викличте метод close (). Це призведе до звільнення сокета і всіх його ресурсів, але не закриє з'єднаний BluetoothSocket. На відміну від TCP / IP, RFCOMM дозволяє працювати тільки з одним клієнтом на каналі, тому в більшості випадків має сенс викликати метод close () зрізу ж після установки прийняття сокета.

Оскільки метод accept () є блокуючим, його не варто викликати з потоку головною діяльності, оскільки це призведе до підвисання інтерфейсу. Звичайна вся робота з BluetoothServerSocket і BluetoothSocket виконується в окремому потоці. Щоб припинити виконання методу accept (), викличте метод close () для BluetoothServerSocket (або BluetoothSocket) з будь-якого іншого потоку вашого застосування.

Нижче наведено приклад потоку, який реалізує описаний вище механізм роботи

У цьому прикладі мається на увазі, що може бути встановлено тільки одне з'єднання, тому після того, як з'єднання підтверджено і отримано BluetoothSocket, додаток посилає його окремому потоку, закриває BluetoothServerSocket і виходить з циклу.

Зверніть увагу, коли accept () повертає BluetoothSocket, сокет вже з'єднаний, тому не потрібно викликати метод connect ().

manageConnectedSocket () являє собою метод, всередині якого потрібно створити потік для передачі даних. Його можлива реалізація буде розглянута нижче.

Ви повинні закрити BluetoothServerSocket відразу ж після завершення прослуховування ефіру на предмет наявності вхідного з'єднання. У наведеному прикладі метод close () викликається відразу після отримання об'єкта BluetoothSocket. Також Вам може знадобитися public метод для зупинки приватного BluetoothSocket.

Для ініціалізації з'єднання з віддаленим пристроїв (пристроєм, який тримає відкритим серверний сокет) вам необхідно отримати об'єкт BluetoothDevice, що містить інформацію про нього. Цей об'єкт використовується для отримання BluetoothSocket і ініціалізації з'єднання.

Опишемо процедуру з'єднання:

  1. Отримаємо BluetoothSocket викликавши метод BluetoothDevice.createRfcommSocketToServiceRecord (UUID). Значення параметра UUID повинно збігатися з значенням, зазначеним при виклику listenUsingRfcommWithServiceRecord сервера.
  2. Ініціалізіруем з'єднання, викликавши метод connect (). Після виклику цього методу система буде виконувати SDP пошук на віддаленому пристрої, щоб зіставити UUID. У разі успіху за умови підтвердження запиту з боку сервера буде відкритий RFCOMM канал. Це блокуючий виклик. Якщо з якихось причин з'єднання зірветься або вийде timeout (близько 12 секунд), буде згенеровано виняток.


Як і у випадку з accept, метод connect () слід виконувати в окремому потоці, в іншому випадку може статися підвисання інтерфейсу.

Зауваження. Перш ніж викликати connect () переконайтеся, що в даний момент не відбувається сканування з метою пошуку доступних пристроїв. У разі одночасного виконання цих операцій з'єднання буде встановлюватися набагато повільніше, і ви ризикуєте не вкластися в timeout.

Наведемо приклад клієнтської програми, не започатковано з'єднання

Для зупинки сканування ефіру викликається метод cancelDiscovery (). Перед викликом цього методу можна перевірити чи йде сканування за допомогою isDiscovering ().

Передача даних

Після успішного з'єднання, кожне з з'єднаних пристроїв має об'єкт BluetoothSocket за допомогою якого легко реалізувати передачу / прийом даних:

  1. За допомогою методів getInputStream () і getOutputStream () підлозі об'єкти InputStream і OutputStream, керуючі передачею через сокет.
  2. Читати і писати дані в потік за допомогою методів read (byte []) і write (byte []).

Ви повинні використовувати окремий потік для читання і запису даних. Це важливо, оскільки методи read (byte []) і write (byte []) є блокуючими і їх виклик в основному потоці може паралізувати вашу програму. Головний цикл в цьому окремому потоці повинен зчитувати дані з InputStream. Для запису в OutputStream має сенс створити окремий public метод.

Переклад: Олександр льодком
Джерело: developer.android.com