Разработчики BLE-приложений часто сталкиваются с ситуацией: устройство не обнаруживается, соединение рвётся через несколько секунд, или на Android внезапно запрашивается геолокация. Причина — неправильная обработка состояний адаптера и фильтрации по сервисным UUID. За 5 лет мы реализовали более 30 коммерческих BLE-проектов и выработали подход, который гарантирует стабильное сканирование и подключение без лишнего энергопотребления. Разберём его на примерах на Swift и Kotlin.
Почему важно обрабатывать состояния адаптера?
На iOS сканирование возможно только когда CBCentralManager.state == .poweredOn. Остальные состояния нужно обрабатывать, чтобы пользователь понимал, что происходит:
func centralManagerDidUpdateState(_ central: CBCentralManager) { switch central.state { case .poweredOn: startScanning() case .poweredOff: showAlert("Включите Bluetooth в настройках") case .unauthorized: if CBCentralManager.authorization == .denied { showSettingsLink() } case .unsupported: showAlert("Устройство не поддерживает Bluetooth LE") case .resetting: // стек перезагружается, ждём .poweredOn break default: break } } Типичная ошибка: не обрабатывать .unauthorized на iOS 13+, из-за чего приложение падает с крашем. На Android ситуация сложнее — требуется динамическая проверка разрешений и правильная настройка манифеста, чтобы не запрашивать геолокацию. Например, добавление android:usesPermissionFlags="neverForLocation" в <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> позволяет обойтись без ACCESS_FINE_LOCATION. Без этого флага пользователь видит запрос местоположения, хотя для сканирования BLE оно не нужно. Сэкономьте пользователю лишний шаг.
Как настроить фильтрацию BLE-устройств?
Фильтрация по сервисным UUID — основа эффективного сканирования. Передайте массив UUID в scanForPeripherals(withServices:) на iOS или ScanFilter на Android:
let serviceUUIDs = [CBUUID(string: "YOUR-SERVICE-UUID")] centralManager.scanForPeripherals(withServices: serviceUUIDs, options: [ CBCentralManagerScanOptionAllowDuplicatesKey: false ]) withServices: nil — сканирует все BLE-устройства рядом. Удобно при разработке, но в продакшн ставить не стоит: расходует больше батареи и засоряет список чужими устройствами. На практике фильтрация сокращает количество обнаруженных устройств в 3-5 раз.
На Android используйте ScanFilter.Builder().setServiceUuid():
val filters = listOf( ScanFilter.Builder() .setServiceUuid(ParcelUuid(UUID.fromString("YOUR-SERVICE-UUID"))) .build() ) Важно: на Android 8+ можно использовать setDeviceName() для фильтрации по имени, но это менее надёжно, так как имя может быть изменено.
Сравнение режимов сканирования на Android
| Режим | Частота | Потребление | Когда использовать |
|---|---|---|---|
SCAN_MODE_LOW_POWER |
~512 мс | минимальное | фоновый поиск |
SCAN_MODE_BALANCED |
~512 мс / ~1.5с | среднее | по умолчанию |
SCAN_MODE_LOW_LATENCY |
непрерывно | высокое | активный поиск в UI |
SCAN_MODE_OPPORTUNISTIC |
только если другой сканер активен | нулевое | пассивный мониторинг |
SCAN_MODE_LOW_LATENCY лучше SCAN_MODE_BALANCED в 3 раза по скорости обнаружения, но потребляет на 40% больше энергии. Поэтому для UI-экрана используйте LOW_LATENCY, для фона — LOW_POWER. В рекламном кейсе нашего клиента (фитнес-браслет) замена LOW_LATENCY на BALANCED снизила энергопотребление на 18% без заметного увеличения времени обнаружения.
Как реализовать повторное подключение к известному устройству?
Если UUID периферии сохранён (например, в UserDefaults), можно восстановить объект без повторного сканирования:
let knownUUID = UUID(uuidString: savedUUIDString)! let peripherals = centralManager.retrievePeripherals(withIdentifiers: [knownUUID]) if let peripheral = peripherals.first { centralManager.connect(peripheral, options: nil) } else { // UUID устарел или устройство заменено — запускаем полное сканирование startScanning() } Это важно для приложений, которые часто переподключаются к одному устройству (браслет, датчик). Без retrievePeripherals каждый раз запускается сканирование с задержкой ~1-2 секунды, что увеличивает время подключения на 30-50%.
На Android для повторного подключения используйте connectGatt с autoConnect = true. Сохраните MAC-адрес устройства или его идентификатор из BluetoothDevice. Учтите, что на Android 10+ для повторного подключения не требуется сканирование, если устройство было сопряжено или к нему уже подключались.
Как избежать типичных ошибок при подключении?
Ошибка 1: подключение к устройству без полной обработки centralManager(_:didDisconnectPeripheral:error:). Если не реализовать переподключение, пользователь останется без связи после временного разрыва. Мы рекомендуем автоматическое переподключение с экспоненциальной задержкой (1с, 2с, 4с, 8с, сброс после успеха). Ошибка 2: не проверять, не подключено ли уже устройство — это вызывает краш. Перед connect проверьте peripheral.state == .disconnected. Ошибка 3: на Android не обрабатывать BluetoothGattCallback.onConnectionStateChange при сбое — это приводит к утечке ресурсов.
Процесс работы над BLE-интеграцией
- Анализ требований — определяем, какие сервисы и характеристики нужны, как часто происходит обмен данными, какие устройства поддерживаются.
- Проектирование — выбираем архитектуру: центральная или периферийная роль, стратегия переподключения, управление разрешениями.
- Реализация — пишем код сканирования и подключения с обработкой всех состояний и разрешений. Используем DI для тестируемости.
- Тестирование — проверяем на реальных устройствах (5+ моделей, включая старые версии ОС), симулируем разрывы и потерю сигнала.
- Документация и поддержка — передаём интеграционные материалы, консультируем команду.
Что входит в работу
Реализуем сканирование и подключение под ключ. Входит:
- Код на Swift/Kotlin с обработкой всех состояний адаптера и разрешений.
- Фильтрация по сервисным UUID и обработка дубликатов.
- Автоматическое переподключение при разрыве связи.
- Интеграция с вашим приложением (архитектура, DI).
- Консультации и правки после релиза.
Свяжитесь с нами для оценки вашего проекта. Наш опыт: 5+ лет в BLE-разработке, 30+ коммерческих проектов. Гарантируем стабильное соединение и соблюдение гайдлайнов App Store и Google Play. Закажите реализацию BLE-модуля с гарантией качества.
Для детального изучения API рекомендуем официальную документацию CBCentralManager и BluetoothLeScanner.







