Mobile Development 13 min read

Mastering BLE on Mobile: From Basics to Advanced Data Handling

This article explains Bluetooth Low Energy fundamentals, compares classic and BLE, describes BLE mesh networking, provides a complete bleno example for peripheral simulation, and details advertising, scanning, connection flow, MTU negotiation, fragmentation, and sticky‑packet handling on Android and iOS.

Goodme Frontend Team
Goodme Frontend Team
Goodme Frontend Team
Mastering BLE on Mobile: From Basics to Advanced Data Handling

Background

Bluetooth was first released in 1998, but its true IoT adoption began with the fourth‑generation Bluetooth 4.0+ BLE standard in 2010. iPhone 4S was the first smartphone supporting Bluetooth 4.0, and Android 4.3 (API 18) introduced a BLE API for developers. BLE is widely used in wearables, smart scales, door locks, etc., while classic Bluetooth is used for audio streaming. This article focuses on BLE characteristics and mobile‑side development considerations.

What Is Low‑Power Bluetooth?

BLE consumes far less power and cost than classic Bluetooth, making it ideal for IoT devices. Classic Bluetooth offers higher data rates (up to 3 Mbps) and requires pairing, whereas BLE can operate without pairing and typically transmits around 1 Mbps in intermittent bursts.

Bluetooth Mesh Network

A Bluetooth mesh (micro‑network) consists of one master device and up to seven slaves. Any device can act as master or slave, but a device cannot be both simultaneously. The master synchronises clocks and initiates connections; slaves respond to the master’s commands.

Communication between master and slaves follows a client‑server model: the master can poll slaves or receive notifications from them.

Example with bleno

The bleno library can simulate a BLE peripheral on Windows, Linux, or macOS. The following code creates a broadcast name "bill", defines a service UUID, a characteristic that supports read and write, and starts advertising when the Bluetooth adapter is powered on.

const name = 'bill'; // broadcast device name
const serviceUuids = ['fffffffffffffffffffffffffffffff0']; // broadcast service UUID

bleno.on('stateChange', (state) => {
  if (state === 'poweredOn') {
    bleno.startAdvertising(name, serviceUuids);
    const characteristic = new Characteristic({
      uuid: 'fffffffffffffffffffffffffffffff2',
      properties: ['read', 'write'],
      descriptors: [
        new Descriptor({ uuid: '2901', value: 'This is a test characteristic' })
      ]
    });
    const service = new PrimaryService({
      uuid: 'fffffffffffffffffffffffffffffff1',
      characteristics: [characteristic]
    });
    bleno.setServices([service]);
  }
});

To add read/write handling:

bleno.on('stateChange', (state) => {
  if (state === 'poweredOn') {
    bleno.startAdvertising(name, serviceUuids);
    const characteristic = new Characteristic({
      uuid: 'fffffffffffffffffffffffffffffff2',
      properties: ['read', 'write'],
      descriptors: [
        new Descriptor({ uuid: '2901', value: 'This is a test characteristic' })
      ],
      onWriteRequest: (data, offset, withoutResponse, callback) => {
        console.log('onWriteRequest:', data.toString('hex'));
        callback(Characteristic.RESULT_SUCCESS);
      },
      onReadRequest: (offset, callback) => {
        callback(Characteristic.RESULT_SUCCESS, Buffer.from('Hello, bill!', 'utf8'));
      }
    });
    const service = new PrimaryService({
      uuid: 'fffffffffffffffffffffffffffffff1',
      characteristics: [characteristic]
    });
    bleno.setServices([service]);
  }
});

Bluetooth Connection

Advertising

The peripheral must be in a "discoverable" state, broadcasting packets that contain device features such as the name. Each advertising packet is limited to 31 bytes and is transmitted on three advertising channels.

Scanning

The scanner (e.g., a phone) receives these packets and can initiate a connection when it finds a matching device. Android requires location services to be enabled for BLE scanning.

Connection Process

After a successful connection, the devices negotiate MTU, discover services and characteristics, and the central (master) subscribes to characteristic changes. The peripheral stops advertising once connected.

Data Packets and MTU

After connection, the devices negotiate the Maximum Transmission Unit (MTU). BLE 4.2 and later support up to 244 bytes per packet, while earlier versions cap MTU at 23 bytes (20 bytes payload after ATT header).

iOS devices (e.g., iPhone 14) automatically negotiate a large MTU (up to 512 bytes), whereas Android often defaults to 23 bytes unless the app explicitly requests a larger MTU. Some mini‑program platforms (e.g., DingTalk) do not expose MTU APIs, forcing developers to rely on the underlying BLE fragmentation.

Fragmentation and Sticky Packets

If a payload exceeds the negotiated MTU, the BLE stack splits it into multiple packets. On Android, a 27‑byte payload (e.g., "123456789126456789123456789") is fragmented into two packets, causing a time gap between arrivals. This can lead to "sticky packet" problems where multiple frames merge.

Typical solutions include:

Using a fixed header or footer to delimit frames.

Defining a constant message length.

Reading a length field defined by the protocol.

Summary

Android requires location permission for BLE scanning, and its default MTU payload is 20 bytes; therefore, protocols should support at least 20‑byte packets for maximum compatibility. iOS automatically negotiates a larger MTU. When developing for platforms that lack MTU APIs (e.g., DingTalk mini‑programs), developers must handle BLE’s built‑in fragmentation and implement sticky‑packet mitigation strategies.

mobile developmentiOSAndroidMTUBLEBlenoBluetooth Low Energy
Goodme Frontend Team
Written by

Goodme Frontend Team

Regularly sharing the team's insights and expertise in the frontend field

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.