
Research
Security News
Lazarus Strikes npm Again with New Wave of Malicious Packages
The Socket Research Team has discovered six new malicious npm packages linked to North Korea’s Lazarus Group, designed to steal credentials and deploy backdoors.
@capacitor-community/bluetooth-le
Advanced tools
@capacitor-community/bluetooth-le
Capacitor Bluetooth Low Energy Plugin
Maintainer | GitHub | Social |
---|---|---|
Patrick Wespi | pwespi |
This is a Capacitor plugin for Bluetooth Low Energy. It supports the web, Android and iOS.
The goal is to support the same features on all platforms. Therefore the Web Bluetooth API is taken as a guidline for what features to implement.
Below is an index of all the methods available.
initialize()
requestDevice(...)
connect(...)
disconnect(...)
read(...)
write(...)
startNotifications(...)
stopNotifications(...)
npm install @capacitor-community/bluetooth-le
npx cap sync
On iOS, add the NSBluetoothAlwaysUsageDescription
to Info.plist
, otherwise the app will crash when trying to use Bluetooth (see here).
If the app needs to use Bluetooth while it is in the background, you also have to add bluetooth-central
to UIBackgroundModes
(for details see here).
./ios/App/App/Info.plist
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
...
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Uses Bluetooth to connect and interact with peripheral BLE devices.</string>
+ <key>UIBackgroundModes</key>
+ <array>
+ <string>bluetooth-central</string>
+ </array>
</dict>
</plist>
On Android, register the plugin in your main activity:
./android/app/src/main/java/<PATH>/MainActivity.java
:
+ import com.capacitorjs.community.plugins.bluetoothle.BluetoothLe;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initializes the Bridge
this.init(
savedInstanceState,
new ArrayList<Class<? extends Plugin>>() {
{
// Additional plugins you've installed go here
// Ex: add(TotallyAwesomePlugin.class);
+ add(BluetoothLe.class);
}
}
);
}
}
You can configure the strings that are displayed in the device selection dialog on iOS and Android:
./capacitor.config.json
:
{
"...": "other configuration",
"plugins": {
"BluetoothLe": {
"displayStrings": {
"scanning": "Am Scannen...",
"cancel": "Abbrechen",
"availableDevices": "Verfügbare Geräte",
"noDeviceFound": "Kein Gerät gefunden"
}
}
}
}
The default values are:
{
"plugins": {
"BluetoothLe": {
"displayStrings": {
"scanning": "Scanning...",
"cancel": "Cancel",
"availableDevices": "Available devices",
"noDeviceFound": "No device found"
}
}
}
}
It is recommended to not use the plugin class directly. There is a wrapper class BleClient
which makes events and method arguments easier to work with.
// Import the wrapper class directly
import { BleClient } from '@capacitor-community/bluetooth-le';
// DO NOT use this
import { Plugins } from '@capacitor/core';
const { BluetoothLe } = Plugins;
Here is an example of how to use the plugin. It shows how to read the heart rate from a BLE heart rate monitor such as the Polar H10.
import {
BleClient,
numbersToDataView,
numberToUUID,
} from '@capacitor-community/bluetooth-le';
const HEART_RATE_SERVICE = '0000180d-0000-1000-8000-00805f9b34fb';
const HEART_RATE_MEASUREMENT_CHARACTERISTIC =
'00002a37-0000-1000-8000-00805f9b34fb';
const BODY_SENSOR_LOCATION_CHARACTERISTIC =
'00002a38-0000-1000-8000-00805f9b34fb';
const BATTERY_SERVICE = numberToUUID(0x180f);
const BATTERY_CHARACTERISTIC = numberToUUID(0x2a19);
const POLAR_PMD_SERVICE = 'fb005c80-02e7-f387-1cad-8acd2d8df0c8';
const POLAR_PMD_CONTROL_POINT = 'fb005c81-02e7-f387-1cad-8acd2d8df0c8';
export async function main() {
try {
await BleClient.initialize();
const device = await BleClient.requestDevice({
services: [HEART_RATE_SERVICE],
optionalServices: [BATTERY_SERVICE],
});
await BleClient.connect(device.deviceId);
console.log('connected to device', device);
const result = await BleClient.read(
device.deviceId,
HEART_RATE_SERVICE,
BODY_SENSOR_LOCATION_CHARACTERISTIC,
);
console.log('body sensor location', result.getUint8(0));
const battery = await BleClient.read(
device.deviceId,
BATTERY_SERVICE,
BATTERY_CHARACTERISTIC,
);
console.log('battery level', battery.getUint8(0));
await BleClient.write(
device.deviceId,
POLAR_PMD_SERVICE,
POLAR_PMD_CONTROL_POINT,
numbersToDataView([1, 0]),
);
console.log('written [1, 0] to control point');
await BleClient.startNotifications(
device.deviceId,
HEART_RATE_SERVICE,
HEART_RATE_MEASUREMENT_CHARACTERISTIC,
value => {
console.log('current heart rate', parseHeartRate(value));
},
);
setTimeout(async () => {
await BleClient.stopNotifications(
device.deviceId,
HEART_RATE_SERVICE,
HEART_RATE_MEASUREMENT_CHARACTERISTIC,
);
await BleClient.disconnect(device.deviceId);
console.log('disconnected from device', device);
}, 10000);
} catch (error) {
console.error(error);
}
}
function parseHeartRate(value: DataView): number {
const flags = value.getUint8(0);
const rate16Bits = flags & 0x1;
let heartRate: number;
if (rate16Bits) {
heartRate = value.getUint16(1, true);
} else {
heartRate = value.getUint8(1);
}
return heartRate;
}
For a full app example, see the ./example
folder of this repository.
initialize() => Promise<void>
Initialize Bluetooth Low Energy (BLE). If it fails, BLE might be unavailable or disabled on this device. On Android it will ask for the location permission. On iOS it will ask for the Bluetooth permission. For an example, see usage.
requestDevice(options?: RequestBleDeviceOptions | undefined) => Promise<BleDevice>
Request a peripheral BLE device to interact with. This will scan for available devices according to the filters provided in the options and show a dialog to pick a device. For an example, see usage.
Param | Type | Description |
---|---|---|
options | RequestBleDeviceOptions | Device filters, see RequestBleDeviceOptions |
Returns: Promise<BleDevice>
connect(deviceId: string) => Promise<void>
Connect to a peripheral BLE device. For an example, see usage.
Param | Type | Description |
---|---|---|
deviceId | string | The ID of the device to use (obtained from requestDevice) |
disconnect(deviceId: string) => Promise<void>
Disconnect from a peripheral BLE device. For an example, see usage.
Param | Type | Description |
---|---|---|
deviceId | string | The ID of the device to use (obtained from requestDevice) |
read(deviceId: string, service: string, characteristic: string) => Promise<DataView>
Read the value of a characteristic. For an example, see usage.
Param | Type | Description |
---|---|---|
deviceId | string | The ID of the device to use (obtained from requestDevice) |
service | string | UUID of the service (see UUID format) |
characteristic | string | UUID of the characteristic (see UUID format) |
Returns: Promise<DataView>
write(deviceId: string, service: string, characteristic: string, value: DataView) => Promise<void>
Write a value to a characteristic. For an example, see usage.
Param | Type | Description |
---|---|---|
deviceId | string | The ID of the device to use (obtained from requestDevice) |
service | string | UUID of the service (see UUID format) |
characteristic | string | UUID of the characteristic (see UUID format) |
value | DataView | The value to write as a DataView. To create a DataView from an array of numbers, there is a helper function, e.g. numbersToDataView([1, 0]) |
startNotifications(deviceId: string, service: string, characteristic: string, callback: (value: DataView) => void) => Promise<void>
Start listening to changes of the value of a characteristic. For an example, see usage.
Param | Type | Description |
---|---|---|
deviceId | string | The ID of the device to use (obtained from requestDevice) |
service | string | UUID of the service (see UUID format) |
characteristic | string | UUID of the characteristic (see UUID format) |
callback | (value: DataView) => void | Callback function to use when the value of the characteristic changes |
stopNotifications(deviceId: string, service: string, characteristic: string) => Promise<void>
Stop listening to the changes of the value of a characteristic. For an example, see usage.
Param | Type | Description |
---|---|---|
deviceId | string | The ID of the device to use (obtained from requestDevice) |
service | string | UUID of the service (see UUID format) |
characteristic | string | UUID of the characteristic (see UUID format) |
Prop | Type | Description |
---|---|---|
deviceId | string | ID of the device, which will be needed for further calls. On Android this is the BLE MAC address. On iOS and web it is an identifier. |
name | string | Name of the device. |
uuids | string[] |
Prop | Type | Description |
---|---|---|
services | string[] | Filter devices by service UUIDs. UUIDs have to be specified as 128 bit UUID strings in lowercase, e.g. ['0000180d-0000-1000-8000-00805f9b34fb'] There is a helper function to convert numbers to UUIDs. e.g. [numberToUUID(0x180f)]. (see UUID format) |
name | string | Filter devices by name |
optionalServices | string[] | For web, all services that will be used have to be listed under services or optionalServices, e.g. [numberToUUID(0x180f)] (see UUID format) |
Prop | Type |
---|---|
buffer | ArrayBuffer |
byteLength | number |
byteOffset | number |
Method | Signature | Description |
---|---|---|
getFloat32 | (byteOffset: number, littleEndian?: boolean | undefined) => number | Gets the Float32 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
getFloat64 | (byteOffset: number, littleEndian?: boolean | undefined) => number | Gets the Float64 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
getInt8 | (byteOffset: number) => number | Gets the Int8 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
getInt16 | (byteOffset: number, littleEndian?: boolean | undefined) => number | Gets the Int16 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
getInt32 | (byteOffset: number, littleEndian?: boolean | undefined) => number | Gets the Int32 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
getUint8 | (byteOffset: number) => number | Gets the Uint8 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
getUint16 | (byteOffset: number, littleEndian?: boolean | undefined) => number | Gets the Uint16 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
getUint32 | (byteOffset: number, littleEndian?: boolean | undefined) => number | Gets the Uint32 value at the specified byte offset from the start of the view. There is no alignment constraint; multi-byte values may be fetched from any offset. |
setFloat32 | (byteOffset: number, value: number, littleEndian?: boolean | undefined) => void | Stores an Float32 value at the specified byte offset from the start of the view. |
setFloat64 | (byteOffset: number, value: number, littleEndian?: boolean | undefined) => void | Stores an Float64 value at the specified byte offset from the start of the view. |
setInt8 | (byteOffset: number, value: number) => void | Stores an Int8 value at the specified byte offset from the start of the view. |
setInt16 | (byteOffset: number, value: number, littleEndian?: boolean | undefined) => void | Stores an Int16 value at the specified byte offset from the start of the view. |
setInt32 | (byteOffset: number, value: number, littleEndian?: boolean | undefined) => void | Stores an Int32 value at the specified byte offset from the start of the view. |
setUint8 | (byteOffset: number, value: number) => void | Stores an Uint8 value at the specified byte offset from the start of the view. |
setUint16 | (byteOffset: number, value: number, littleEndian?: boolean | undefined) => void | Stores an Uint16 value at the specified byte offset from the start of the view. |
setUint32 | (byteOffset: number, value: number, littleEndian?: boolean | undefined) => void | Stores an Uint32 value at the specified byte offset from the start of the view. |
Represents a raw buffer of binary data, which is used to store data for the different typed arrays. ArrayBuffers cannot be read from or written to directly, but can be passed to a typed array or DataView Object to interpret the raw buffer as needed.
Prop | Type | Description |
---|---|---|
byteLength | number | Read-only. The length of the ArrayBuffer (in bytes). |
Method | Signature | Description |
---|---|---|
slice | (begin: number, end?: number | undefined) => ArrayBuffer | Returns a section of an ArrayBuffer. |
All UUIDs have to be provided in 128 bit format as string (lowercase), e.g. '0000180d-0000-1000-8000-00805f9b34fb'
. There is a helper function to convert 16 bit UUID numbers to string:
import { numberToUUID } from '@capacitor-community/bluetooth-le';
const HEART_RATE_SERVICE = numberToUUID(0x180d);
// '0000180d-0000-1000-8000-00805f9b34fb'
0.0.2 (2020-12-14)
FAQs
Capacitor plugin for Bluetooth Low Energy
The npm package @capacitor-community/bluetooth-le receives a total of 5,190 weekly downloads. As such, @capacitor-community/bluetooth-le popularity was classified as popular.
We found that @capacitor-community/bluetooth-le demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 42 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
The Socket Research Team has discovered six new malicious npm packages linked to North Korea’s Lazarus Group, designed to steal credentials and deploy backdoors.
Security News
Socket CEO Feross Aboukhadijeh discusses the open web, open source security, and how Socket tackles software supply chain attacks on The Pair Program podcast.
Security News
Opengrep continues building momentum with the alpha release of its Playground tool, demonstrating the project's rapid evolution just two months after its initial launch.