Реализация сканирования и подключения BLE-устройств

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация сканирования и подключения BLE-устройств
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1054
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Реализация сканирования и подключения BLE-устройств

Задача выглядит просто: найти BLE-устройство, подключиться. На практике — это обработка восьми различных состояний адаптера, разных режимов сканирования и нюансов работы конкретных чипсетов. Рассмотрим только эту часть BLE-стека, без чтения характеристик.

iOS: сканирование через CBCentralManager

Сканирование возможно только когда CBCentralManager.state == .poweredOn. Остальные состояния нужно обрабатывать:

func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
    case .poweredOn:
        startScanning()
    case .poweredOff:
        showAlert("Включите Bluetooth в настройках")
    case .unauthorized:
        // iOS 13+ — CBManager.authorization
        if CBCentralManager.authorization == .denied {
            showSettingsLink()
        }
    case .unsupported:
        showAlert("Устройство не поддерживает Bluetooth LE")
    case .resetting:
        // стек перезагружается, ждём .poweredOn
        break
    default:
        break
    }
}

Фильтрация при сканировании

// Сканируем только устройства с нужным сервисом
let serviceUUIDs = [CBUUID(string: "YOUR-SERVICE-UUID")]
centralManager.scanForPeripherals(withServices: serviceUUIDs, options: [
    CBCentralManagerScanOptionAllowDuplicatesKey: false
])

withServices: nil — сканирует все BLE-устройства рядом. Удобно при разработке. В продакшн не ставить: расходует больше батареи и засоряет список чужими устройствами.

Повторное подключение к известному устройству

Если 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 каждый раз запускается сканирование с задержкой.

Android: BluetoothLeScanner

val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
val scanner = bluetoothAdapter.bluetoothLeScanner

val filters = listOf(
    ScanFilter.Builder()
        .setServiceUuid(ParcelUuid(UUID.fromString("YOUR-SERVICE-UUID")))
        .build()
)

val settings = ScanSettings.Builder()
    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // при активном использовании
    .setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
    .build()

val scanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult) {
        val device = result.device
        val rssi = result.rssi
        val advertisingData = result.scanRecord
        // добавляем в список найденных устройств
    }

    override fun onScanFailed(errorCode: Int) {
        // SCAN_FAILED_ALREADY_STARTED = 1 — сканирование уже запущено
        // SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2 — слишком много сканеров
        // SCAN_FAILED_FEATURE_UNSUPPORTED = 4 — фильтры не поддерживаются (старые устройства)
    }
}

scanner.startScan(filters, settings, scanCallback)

Режимы сканирования

Режим Частота Потребление Когда использовать
SCAN_MODE_LOW_POWER ~512 мс минимальное фоновый поиск
SCAN_MODE_BALANCED ~512 мс / ~1.5с среднее по умолчанию
SCAN_MODE_LOW_LATENCY непрерывно высокое активный поиск в UI
SCAN_MODE_OPPORTUNISTIC только если другой сканер активен нулевое пассивный мониторинг

Разрешения Android 12+

// Проверяем перед сканированием
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    when {
        ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED -> {
            requestPermissions(arrayOf(
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT
            ), REQUEST_CODE)
        }
    }
}

BLUETOOTH_SCAN без neverForLocation флага требует ACCESS_FINE_LOCATION. Если сканирование не для определения местоположения, в манифесте:

<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />

Тогда геолокация не нужна и пользователю не придётся объяснять, почему Bluetooth-приложение просит доступ к GPS.

Срок реализации: 2-3 дня — сканирование + подключение с обработкой всех состояний и разрешений на обеих платформах. Стоимость рассчитывается индивидуально.