Интеграция с железом: BLE, NFC, IoT и HomeKit в мобильных приложениях
Когда задача — связать смартфон с физическим устройством, половина проблем находится не в коде, а в прошивке железа, характеристиках BLE-сервисов и задержках протокола. Мобильный разработчик здесь работает на стыке с firmware-командой, и без понимания стека снизу вверх результат непредсказуем.
BLE: где всё обычно ломается
Bluetooth Low Energy — основной протокол для носимых, медицинских устройств, умных замков и промышленных датчиков. Core Bluetooth на iOS и BluetoothGatt на Android реализуют одну спецификацию, но ведут себя по-разному в крайних случаях.
Самая болезненная точка — управление подключением. На iOS CBCentralManager требует хранения сильной ссылки на протяжении всей сессии; если объект уничтожается, соединение молча закрывается. В Android BluetoothGatt нужно явно вызывать gatt.disconnect() и gatt.close() по отдельности — только close() без disconnect() оставляет устройство в состоянии «занято» и следующее подключение падает с ошибкой 133 (GATT_ERROR). Ошибка 133 — самая частая в Android BLE-разработке, и это не «что-то пошло не так», а конкретный случай переполнения очереди GATT или некорректного закрытия предыдущей сессии.
Сканирование тоже нетривиально. На Android 12+ BLUETOOTH_SCAN требует neverForLocation флага если вам не нужна геолокация — без него пользователь видит запрос на местоположение при подключении к замку, что вызывает недоумение. На iOS с iOS 13 NSBluetoothAlwaysUsageDescription обязателен в Info.plist, и приложение молча не будет сканировать без него — без крэша, без лога.
Для надёжной работы в production используем очередь операций над GATT: write, read, notification subscribe — строго последовательно через операционную очередь, иначе при конкурентных запросах характеристики возвращают ошибку ATT_INSUFFICIENT_RESOURCES.
NFC: CoreNFC и Android NFC API
iOS поддерживает NFC-чтение через CoreNFC с iOS 11, запись — с iOS 13. Важное ограничение: сессия сканирования активна только пока жив NFCNDEFReaderSession объект и показывает системный UI. Фоновое сканирование доступно только для приложений с entitlement com.apple.developer.nfc.readersession.formats и только для ISO 14443 (банковские карты, паспорта) — и это entitlement выдаётся не всем.
На Android всё проще: NfcAdapter.enableForegroundDispatch() ловит теги в foreground без системного UI. Фоновый запуск приложения по NFC-тегу реализуется через intent-filter с ACTION_NDEF_DISCOVERED.
HomeKit и Matter
HomeKit — экосистема Apple для умного дома. Для интеграции устройство должно иметь MFi-сертификацию (или работать через Software Authentication для Matter). Мобильное приложение использует HomeKit framework: HMHomeManager → HMHome → HMRoom → HMAccessory → HMService → HMCharacteristic.
Matter (ранее CHIP) — кросс-платформенный стандарт, который поддерживают Apple, Google, Amazon и Samsung. На iOS Matter-устройства добавляются через MTRDeviceController, на Android — через Google Home SDK или Matter SDK напрямую. Преимущество Matter: одно устройство работает с HomeKit, Google Home и Alexa без перепрошивки.
Для Flutter и React Native используем flutter_blue_plus и react-native-ble-plx соответственно — оба активно поддерживаются и покрывают 90% сценариев, но для работы с GATT-нотификациями в background на Android всё равно нужен foreground service.
Как выстраиваем работу
Процесс начинается с получения спецификации BLE GATT (список сервисов, характеристик, форматы данных) или HCI-лога от firmware-команды. Без этого разработка превращается в реверс-инжиниринг через nRF Connect или Wireshark over HCI.
Тестируем на реальных устройствах с первого дня — эмулятор BLE в симуляторах не воспроизводит edge cases переподключения, потери сигнала, смены MTU.
Сроки: простая интеграция с одним BLE-периферийным устройством (показания + команды управления) — 2-4 недели. Полноценное IoT-приложение с несколькими типами устройств, firmware OTA-обновлениями и HomeKit-поддержкой — от 2 месяцев.







