Android BLE Library
repository·main·Indexed 25 days ago
https://github.com/nordicsemi/android-ble-libraryAn Android library by Nordic Semiconductor designed to simplify Bluetooth Low Energy (BLE) development. It provides connection management, service discovery, data packet splitting/merging, and GATT server support via the BleManager class. The library includes modules for Kotlin Coroutines and Flow (:ble-ktx), LiveData integration (:ble-livedata), and pre-built Bluetooth SIG profile parsers (:ble-common). Note that it does not provide device scanning functionality.
What's inside android-ble-library
- The Android BLE Common Library is an add-on to the main Android BLE Library. It provides pre-built data parsers for various Bluetooth SIG adopted profiles. Instead of manually parsing raw byte arrays from GATT characteristics, you can use these specialized parsers to receive structured, type-safe data. It is compatible with the Android BLE Library starting from version 2.0.
Core features of BleManager
mainThe
BleManagerclass is the primary entry point for BLE operations and provides:- Connection Management: Automatic retries, connection timeouts, and disconnection timeouts.
- Service & Bonding: Service discovery, optional bonding, and removing bond information.
- Data Handling: Splitting/merging long packets, Reliable Write support, and MTU/connection priority requests.
- Advanced BLE: GATT server support (since v2.2), preferred PHY reading/setting (Android Oreo+), and RSSI reading.
- Lifecycle & Error Handling: Automatic handling of Service Changed indications, operation timeouts, error handling, and logging.
- Kotlin Support: Coroutines and
Flowsupport (since v2.3).
Important: This library does not provide scanning functionality. It is recommended to use the Android Scanner Compat Library for device scanning.
Key features of BleManager
mainThe
BleManagerclass is the primary entry point for BLE operations and provides:- Connection Management: Automatic retries and connection timeouts.
- Service & Discovery: Service discovery and automatic handling of Service Changed indications.
- Bonding: Optional bonding and removal of bond information.
- Data Handling: Splitting/merging long packets for reads/writes, and Reliable Write support.
- Advanced BLE Config: Requesting MTU, connection priority, and preferred PHY.
- GATT Server: Support for running a local GATT server (since v2.2).
- Modern Tooling: Kotlin support (coroutines,
Flow) and error handling/logging.
Important Limitation: The library does not provide scanning for Bluetooth LE devices. It is recommended to use the Android Scanner Compat Library for device discovery.
How to implement a BleManager
mainTo use the library, you must extend
BleManagerto define your device's high-level API. ABleManagerinstance is responsible for a single Bluetooth LE peripheral. While you can reuse an instance for a new peripheral after disconnection, it is recommended to create a new instance for each device.You must implement the following three methods:
isRequiredServiceSupported(BluetoothGatt gatt): Searchgatt.getServices()for required services and characteristics. Returntrueonly if all required services and characteristics are found. Use this method to acquire and store references to yourBluetoothGattCharacteristicobjects.onServicesInvalidated(): Called when the device disconnects or services become invalid. Use this to nullify your stored characteristic references.initialize(): (Optional) Perform device setup, such as enabling notifications or writing initial values. Enqueued operations in this method will complete beforeonDeviceReady()is called and before theConnectRequest'sdonecallback triggers.
Additionally, you should implement your own high-level public methods (e.g.,
turnLedOn()) that wrap low-level BLE operations likewriteCharacteristic.class MyBleManager extends BleManager { private BluetoothGattCharacteristic fluxCapacitorControlPoint; @Override protected boolean isRequiredServiceSupported(@NonNull BluetoothGatt gatt) { BluetoothGattService fluxCapacitorService = gatt.getService(FLUX_SERVICE_UUID); if (fluxCapacitorService != null) { fluxCapacitorControlPoint = fluxCapacitorService.getCharacteristic(FLUX_CHAR_UUID); } return fluxCapacitorControlPoint != null; } @Override protected void initialize() { requestMtu(517).enqueue(); } @Override protected void onServicesInvalidated() { fluxCapacitorControlPoint = null; } public void enableFluxCapacitor() { writeCharacteristic(fluxCapacitorControlPoint, Flux.enable(), BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) .enqueue(); } }Implement Client-Server BLE interaction
mainThe Trivia example demonstrates a client-server architecture using the Android BLE Library.
- Server Role: Use a
BleServerManagerto open the GATT server and initialize services. The server advertises services using a randomly generated service UUID to make them discoverable by remote devices. - Client Role: The client scans for advertising devices matching the specific service UUID and connects to the first one discovered. A
BleManagerinstance is used to manage the connection and handle communication with the peripheral.
Data is exchanged between the client and server using Protocol Buffers (Protobuf) for efficient transmission.
- Server Role: Use a
Use GATT Server in the BLE Library
mainSince version 2.2, the library supports implementing a local GATT server on the Android device. This allows the device to act as a peripheral.
Key server-side operations include:
- wait for read
- wait for write
- send notification
- send indication
- set characteristic value
- set descriptor value
To use a device as a server-only implementation, call
attachClientConnection(BluetoothDevice)instead ofconnect(BluetoothDevice).Use Kotlin Coroutines and Flow with BLE
mainThe
:ble-ktxmodule provides extensions for modern asynchronous programming in Kotlin.Using Coroutines: When using coroutines, use the
.suspend()method on aRequestinstead ofenqueue()orawait().Using Flows for Notifications: You can register for notifications or indications and convert them into a
Flow. You can also useJsonMergerto handle data sent in multiple packets.setNotificationCallback(characteristic) .merge(JsonMerger()) // Optional: merges multi-packet JSON .asFlow()Other Flow features:
.stateAsFlow()and.bondingStateAsFlow()inBleManagerreturn flows for connection and bond states.- Progress for split/merged data can be observed via
splitWithProgressFlow(...)andmergeWithProgressFlow(...). ValueChangedCallbackcan be converted to a flow using.asResponseFlow()or.asValidResponseFlow()(v2.4+).
setNotificationCallback(characteristic) .merge(JsonMerger()) // Example of how to use JsonMerger, optional .asFlow()Migrate from version 1.x to 2.x
mainWhen upgrading to version 2.0 or higher, several core architectural changes require updates to your
BleManagerimplementation:- Initialization: Replace
initGatt(BluetoothGatt)withinitialize(). Instead of returning aDeque<Request>, useinitialize()to set up callbacks and call.enqueue()on your initialization requests. - Request-based API: BLE operation methods (e.g.,
writeCharacteristic(...)) now return aRequestobject instead of aboolean. Use theseRequestobjects and their callbacks instead of the deprecatedBleManagerGattCallbackGATT callbacks. - Connection Configuration: Replace
shouldAutoConnect()with.useAutoConnect(boolean)on theConnectRequestobject. - Asynchronous Operations: For
connect()anddisconnect()methods, you must call.enqueue()when using them asynchronously. - Callback Renaming:
onLinklossOccuris renamed toonLinkLossOccurred.
// Old code (1.x) @Override protected Deque<Request> initGatt(final BluetoothGatt gatt) { final LinkedList<Request> requests = new LinkedList<>(); requests.add(Request.newEnableNotificationsRequest(characteristic)); return requests; } // New code (2.x) @Override protected void initialize() { setNotificationCallback(characteristic) .with(new DataReceivedCallback() { @Override public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { ... } }); enableNotifications(characteristic) .enqueue(); }- Initialization: Replace
Migrate from version 2.1 to 2.2
mainIn version 2.2,
BleManageris no longer a generic class. This change affects how you handle connection and bonding states.Quick Migration (using deprecated API)
To transition quickly, change your base class to
LegacyBleManager. You must ensuregetGattCallback()returns a new object rather than a class property to avoid null pointer issues during construction:class MyBleManager extends LegacyBleManager<MyBleManagerCallbacks> { @NonNull @Override protected BleManagerGattCallback getGattCallback() { return new MyBleManagerGattCallback(); } }Proper Migration
- Remove Generics: Remove the type parameter from your
BleManagerimplementation class. - Replace Callbacks:
- Use
setConnectionObserver(observer)for connection state updates (replacessetGattCallbacks). - Use
setBondingObserver(observer)for bonding events. - Manage application-level callbacks manually within your manager.
- Use
- Connection Observer Mapping:
onServicesDiscoveredis removed.onLinkLossOccurred$\rightarrow$onDeviceDisconnectedwithConnectionObserver#REASON_LINK_LOSS.onDeviceNotSupported$\rightarrow$onDeviceDisconnectedwithConnectionObserver#REASON_NOT_SUPPORTED.
- LiveData Integration: For easier state management, extend
ObservableBleManagerand useno.nordicsemi.android:ble-livedatato accessgetState()andgetBondingState()asLiveDataobjects.
class MyBleManager extends LegacyBleManager<MyBleManagerCallbacks> { // [...] @NonNull @Override protected BleManagerGattCallback getGattCallback() { // Before 2.2 it was allowed to return a class property here, but properties are initiated // after the constructor, so they would still be null here. Instead, create a new object: return new MyBleManagerGattCallback(); } // [...] }- Remove Generics: Remove the type parameter from your
Requirements for the Trivia example
mainTo run the Trivia example application, ensure the following requirements are met:
- Library: The application depends on the Android BLE Library.
- OS Version: Android 4.3 or newer is required.
Install the Android BLE Library via Maven Central
mainTo use the Android BLE Library, add the following dependency to your
build.gradlefile. The library is available on Maven Central.Core Library:
implementation 'no.nordicsemi.android:ble:2.11.0'Kotlin Extensions (Coroutines & Flow): If you are using Kotlin and want support for coroutines and
Flow, add the:ble-ktxmodule:implementation 'no.nordicsemi.android:ble-ktx:2.11.0'Common Bluetooth SIG Parsers: To include a set of parsers for common Bluetooth SIG characteristics, add:
implementation 'no.nordicsemi.android:ble-common:2.11.0'LiveData Integration: To use
ObservableBleManagerwhich providesstateandbondingStateproperties asandroidx.lifecycle.LiveData, add:implementation 'no.nordicsemi.android:ble-livedata:2.11.0'Note on Versions:
- The last version not migrated to AndroidX is
2.0.5. - Version 1.x is no longer supported; migrate to 2.x.
implementation 'no.nordicsemi.android:ble:2.11.0'- The last version not migrated to AndroidX is
Configure required permissions for BLE and Internet
mainTo run applications like the Trivia example, you must handle the following permissions:
Bluetooth and Location
- Android 6 to 11: You must request
Location Permissionand ensureLocation servicesare enabled to obtain BLE scan and advertising results. - Android 12 and newer: New Bluetooth permissions are used. You can request
BLUETOOTH_SCANwith theusesPermissionFlags="neverForLocation"parameter, which allows you to perform scans without requiring location permissions (provided you do not use scan results for location-related data).
Internet
- Internet Access: Required if the application needs to fetch data from external web APIs (e.g., the Trivia API).
- Android 6 to 11: You must request