Mobile devices have a lot of various sensors, but often, for additional functionality, they need to communicate with some other devices.
When it comes to Android OS, for instance, a rich Bluetooth API enables wireless communication with other nearby Bluetooth-powered devices.
Now the question arises: Should we use Bluetooth Classic or Bluetooth Low-Energy technology when integrating the Bluetooth API?
Let’s first demystify the two concepts and clearly determine the difference between the two.
Bluetooth Classic vs. BLE (Bluetooth Low Energy)
Bluetooth Classic is intended to support transmitting continuous data streams and battery-intensive operations. It is highly effective for short distances and has high Application throughput (up to 2.1 Mbps).
Bluetooth Low Energy is designed to exchange small packets of data without a large bandwidth and in a broad range (more than 100 meters). It has low power requirements and is optimized for power efficiency. It has only 0.3 Mbps of Application throughput and is more developer-friendly. Essentially, BLE is aimed at novel applications in healthcare, smart homes, wearables, automotive, sports, etc. The implementation of BLE is provided by Android version 4.3 (API 18) and above.
Before diving into how you can set communication flow in an Android app using Bluetooth LE, let us introduce you to the basic concept of BLE and Android BLE API.
What you need to know about BLE & Android BLE AP
BLE support was added to the Android SDK in Android 4.3 (Jelly Bean, API level 18). But with the release of Android 5.0 (Lollipop, API level 21), the Android BLE API got more powerful Bluetooth low-energy capabilities. Therefore, the general recommendation is to set the Android app to target a minimum API level of 21 (Android 5.0) due to more developer-friendly APIs.
In terms of device connectivity via BLE, an Android device has the central role, and an IoT device has the peripheral role to which the Android device connects. An Android device can connect to multiple peripherals, and the peripheral advertises its presence.
Here are a few more relevant terms and concepts you need to know to be able to understand the process more easily:
- Generic Attribute Profile (GATT) is a general specification for sending and receiving short pieces of data known as “attributes” over a BLE link.
- The Bluetooth SIG (Bluetooth Special Interest Group) defines many profiles for BLE devices. A profile specifies how a device works in a particular application.
- Attribute Protocol (ATT) on top of which GATT is built. Each attribute is uniquely identified by a Universally Unique Identifier (UUID), a standardized 128-bit format for a string ID. The attributes transported by ATT are formatted as characteristics and services.
- Characteristic describes a device feature containing a single value and descriptors — an entity containing meaningful data that can typically be read or written.
- Descriptors are defined attributes that describe the characteristic that they are attached to.
- Service is a collection of characteristics.
How to set communication flow in an Android app using BLE technology in a few steps
Step #1: Configure permissions
Android apps require specific runtime permissions from users granted to enable Bluetooth connectivity. The configuration would depend on the Android version that the app is targeting.
- Android 11 and older — they require location permission to be granted. It is also recommended to check whether the location services are turned on.
- Android 12 and new versions — they require new Bluetooth permissions to be granted.
After checking/requesting necessary runtime permissions, it is also necessary to check whether Bluetooth is enabled on the phone. If not, you need to guide the user to the phone settings to enable it to continue with the Bluetooth communication flow.
Step #2: Scan devices
The phone has a central role in Bluetooth communication, so it must initiate the BLE scanning process to discover the nearby devices that advertise their availability for connection.
Before scanning for devices, the app can configure appropriate scan filter options. For example, to adjust the scan interval, define a time interval to be notified about found results, set MAC addresses for searching for specific devices, etc.
The scan results are received containing discovered BluetoothDevice objects. By analyzing the device object properties and identifiers, it can be determined whether there is a device that the app is searching for (e.g., by comparing MAC address, name, UUID, RSSI signal strength).
After the target device is discovered nearby, the app should stop the scan process and proceed with a connection process.
Step #3: Connect to the device
The app must establish a Bluetooth connection to start communicating with the found BLE device.
BLE connection process is often referred to as Bonding or Pairing, but these terms are not the same. The difference is that pairing is the exchange of temporary encryption keys that enable bonding, which is the exchange of long-term encryption keys. The motivation behind creating a bond is to set up an encrypted communication channel between a BLE central and peripheral.
Service discovery is essential after establishing a BLE connection with a device. Through Bluetooth GATT, the Android can access the services and characteristics that are present on the BLE device. That allows the app to explore the device’s capabilities.
When establishing a connection, an Android app as a client can request a preferred ATT MTU (Maximum Transmission Unit), which stands for the maximum length of a data packet. Usually, a final MTU value will differ from the originally requested one because the request must be negotiated between Android and the BLE device.
Another important configuration that can be set upon establishing a connection is a PHY. PHY (Physical Layer) is responsible for transmitting and receiving information over the air via radio waves. The application can choose to request either 1M or 2M PHY (Megabit – Mega symbols per second) to impact the throughput. The final value is negotiated with the BLE device.
Once the connection to the device is established, there are 3 types of operations you can perform on a characteristic:
- Write Command — it can be executed with or without a response acknowledgment by sending a byte array to the specified characteristic.
- Notifications — these are the primary mechanism that allows BLE devices to communicate with the Android device. Upon established connection, the app can enable receiving the notifications and subscribe to receive BLE notifications from a characteristic.
- Read Response — allows the app to obtain information from the BLE device (e.g., battery levels). After executing the read command, the app receives a byte array that contains the appropriate data.
Step #4: Configure communication protocol
It is necessary to have a defined communication protocol to enable clear Bluetooth communication between Android and BLE devices. The BLE binary communication protocol represents an API for data message flow. Therefore, these messages should be in an appropriate, predetermined format, where it is precisely defined which type of value can be found in which position. In addition, most BLE firmware utilizes little-endian byte order, so it is crucial to ensure parsing the bytes in the correct order.
The verification mechanism should be encapsulated within the communication protocol to check that each sent/received message is valid according to the protocol. One of the examples is calculating the checksum on message values and setting it as a part of the message for verification, both on Android and BLE device’s firmware.
To provide a robust scheme for avoiding framing errors, COBS (Consistent Overhead Byte Stuffing) encoding/decoding is often used on message data.
And finally, to secure the message content, the protocol messages may require encryption, especially if an app is communicating with a medical device that deals with sensitive patient data.
An Android app should implement a specific BLE data parser to support such BLE protocol. Also, it is necessary to implement support for sending and receiving messages (commands, responses).
It’s important to keep in mind that the large data packets, which exceed the MTU, might split into multiple smaller chunks causing the application not to parse those chunks. This is why you should consider implementing an appropriate and thread-safe buffering mechanism, queues for incoming messages, and commands that are to be sent.
Step #5: Manage connections
Now that you have successfully connected the device, how do you manage to maintain the connection?
The Android application should provide a central point of access to information regarding the current status of the BLE connection. This point of access should contain some of the following options:
- Status of connection to the BLE device
- Device discovery status
- Options to initiate and stop device discovery
- Options to connect and disconnect from a device
- Options to send and receive BLE messages
- Mechanism to handle connection or communication errors
For dispatching received BLE messages through the Android app layers, it would be helpful to utilize some asynchronous data stream propagation mechanisms like RxJava/RxKotlin or Kotlin Coroutines.
If you need to keep the connection and data flow active, even when the application goes to the background state, it is advisable that you consider the Android system’s background limitations and set up an adequate approach (e.g., by introducing Foreground Services).
BLE library wrappers to the rescue
When developing an Android application that needs to establish a BLE connection with an IoT device and when configuring the communication protocol, it would be helpful to immediately consider whether to use the native Android BLE API or look for a suitable third-party BLE library. Both approaches have their advantages and disadvantages.
The native Android BLE API can be complex to understand and use for developers who have no experience working with Bluetooth APIs. Also, they may experience a steep learning curve which can then result in the occurrence of errors in Bluetooth connection or communication.
But there is a solution to this challenge. There are a few open-source libraries that solve the complexities and help developers avoid the pitfalls of the official Android BLE SDK. One that stands out is Nordic Android BLE Library — a highly recommended and reliable library that we have already used in several projects here in HTEC.