react-native-ble-manager
A React Native Bluetooth Low Energy library.
Originally inspired by https://github.com/don/cordova-plugin-ble-central.
Introduction
The library is a simple connection with the OS APIs, the BLE stack should be standard but often has different behaviors based on the device used, the operating system and the BLE chip it connects to. Before opening an issue verify that the problem is really the library.
Requirements
RN 0.60+
RN 0.40-0.59 supported until 6.7.X
RN 0.30-0.39 supported until 2.4.3
Supported Platforms
Install
npm i --save react-native-ble-manager
The library support the react native autolink feature.
Android - Update Manifest
// file: android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="YOUR_PACKAGE_NAME">
<uses-permission android:name="android.permission.BLUETOOTH" tools:remove="android:maxSdkVersion" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" tools:remove="android:maxSdkVersion" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28"/>
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
...
If you need communication while the app is not in the foreground you need the "ACCESS_BACKGROUND_LOCATION" permission.
iOS - Update Info.plist
In iOS >= 13 you need to add the NSBluetoothAlwaysUsageDescription
string key.
If the deployment target is earlier than iOS 13, you also need to add the NSBluetoothPeripheralUsageDescription
string key.
Note
- Remember to use the
start
method before anything. - If you have problem with old devices try avoid to connect/read/write to a peripheral during scan.
- Android API >= 23 require the ACCESS_COARSE_LOCATION permission to scan for peripherals. React Native >= 0.33 natively support PermissionsAndroid like in the example.
- Android API >= 29 require the ACCESS_FINE_LOCATION permission to scan for peripherals.
React-Native 0.63.X started targeting Android API 29.
- Before write, read or start notification you need to call
retrieveServices
method - Because location and bluetooth permissions are runtime permissions, you must request these permissions at runtime along with declaring them in your manifest.
Example
The easiest way to test is simple make your AppRegistry point to our example component, like this:
import React, { Component } from "react";
import { AppRegistry } from "react-native";
import App from "react-native-ble-manager/example/App";
AppRegistry.registerComponent("MyAwesomeApp", () => App);
Or, use the example directly
Methods
start(options)
Init the module.
Returns a Promise
object.
Don't call this multiple times.
Arguments
The parameter is optional the configuration keys are:
showAlert
- Boolean
- [iOS only] Show or hide the alert if the bluetooth is turned off during initializationrestoreIdentifierKey
- String
- [iOS only] Unique key to use for CoreBluetooth state restorationqueueIdentifierKey
- String
- [iOS only] Unique key to use for a queue identifier on which CoreBluetooth events will be dispatchedforceLegacy
- Boolean
- [Android only] Force to use the LegacyScanManager
Examples
BleManager.start({ showAlert: false }).then(() => {
console.log("Module initialized");
});
scan(serviceUUIDs, seconds, allowDuplicates, scanningOptions)
Scan for available peripherals.
Returns a Promise
object.
Arguments
serviceUUIDs
- Array of String
- the UUIDs of the services to looking for. On Android the filter works only for 5.0 or newer.seconds
- Integer
- the amount of seconds to scan.allowDuplicates
- Boolean
- [iOS only] allow duplicates in device scanningscanningOptions
- JSON
- [Android only] after Android 5.0, user can control specific ble scan behaviors:
numberOfMatches
- Number
- [Android only] corresponding to setNumOfMatches
. Defaults to ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT
. /!\ anything other than default may only work when a ScanFilter
is active /!\matchMode
- Number
- [Android only] corresponding to setMatchMode
. Defaults to ScanSettings.MATCH_MODE_AGGRESSIVE
.callbackType
- Number
- [Android only] corresponding to setCallbackType
. Defaults ScanSettings.CALLBACK_TYPE_ALL_MATCHES
. /!\ anything other than default may only work when a ScanFilter
is active /!\scanMode
- Number
- [Android only] corresponding to setScanMode
. Defaults to ScanSettings.SCAN_MODE_LOW_POWER
.reportDelay
- Number
- [Android only] corresponding to setReportDelay
. Defaults to 0ms
.phy
- Number
- [Android only] corresponding to setPhy
legacy
- Boolean
- [Android only] corresponding to setLegacy
exactAdvertisingName
- string[]
- In Android corresponds to the ScanFilter
deviceName. In ios the filter is done manually before sending the peripheral.
Examples
BleManager.scan([], 5, true).then(() => {
console.log("Scan started");
});
stopScan()
Stop the scanning.
Returns a Promise
object.
Examples
BleManager.stopScan().then(() => {
console.log("Scan stopped");
});
connect(peripheralId, options)
Attempts to connect to a peripheral. In many case if you can't connect you have to scan for the peripheral before.
Returns a Promise
object.
In iOS, attempts to connect to a peripheral do not time out (please see Apple's doc), so you might need to set a timer explicitly if you don't want this behavior.
Arguments
Examples
BleManager.connect("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
.then(() => {
console.log("Connected");
})
.catch((error) => {
console.log(error);
});
disconnect(peripheralId, force)
Disconnect from a peripheral.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral to disconnect.force
- boolean
- [Android only] defaults to true, if true force closes gatt
connection and send the BleManagerDisconnectPeripheral
event immediately to Javascript, else disconnects the
connection and waits for disconnected state
to
close the gatt connection
and then sends the BleManagerDisconnectPeripheral to the
Javascript
Examples
BleManager.disconnect("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
.then(() => {
console.log("Disconnected");
})
.catch((error) => {
console.log(error);
});
enableBluetooth() [Android only]
Create the request to the user to activate the bluetooth.
Returns a Promise
object.
Examples
BleManager.enableBluetooth()
.then(() => {
console.log("The bluetooth is already enabled or the user confirm");
})
.catch((error) => {
console.log("The user refuse to enable bluetooth");
});
checkState()
Force the module to check the state of the native BLE manager and trigger a BleManagerDidUpdateState event.
Resolves to a promise containing the current BleState.
Examples
BleManager.checkState().then((state) =>
console.log(`current BLE state = '${state}'.`)
);
startNotification(peripheralId, serviceUUID, characteristicUUID)
Start the notification on the specified characteristic, you need to call retrieveServices
method before.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUID
- String
- the UUID of the service.characteristicUUID
- String
- the UUID of the characteristic.
Examples
BleManager.startNotification(
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
)
.then(() => {
console.log("Notification started");
})
.catch((error) => {
console.log(error);
});
startNotificationUseBuffer(peripheralId, serviceUUID, characteristicUUID, buffer) [Android only]
Start the notification on the specified characteristic, you need to call retrieveServices
method before. The buffer collect messages until the buffer of messages bytes reaches the limit defined with the buffer
argument and then emit all the collected data. Helpful to reducing the number or js bridge crossings when a characteristic is sending a lot of messages.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUID
- String
- the UUID of the service.characteristicUUID
- String
- the UUID of the characteristic.buffer
- Integer
- the capacity of the buffer (bytes) stored before emitting the data for the characteristic.
Examples
BleManager.startNotification(
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
1234
)
.then(() => {
console.log("Notification started");
})
.catch((error) => {
console.log(error);
});
stopNotification(peripheralId, serviceUUID, characteristicUUID)
Stop the notification on the specified characteristic.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUID
- String
- the UUID of the service.characteristicUUID
- String
- the UUID of the characteristic.
read(peripheralId, serviceUUID, characteristicUUID)
Read the current value of the specified characteristic, you need to call retrieveServices
method before.
Returns a Promise
object that will resolves to an array of plain integers (number[]
) representing a ByteArray
structure.
That array can then be converted to a JS ArrayBuffer
for example using Buffer.from()
thanks to this buffer module.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUID
- String
- the UUID of the service.characteristicUUID
- String
- the UUID of the characteristic.
Examples
BleManager.read(
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
)
.then((readData) => {
console.log("Read: " + readData);
const buffer = Buffer.from(readData);
const sensorData = buffer.readUInt8(1, true);
})
.catch((error) => {
console.log(error);
});
write(peripheralId, serviceUUID, characteristicUUID, data, maxByteSize)
Write with response to the specified characteristic, you need to call retrieveServices
method before.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUID
- String
- the UUID of the service.characteristicUUID
- String
- the UUID of the characteristic.data
- number[]
- the data to write as a plain integer array representing a ByteArray
structure.maxByteSize
- Integer
- specify the max byte size before splitting message, defaults to 20 bytes if not specified
Data preparation
To convert your data to a number[]
, you should probably be manipulating a Buffer
or anything representing a JS ArrayBuffer
.
This will make sure you are converting from valid byte representations of your data first and not with an integer outside the expected range.
You can create a buffer from files, numbers or strings easily (see examples bellow).
import { Buffer } from 'buffer';
*
* const buffer = Buffer.from([1, 2, 3]);
*
*
*
* const buffer = Buffer.from([257, 257.5, -255, '1']);
*
*
*
*
* const buffer = Buffer.from('tést');
Feel free to use other packages or google how to convert into byte array if your data has other format.
Examples
BleManager.write(
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
buffer.toJSON().data
)
.then(() => {
console.log("Write: " + data);
})
.catch((error) => {
console.log(error);
});
writeWithoutResponse(peripheralId, serviceUUID, characteristicUUID, data, maxByteSize, queueSleepTime)
Write without response to the specified characteristic, you need to call retrieveServices
method before.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUID
- String
- the UUID of the service.characteristicUUID
- String
- the UUID of the characteristic.data
- number[]
- the data to write as a plain integer array representing a ByteArray
structure. (see write()
).maxByteSize
- Integer
- (Optional) specify the max byte sizequeueSleepTime
- Integer
- (Optional) specify the wait time before each write if the data is greater than maxByteSize
Data preparation
If your data is not in number[]
format check info fom the write()
function example above.
Example
BleManager.writeWithoutResponse(
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
data
)
.then(() => {
console.log("Writed: " + data);
})
.catch((error) => {
console.log(error);
});
Read the current value of the RSSI.
Returns a Promise
object resolving with the updated RSSI value (number
) if it succeeds.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.
Examples
BleManager.readRSSI("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
.then((rssi) => {
console.log("Current RSSI: " + rssi);
})
.catch((error) => {
console.log(error);
});
readDescriptor(peripheralId, serviceId, characteristicId, descriptorId)
Read the current value of the specified descriptor, you need to call retrieveServices
method before.
Returns a Promise
object that will resolves to an array of plain integers (number[]
) representing a ByteArray
structure.
That array can then be converted to a JS ArrayBuffer
for example using Buffer.from()
thanks to this buffer module.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUID
- String
- the UUID of the service.characteristicUUID
- String
- the UUID of the characteristic.descriptorUUID
- String
- the UUID of the descriptor.
Examples
BleManager.readDescriptor(
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"XXXX"
)
.then((readData) => {
console.log("Read: " + readData);
const buffer = Buffer.from(readData);
const sensorData = buffer.readUInt8(1, true);
})
.catch((error) => {
console.log(error);
});
requestConnectionPriority(peripheralId, connectionPriority) [Android only API 21+]
Request a connection parameter update.
Returns a Promise
object which fulfills with the status of the request.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.connectionPriority
- Integer
- the connection priority to be requested, as follows:
- 0 - balanced priority connection
- 1 - high priority connection
- 2 - low power priority connection
Examples
BleManager.requestConnectionPriority("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 1)
.then((status) => {
console.log("Requested connection priority");
})
.catch((error) => {
console.log(error);
});
requestMTU(peripheralId, mtu) [Android only API 21+]
Request an MTU size used for a given connection.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.mtu
- Integer
- the MTU size to be requested in bytes.
Examples
BleManager.requestMTU("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 512)
.then((mtu) => {
console.log("MTU size changed to " + mtu + " bytes");
})
.catch((error) => {
console.log(error);
});
retrieveServices(peripheralId[, serviceUUIDs])
Retrieve the peripheral's services and characteristics.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.serviceUUIDs
- String[]
- [iOS only] only retrieve these services.
Examples
BleManager.retrieveServices("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX").then(
(peripheralInfo) => {
console.log("Peripheral info:", peripheralInfo);
}
);
refreshCache(peripheralId) [Android only]
refreshes the peripheral's services and characteristics cache
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.
Examples
BleManager.refreshCache("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
.then((peripheralInfo) => {
console.log("cache refreshed!");
})
.catch((error) => {
console.error(error);
});
getConnectedPeripherals(serviceUUIDs)
Return the connected peripherals.
Returns a Promise
object.
Arguments
serviceUUIDs
- Array of String
- the UUIDs of the services to looking for.
Examples
BleManager.getConnectedPeripherals([]).then((peripheralsArray) => {
console.log("Connected peripherals: " + peripheralsArray.length);
});
createBond(peripheralId,peripheralPin) [Android only]
Start the bonding (pairing) process with the remote device. If you pass peripheralPin(optional), bonding will be auto(without manual entering pin)
Returns a Promise
object that will resolves if the bond is successfully created, otherwise it will be rejected with the appropriate error message.
Examples
BleManager.createBond(peripheralId)
.then(() => {
console.log("createBond success or there is already an existing one");
})
.catch(() => {
console.log("fail to bond");
});
removeBond(peripheralId) [Android only]
Remove a paired device.
Returns a Promise
object.
Examples
BleManager.removeBond(peripheralId)
.then(() => {
console.log("removeBond success");
})
.catch(() => {
console.log("fail to remove the bond");
});
getBondedPeripherals() [Android only]
Return the bonded peripherals.
Returns a Promise
object.
Examples
BleManager.getBondedPeripherals([]).then((bondedPeripheralsArray) => {
console.log("Bonded peripherals: " + bondedPeripheralsArray.length);
});
getDiscoveredPeripherals()
Return the discovered peripherals after a scan.
Returns a Promise
object.
Examples
BleManager.getDiscoveredPeripherals([]).then((peripheralsArray) => {
console.log("Discovered peripherals: " + peripheralsArray.length);
});
removePeripheral(peripheralId) [Android only]
Removes a disconnected peripheral from the cached list.
It is useful if the device is turned off, because it will be re-discovered upon turning on again.
Returns a Promise
object.
Arguments
peripheralId
- String
- the id/mac address of the peripheral.
isPeripheralConnected(peripheralId, serviceUUIDs)
Check whether a specific peripheral is connected and return true
or false
.
Returns a Promise
object.
Examples
BleManager.isPeripheralConnected(
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
[]
).then((isConnected) => {
if (isConnected) {
console.log("Peripheral is connected!");
} else {
console.log("Peripheral is NOT connected!");
}
});
setName(name) [Android only]
Create the request to set the name of the bluetooth adapter. (https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#setName(java.lang.String))
Returns a Promise
object.
Examples
BleManager.setName("INNOVEIT_CENTRAL")
.then(() => {
console.log("Name set successfully");
})
.catch((error) => {
console.log("Name could not be set");
});
getMaximumWriteValueLengthForWithoutResponse(peripheralId) [iOS only]
Return the maximum value length for WriteWithoutResponse.
Returns a Promise
object.
Examples
BleManager.getMaximumWriteValueLengthForWithoutResponse("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX").then((maxValue) => {
console.log("Maximum length for WriteWithoutResponse: " + maxValue);
});
getMaximumWriteValueLengthForWitResponse(peripheralId) [iOS only]
Return the maximum value length for WriteWithResponse.
Returns a Promise
object.
Examples
BleManager.getMaximumWriteValueLengthForWitResponse("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX").then((maxValue) => {
console.log("Maximum length for WriteWithResponse: " + maxValue);
});
Events
BleManagerStopScan
The scanning for peripherals is ended.
Arguments
Examples
bleManagerEmitter.addListener("BleManagerStopScan", (args) => {
});
BleManagerDidUpdateState
The BLE change state.
Arguments
state
- String
- the new BLE state. can be one of unknown
(iOS only), resetting
(iOS only), unsupported
, unauthorized
(iOS only), on
, off
, turning_on
(android only), turning_off
(android only).
Examples
bleManagerEmitter.addListener("BleManagerDidUpdateState", (args) => {
});
BleManagerDiscoverPeripheral
The scanning find a new peripheral.
Arguments
id
- String
- the id of the peripheralname
- String
- the name of the peripheralrssi
- Number
- the RSSI valueadvertising
- JSON
- the advertising payload, here are some examples:
isConnectable
- Boolean
serviceUUIDs
- Array of String
manufacturerData
- JSON
- contains a json with the company id as field and the custom value as raw bytes
and data
(Base64 encoded string)serviceData
- JSON
- contains the raw bytes
and data
(Base64 encoded string)txPowerLevel
- Int
rawData
- [Android only] JSON
- contains the raw bytes
and data
(Base64 encoded string) of the all advertising data
Examples
bleManagerEmitter.addListener("BleManagerDiscoverPeripheral", (args) => {
});
BleManagerDidUpdateValueForCharacteristic
A characteristic notify a new value.
Arguments
value
— Array
— the read valueperipheral
— String
— the id of the peripheralcharacteristic
— String
— the UUID of the characteristicservice
— String
— the UUID of the characteristic
Event will only be emitted after successful startNotification
.
Example
import { bytesToString } from "convert-string";
import { NativeModules, NativeEventEmitter } from "react-native";
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
async function connectAndPrepare(peripheral, service, characteristic) {
await BleManager.connect(peripheral);
await BleManager.retrieveServices(peripheral);
await BleManager.startNotification(peripheral, service, characteristic);
bleManagerEmitter.addListener(
"BleManagerDidUpdateValueForCharacteristic",
({ value, peripheral, characteristic, service }) => {
const data = bytesToString(value);
console.log(`Received ${data} for characteristic ${characteristic}`);
}
);
}
BleManagerConnectPeripheral
A peripheral was connected.
Arguments
peripheral
- String
- the id of the peripheralstatus
- Number
- [Android only] connect reasons
BleManagerDisconnectPeripheral
A peripheral was disconnected.
Arguments
BleManagerPeripheralDidBond
A bond with a peripheral was established
Arguments
Object with information about the device
BleManagerCentralManagerWillRestoreState [iOS only]
This is fired when centralManager:WillRestoreState:
is called (app relaunched in the background to handle a bluetooth event).
Arguments
peripherals
- Array
- an array of previously connected peripherals.
For more on performing long-term bluetooth actions in the background:
iOS Bluetooth State Preservation and Restoration
iOS Relaunch Conditions
BleManagerDidUpdateNotificationStateFor [iOS only]
The peripheral received a request to start or stop providing notifications for a specified characteristic's value.
Arguments
peripheral
- String
- the id of the peripheralcharacteristic
- String
- the UUID of the characteristicisNotifying
- Boolean
- Is the characteristic notifying or notdomain
- String
- [iOS only] error domaincode
- Number
- [iOS only] error code
Library development
- the library is written in typescript and needs to be built before being used for publication or local development, using the provided npm scripts in
package.json
. - the local
example
project is configured to work with the locally built version of the library. To be able to run it, you need to build at least once the library so that its outputs listed as entrypoint in package.json
(in the dist
folder) are properly generated for consumption by the example project:
from the root folder:
npm install
npm run build
if you are modifying the typescript files of the library (in src/
) on the fly, you can run npm run watch
instead. If you are modifying files from the native counterparts, you'll need to rebuild the whole app for your target environnement (npm run android/ios
).