Stable BLE Integration for Mobile Apps

BLE Integration: Stable Operation with Devices We often see projects where BLE connection is implemented as "turn on scanning — connect — enjoy." In reality it's a state machine with a dozen states, each of which can fail: adapter off, device out of range, service not found, characteristic doesn'

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Stable BLE Integration for Mobile Apps
Complex
~3-5 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

BLE Integration: Stable Operation with Devices

We often see projects where BLE connection is implemented as "turn on scanning — connect — enjoy." In reality it's a state machine with a dozen states, each of which can fail: adapter off, device out of range, service not found, characteristic doesn't support write. Our team are specialists with 5+ years of experience developing BLE solutions for iOS and Android. We guarantee your app will stably handle all edge cases.

Why Does BLE Integration Require a Professional Approach?

BLE operates on the GATT (Generic Attribute Profile) model. The peripheral device provides Services — logical groups of functions. Each Service contains Characteristics — specific values for reading, writing, or subscribing (notify/indicate). An error at any of these levels — and the app won't receive data. We've seen projects where developers forgot to subscribe to the CCCD descriptor — as a result, the characteristic didn't send notifications.

Connection State Machine

Minimum set of states that must be explicitly handled:

IDLE → SCANNING → DISCOVERED → CONNECTING → CONNECTED → DISCOVERING_SERVICES → SERVICES_READY → SUBSCRIBING → READY 

And errors at each transition: scanning timeout, connection break in CONNECTING, gattStatus != GATT_SUCCESS at discovery, connection loss in READY. We test all scenarios using simulators and real devices.

State iOS (CoreBluetooth) Android (BluetoothGatt)
IDLE .poweredOn BluetoothAdapter.state_on
SCANNING scanForPeripherals startScan
DISCOVERED didDiscover onScanResult
CONNECTING connect connectGatt
CONNECTED didConnect onConnectionStateChange (STATE_CONNECTED)
DISCOVERING_SERVICES discoverServices discoverServices
SERVICES_READY didDiscoverServices onServicesDiscovered
SUBSCRIBING setNotifyValue writeDescriptor (CCCD)
READY didUpdateValue onCharacteristicChanged

What to Do If the Connection Drops?

The most common error is ignoring didDisconnectPeripheral (iOS) or onConnectionStateChange with non-GATT_SUCCESS (Android). Without automatic reconnection, the user has to restart the app. We implement logic with exponential backoff: on disconnection wait 1s, 2s, 4s, 8s, then reset. On iOS for background operation we use CBCentralManagerOptionRestoreIdentifierKey — system wakes up the app when device reappears.

iOS: CoreBluetooth

import CoreBluetooth class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate { var centralManager: CBCentralManager! var targetPeripheral: CBPeripheral? override init() { super.init() centralManager = CBCentralManager(delegate: self, queue: DispatchQueue(label: "ble.queue")) } func centralManagerDidUpdateState(_ central: CBCentralManager) { guard central.state == .poweredOn else { // handle .poweredOff, .unauthorized, .unsupported return } startScanning() } func startScanning() { let serviceUUID = CBUUID(string: "180D") centralManager.scanForPeripherals(withServices: [serviceUUID], options: [ CBCentralManagerScanOptionAllowDuplicatesKey: false ]) } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { guard RSSI.intValue > -80 else { return } // filter by signal centralManager.stopScan() targetPeripheral = peripheral centralManager.connect(peripheral, options: nil) } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { peripheral.delegate = self peripheral.discoverServices([CBUUID(string: "180D")]) } func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { guard error == nil, let services = peripheral.services else { return } for service in services { peripheral.discoverCharacteristics([CBUUID(string: "2A37")], for: service) } } func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { guard let characteristics = service.characteristics else { return } for char in characteristics where char.properties.contains(.notify) { peripheral.setNotifyValue(true, for: char) } } func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { guard let data = characteristic.value else { return } // parse data according to GATT characteristic specification } } 

Android: BluetoothGatt

val gattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { if (status != BluetoothGatt.GATT_SUCCESS) { // status contains error code, e.g., 133 (GATT_ERROR) - needs reconnect gatt.close() return } if (newState == BluetoothProfile.STATE_CONNECTED) { gatt.discoverServices() } } override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { val characteristic = gatt .getService(UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb")) ?.getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb")) ?: return gatt.setCharacteristicNotification(characteristic, true) val descriptor = characteristic.getDescriptor( UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") // Client Characteristic Configuration ) descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE gatt.writeDescriptor(descriptor) } override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) { val data = characteristic.value // parse } } device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE) 

Problems We Solve in Every Project

Problem Solution
didDisconnectPeripheral without warning Auto-reconnect with backoff, restoration identifier (iOS)
Status 133 GATT_ERROR on Android gatt.close(), refresh() via reflection, retry after 2s
Scanning kills battery allowDuplicates: false — enable only when measuring RSSI
State restoration doesn't work Configure CBCentralManagerOptionRestoreIdentifierKey in scheme
Android 12+ permissions Request BLUETOOTH_SCAN and BLUETOOTH_CONNECT dynamically

What's Included in BLE Integration Work

  • Documentation of the device's GATT scheme (services, characteristics, data formats)
  • Implementation of scanning, connection, subscription, reconnection
  • Handling of all normal and emergency states
  • MTU optimization: request 512 bytes instead of 23 for faster transfer
  • Integration with a test device (provided by the client or ours)
  • Unit tests and load testing scenarios (up to 10 simultaneous BLE peripherals)
  • Post-delivery support: 3-month guarantee on connection stability

How We Work: From Analysis to Deployment

  1. Analysis — study device documentation, agree on GATT scheme and data format.
  2. Design — create a state machine, define reconnection policy.
  3. Implementation — write code in Swift/Kotlin using modern frameworks.
  4. Testing — test on simulators, real devices, with interference emulation.
  5. Deployment — publish to TestFlight / Firebase Distribution, assist with App Review (check sections 4.2 and 5.1 of App Store Review Guidelines).

Performance and Battery

Default MTU is 23 bytes. We request via gatt.requestMtu(512) / peripheral.maximumWriteValueLength(for: .withResponse). On large transfers (firmware OTA, sensor data) this is the difference between 30 seconds and 3 minutes. Time savings using our library reach 40%. The financial efficiency of turnkey BLE integration is obvious — you get a ready solution without delving into GATT intricacies.

More about MTU

By default, BLE uses MTU of 23 bytes, of which 3 are overhead. We request 512 bytes, which is 22 times more. For transferring 1 KB of data, this reduces the number of packets from 50 to 3. On devices with limited bandwidth (e.g., fitness bracelets), this saves up to 60% energy.

Timeline and Conditions

Basic integration (one notify service) — 3–5 days. Complex scenarios (OTA, multi-peripheral, background mode) — 1–2 weeks. Cost is calculated individually after analyzing your device. Contact us for a free evaluation of your project. Order BLE integration today — we'll propose implementation options.

We recommend reading the official documentation for CoreBluetooth and Android BluetoothGatt for a more detailed understanding of the API. Learn more about GATT on Wikipedia.