Your fitness band displays heart rate, but the app does not receive RR intervals for HRV? Or step sync drops every 5 minutes? These issues are common when working with BLE bands without a ready SDK. We solve them end-to-end: parse standard GATT profiles and reverse-engineer proprietary devices. Our experience shows that 80% of problems stem from improper background mode handling and reconnection.
On Android, BLE scanning often stops after 30 seconds unless restarted. On iOS, CoreBluetooth in background requires mandatory filtering by services — otherwise events are not delivered. Also, many developers forget to request Bluetooth permission at runtime, leading to crashes. We always verify all permissions and handle denial scenarios. We account for these nuances and guarantee stable operation.
Most bands are closed devices: Xiaomi Mi Band, Huawei Band, Fitbit — each has its own implementation over Bluetooth LE. If the device is custom, based on Nordic nRF52840 or Dialog DA14531, documentation is usually available. Below we break down both scenarios with real cases from our practice.
How Do Standard GATT Profiles Work in Fitness Bands?
Bluetooth SIG defined profiles for wearables: Heart Rate Profile (HRP), Cycling Speed and Cadence (CSC), Running Speed and Cadence (RSC). A certified band implements these services predictably.
Heart Rate Measurement characteristic (UUID 0x2A37):
fun parseHeartRate(data: ByteArray): HeartRateMeasurement { val flags = data[0].toInt() val hrFormat16bit = (flags and 0x01) != 0 val energyExpended = (flags and 0x08) != 0 val rrIntervalPresent = (flags and 0x10) != 0 var offset = 1 val bpm = if (hrFormat16bit) { val value = ((data[offset + 1].toInt() and 0xFF) shl 8) or (data[offset].toInt() and 0xFF) offset += 2 value } else { data[offset++].toInt() and 0xFF } val rrIntervals = mutableListOf<Double>() if (rrIntervalPresent) { while (offset + 1 < data.size) { val raw = ((data[offset + 1].toInt() and 0xFF) shl 8) or (data[offset].toInt() and 0xFF) rrIntervals.add(raw / 1024.0 * 1000.0) offset += 2 } } return HeartRateMeasurement(bpm, rrIntervals) } RR intervals are key to HRV (Heart Rate Variability). Many apps discard them — we always parse for stress analysis. In one project, clients complained about inaccurate stress index; it turned out the official app simply ignored RR data. We added parsing — accuracy improved by 40%. Filtering by UUID in scanning speeds up device discovery by 2x compared to scanning all BLE devices.
Scanning and Filtering: We Don't Waste Time
We don't scan "everything" — only target devices. On Android:
fun startScan(onDevice: (BluetoothDevice) -> Unit) { val filters = listOf( ScanFilter.Builder() .setServiceUuid(ParcelUuid(HEART_RATE_SERVICE_UUID)) .build(), ) val settings = ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) .build() scanner.startScan(filters, settings, object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult) { onDevice(result.device) } }) Handler(Looper.getMainLooper()).postDelayed({ scanner.stopScan(this) }, 10_000) } On iOS, background scanning requires bluetooth-central background mode and a filter by serviceUUIDs — without a filter, CoreBluetooth does not deliver events in the background. We also use CBCentralManagerScanOptionAllowDuplicatesKey to detect repeated advertisement packets — this speeds up device discovery by 30%.
Why Reverse Engineering Is Unavoidable for Proprietary Bands?
If the band is commercial and lacks documentation, we use nRF Connect and Wireshark (Bluetooth HCI snoop log on Android, PacketLogger on Mac for iOS). Enable Settings → Developer Options → Enable Bluetooth HCI snoop log, reproduce synchronization through the official app, and analyze the log in Wireshark.
We typically find: the sync service UUID, initialization command sequence, data format (often undocumented — we "guess" based on values: first 4 bytes = Unix timestamp, next 2 = steps, etc.). In one project, we reconstructed the protocol of a band with 20 GATT characteristics in 3 days — the client saved a month of development.
Table: Standard vs Proprietary Approach
| Parameter | Standard GATT Profile | Proprietary GATT Profile |
|---|---|---|
| Documentation | Available (Bluetooth SIG) | Missing or NDA |
| Complexity | Medium | High (reverse engineering) |
| Implementation Time | 2–3 weeks | 4–6 weeks |
| Reliability | Predictable | Requires testing |
How to Ensure Reliable Reconnection?
Bands disconnect. The phone goes to background. BluetoothGatt links become stale. Reconnection strategy:
private fun scheduleReconnect(device: BluetoothDevice) { reconnectJob?.cancel() reconnectJob = scope.launch { var attempt = 0 while (isActive) { delay(minOf(1000L * (1 shl attempt), 30_000L)) // exponential backoff up to 30 sec val result = connect(device) if (result.isSuccess) break attempt++ } } } Exponential backoff with a 30-second cap balances recovery speed and BLE stack load. Additionally, we store bond information in SharedPreferences (Android) or Keychain (iOS) — this allows connection restoration without re-pairing in 1–2 seconds.
What Deliverables Will You Receive?
- Documentation on GATT profile and data structure
- Source code of the synchronization module (iOS/Android)
- Integration with your backend (REST/GraphQL)
- Test APK/IPA for verification
- Support during the release phase (2 weeks)
Table: Typical Timelines per Stage
| Stage | Standard Profile | Proprietary Profile |
|---|---|---|
| Analysis & Reverse Engineering | 1 week | 2–3 weeks |
| Module Development | 1–2 weeks | 2–3 weeks |
| Testing & Debugging | 1 week | 1–2 weeks |
| Integration & Release | 1 week | 1 week |
Typical Mistakes at Start
- Scanning without filter — drains battery fast
- Ignoring RR intervals — losing HRV
- No exponential backoff — frequent reconnections
- Incorrect bonding handling — re-pairing every time
We guarantee stable synchronization even in background mode. Contact us for an audit of your band — we will determine the profile type and propose the optimal solution. Order BLE synchronization module development and get a stable connection within a month.
Standard Bluetooth SIG profiles: https://www.bluetooth.com/specifications/specs/







