react-native-ble-nitro
Version:
High-performance React Native BLE library built on Nitro Modules
493 lines • 18.9 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BleNitroManager = exports.AndroidScanMode = exports.BLEState = void 0;
exports.mapNativeBLEStateToBLEState = mapNativeBLEStateToBLEState;
exports.mapAndroidScanModeToNativeAndroidScanMode = mapAndroidScanModeToNativeAndroidScanMode;
exports.convertNativeBleDeviceToBleDevice = convertNativeBleDeviceToBleDevice;
exports.arrayBufferToByteArray = arrayBufferToByteArray;
exports.byteArrayToArrayBuffer = byteArrayToArrayBuffer;
const NativeBleNitro_1 = __importDefault(require("./specs/NativeBleNitro"));
const NativeBleNitro_2 = require("./specs/NativeBleNitro");
var BLEState;
(function (BLEState) {
BLEState["Unknown"] = "Unknown";
BLEState["Resetting"] = "Resetting";
BLEState["Unsupported"] = "Unsupported";
BLEState["Unauthorized"] = "Unauthorized";
BLEState["PoweredOff"] = "PoweredOff";
BLEState["PoweredOn"] = "PoweredOn";
})(BLEState || (exports.BLEState = BLEState = {}));
;
var AndroidScanMode;
(function (AndroidScanMode) {
AndroidScanMode["LowLatency"] = "LowLatency";
AndroidScanMode["Balanced"] = "Balanced";
AndroidScanMode["LowPower"] = "LowPower";
AndroidScanMode["Opportunistic"] = "Opportunistic";
})(AndroidScanMode || (exports.AndroidScanMode = AndroidScanMode = {}));
function mapNativeBLEStateToBLEState(nativeState) {
const map = {
0: BLEState.Unknown,
1: BLEState.Resetting,
2: BLEState.Unsupported,
3: BLEState.Unauthorized,
4: BLEState.PoweredOff,
5: BLEState.PoweredOn,
};
return map[nativeState];
}
function mapAndroidScanModeToNativeAndroidScanMode(scanMode) {
const map = {
LowLatency: NativeBleNitro_2.AndroidScanMode.LowLatency,
Balanced: NativeBleNitro_2.AndroidScanMode.Balanced,
LowPower: NativeBleNitro_2.AndroidScanMode.LowPower,
Opportunistic: NativeBleNitro_2.AndroidScanMode.Opportunistic,
};
return map[scanMode];
}
function convertNativeBleDeviceToBleDevice(nativeBleDevice) {
return {
...nativeBleDevice,
serviceUUIDs: BleNitroManager.normalizeGattUUIDs(nativeBleDevice.serviceUUIDs),
manufacturerData: {
companyIdentifiers: nativeBleDevice.manufacturerData.companyIdentifiers.map(entry => ({
id: entry.id,
data: arrayBufferToByteArray(entry.data)
}))
}
};
}
function arrayBufferToByteArray(buffer) {
return Array.from(new Uint8Array(buffer));
}
function byteArrayToArrayBuffer(data) {
return new Uint8Array(data).buffer;
}
class BleNitroManager {
constructor(options) {
this._isScanning = false;
this._connectedDevices = {};
this._restoredStateCallback = null;
this._restoredState = null;
this._restoredStateCallback = (options === null || options === void 0 ? void 0 : options.onRestoredState) || null;
NativeBleNitro_1.default.setRestoreStateCallback((peripherals) => this.onNativeRestoreStateCallback(peripherals));
}
onNativeRestoreStateCallback(peripherals) {
const bleDevices = peripherals.map((peripheral) => convertNativeBleDeviceToBleDevice(peripheral));
if (this._restoredStateCallback) {
this._restoredStateCallback(bleDevices);
}
else {
this._restoredState = bleDevices;
}
}
onRestoredState(callback) {
if (this._restoredState) {
callback(this._restoredState);
this._restoredState = null;
}
this._restoredStateCallback = callback;
}
/**
* Converts a 16- oder 32-Bit UUID to a 128-Bit UUID
*
* @param uuid 16-, 32- or 128-Bit UUID as string
* @returns Full 128-Bit UUID
*/
static normalizeGattUUID(uuid) {
const cleanUuid = uuid.toLowerCase();
// 128-Bit UUID → normalisieren
if (cleanUuid.length === 36 && cleanUuid.includes("-")) {
return cleanUuid;
}
// GATT-Service UUIDs
// 16- oder 32-Bit UUID → 128-Bit UUID
const padded = cleanUuid.padStart(8, "0");
return `${padded}-0000-1000-8000-00805f9b34fb`;
}
static normalizeGattUUIDs(uuids) {
return uuids.map((uuid) => BleNitroManager.normalizeGattUUID(uuid));
}
/**
* Start scanning for Bluetooth devices
* @param filter Optional scan filter
* @param callback Callback function called when a device is found
* @returns Promise resolving to success state
*/
startScan(filter = {}, callback, onError) {
var _a, _b, _c;
if (this._isScanning) {
return;
}
// Create native scan filter with defaults
const nativeFilter = {
serviceUUIDs: filter.serviceUUIDs || [],
rssiThreshold: (_a = filter.rssiThreshold) !== null && _a !== void 0 ? _a : -100,
allowDuplicates: (_b = filter.allowDuplicates) !== null && _b !== void 0 ? _b : false,
androidScanMode: mapAndroidScanModeToNativeAndroidScanMode((_c = filter.androidScanMode) !== null && _c !== void 0 ? _c : AndroidScanMode.Balanced),
};
// Create callback wrapper
const scanCallback = (device, error) => {
if (error && !device) {
this._isScanning = false;
onError === null || onError === void 0 ? void 0 : onError(error);
return;
}
device = device; // eslint-disable-line @typescript-eslint/no-non-null-assertion
// Convert manufacturer data to Uint8Arrays
const convertedDevice = convertNativeBleDeviceToBleDevice(device);
callback(convertedDevice);
};
// Start scan
NativeBleNitro_1.default.startScan(nativeFilter, scanCallback);
this._isScanning = true;
}
/**
* Stop scanning for Bluetooth devices
* @returns Promise resolving to success state
*/
stopScan() {
if (!this._isScanning) {
return;
}
NativeBleNitro_1.default.stopScan();
this._isScanning = false;
}
/**
* Check if currently scanning for devices
* @returns Promise resolving to scanning state
*/
isScanning() {
this._isScanning = NativeBleNitro_1.default.isScanning();
return this._isScanning;
}
/**
* Get all currently connected devices
* @param services Optional list of service UUIDs to filter by
* @returns Array of connected devices
*/
getConnectedDevices(services) {
const devices = NativeBleNitro_1.default.getConnectedDevices(services || []);
// Normalize service UUIDs - manufacturer data already comes as ArrayBuffers
return devices.map(device => convertNativeBleDeviceToBleDevice(device));
}
/**
* Connect to a Bluetooth device
* @param deviceId ID of the device to connect to
* @param onDisconnect Optional callback for disconnect events
* @returns Promise resolving when connected
*/
connect(deviceId, onDisconnect) {
return new Promise((resolve, reject) => {
// Check if already connected
if (this._connectedDevices[deviceId]) {
resolve(deviceId);
return;
}
NativeBleNitro_1.default.connect(deviceId, (success, connectedDeviceId, error) => {
if (success) {
this._connectedDevices[deviceId] = true;
resolve(connectedDeviceId);
}
else {
reject(new Error(error));
}
}, onDisconnect ? (deviceId, interrupted, error) => {
// Remove from connected devices when disconnected
delete this._connectedDevices[deviceId];
onDisconnect(deviceId, interrupted, error);
} : undefined);
});
}
/**
* Disconnect from a Bluetooth device
* @param deviceId ID of the device to disconnect from
* @returns Promise resolving when disconnected
*/
disconnect(deviceId) {
return new Promise((resolve, reject) => {
// Check if already disconnected
if (!this._connectedDevices[deviceId]) {
resolve();
return;
}
NativeBleNitro_1.default.disconnect(deviceId, (success, error) => {
if (success) {
delete this._connectedDevices[deviceId];
resolve();
}
else {
reject(new Error(error));
}
});
});
}
/**
* Check if connected to a device
* @param deviceId ID of the device to check
* @returns Promise resolving to connection state
*/
isConnected(deviceId) {
return NativeBleNitro_1.default.isConnected(deviceId);
}
/**
* Request a new MTU size
* @param deviceId ID of the device
* @param mtu New MTU size, min is 23, max is 517
* @returns On Android: new MTU size; on iOS: current MTU size as it is handled by iOS itself; on error: -1
*/
requestMTU(deviceId, mtu) {
mtu = parseInt(mtu.toString(), 10);
const deviceMtu = NativeBleNitro_1.default.requestMTU(deviceId, mtu);
return deviceMtu;
}
/**
* Read RSSI for a connected device
* @param deviceId ID of the device
* @returns Promise resolving to RSSI value
*/
readRSSI(deviceId) {
return new Promise((resolve, reject) => {
// Check if connected first
if (!this._connectedDevices[deviceId]) {
reject(new Error('Device not connected'));
return;
}
NativeBleNitro_1.default.readRSSI(deviceId, (success, rssi, error) => {
if (success) {
resolve(rssi);
}
else {
reject(new Error(error));
}
});
});
}
/**
* Discover services for a connected device
* @param deviceId ID of the device
* @returns Promise resolving when services are discovered
*/
discoverServices(deviceId) {
return new Promise((resolve, reject) => {
// Check if connected first
if (!this._connectedDevices[deviceId]) {
reject(new Error('Device not connected'));
return;
}
NativeBleNitro_1.default.discoverServices(deviceId, (success, error) => {
if (success) {
resolve(true);
}
else {
reject(new Error(error));
}
});
});
}
/**
* Get services for a connected device
* @param deviceId ID of the device
* @returns Promise resolving to array of service UUIDs
*/
getServices(deviceId) {
return new Promise(async (resolve, reject) => {
// Check if connected first
if (!this._connectedDevices[deviceId]) {
reject(new Error('Device not connected'));
return;
}
const success = await this.discoverServices(deviceId);
if (!success) {
reject(new Error('Failed to discover services'));
return;
}
const services = NativeBleNitro_1.default.getServices(deviceId);
resolve(BleNitroManager.normalizeGattUUIDs(services));
});
}
/**
* Get characteristics for a service
* @param deviceId ID of the device
* @param serviceId ID of the service
* @returns Promise resolving to array of characteristic UUIDs
*/
getCharacteristics(deviceId, serviceId) {
if (!this._connectedDevices[deviceId]) {
throw new Error('Device not connected');
}
const characteristics = NativeBleNitro_1.default.getCharacteristics(deviceId, BleNitroManager.normalizeGattUUID(serviceId));
return BleNitroManager.normalizeGattUUIDs(characteristics);
}
/**
* Read a characteristic value
* @param deviceId ID of the device
* @param serviceId ID of the service
* @param characteristicId ID of the characteristic
* @returns Promise resolving to the characteristic data as ArrayBuffer
*/
readCharacteristic(deviceId, serviceId, characteristicId) {
return new Promise((resolve, reject) => {
// Check if connected first
if (!this._connectedDevices[deviceId]) {
reject(new Error('Device not connected'));
return;
}
NativeBleNitro_1.default.readCharacteristic(deviceId, BleNitroManager.normalizeGattUUID(serviceId), BleNitroManager.normalizeGattUUID(characteristicId), (success, data, error) => {
if (success) {
resolve(arrayBufferToByteArray(data));
}
else {
reject(new Error(error));
}
});
});
}
/**
* Write a value to a characteristic
* @param deviceId ID of the device
* @param serviceId ID of the service
* @param characteristicId ID of the characteristic
* @param data Data to write as ByteArray (number[])
* @param withResponse Whether to wait for response
* @returns Promise resolving with response data (empty ByteArray when withResponse=false)
*/
writeCharacteristic(deviceId, serviceId, characteristicId, data, withResponse = true) {
return new Promise((resolve, reject) => {
// Check if connected first
if (!this._connectedDevices[deviceId]) {
reject(new Error('Device not connected'));
return;
}
NativeBleNitro_1.default.writeCharacteristic(deviceId, BleNitroManager.normalizeGattUUID(serviceId), BleNitroManager.normalizeGattUUID(characteristicId), byteArrayToArrayBuffer(data), withResponse, (success, responseData, error) => {
if (success) {
// Convert ArrayBuffer response to ByteArray
const responseByteArray = arrayBufferToByteArray(responseData);
resolve(responseByteArray);
}
else {
reject(new Error(error));
}
});
});
}
/**
* Subscribe to characteristic notifications
* @param deviceId ID of the device
* @param serviceId ID of the service
* @param characteristicId ID of the characteristic
* @param callback Callback function called when notification is received
* @returns Promise resolving when subscription is complete
*/
subscribeToCharacteristic(deviceId, serviceId, characteristicId, callback) {
// Check if connected first
if (!this._connectedDevices[deviceId]) {
throw new Error('Device not connected');
}
let _success = false;
NativeBleNitro_1.default.subscribeToCharacteristic(deviceId, BleNitroManager.normalizeGattUUID(serviceId), BleNitroManager.normalizeGattUUID(characteristicId), (charId, data) => {
callback(charId, arrayBufferToByteArray(data));
}, (success, error) => {
_success = success;
if (!success) {
throw new Error(error);
}
});
return {
remove: () => {
if (!_success) {
return;
}
this.unsubscribeFromCharacteristic(deviceId, serviceId, characteristicId).catch(() => { });
}
};
}
/**
* Unsubscribe from characteristic notifications
* @param deviceId ID of the device
* @param serviceId ID of the service
* @param characteristicId ID of the characteristic
* @returns Promise resolving when unsubscription is complete
*/
unsubscribeFromCharacteristic(deviceId, serviceId, characteristicId) {
return new Promise((resolve, reject) => {
// Check if connected first
if (!this._connectedDevices[deviceId]) {
reject(new Error('Device not connected'));
return;
}
NativeBleNitro_1.default.unsubscribeFromCharacteristic(deviceId, BleNitroManager.normalizeGattUUID(serviceId), BleNitroManager.normalizeGattUUID(characteristicId), (success, error) => {
if (success) {
resolve();
}
else {
reject(new Error(error));
}
});
});
}
/**
* Check if Bluetooth is enabled
* @returns Promise resolving to Bluetooth state
*/
isBluetoothEnabled() {
return this.state() === BLEState.PoweredOn;
}
/**
* Request to enable Bluetooth (Android only)
* @returns Promise resolving when Bluetooth is enabled
*/
requestBluetoothEnable() {
return new Promise((resolve, reject) => {
NativeBleNitro_1.default.requestBluetoothEnable((success, error) => {
if (success) {
resolve(true);
}
else {
reject(new Error(error));
}
});
});
}
/**
* Get the current Bluetooth state
* @returns Promise resolving to Bluetooth state
* @see BLEState
*/
state() {
return mapNativeBLEStateToBLEState(NativeBleNitro_1.default.state());
}
/**
* Subscribe to Bluetooth state changes
* @param callback Callback function called when state changes
* @param emitInitial Whether to emit initial state callback
* @returns Promise resolving when subscription is complete
* @see BLEState
*/
subscribeToStateChange(callback, emitInitial = false) {
if (emitInitial) {
const state = this.state();
callback(state);
}
NativeBleNitro_1.default.subscribeToStateChange((nativeState) => {
callback(mapNativeBLEStateToBLEState(nativeState));
});
return {
remove: () => {
NativeBleNitro_1.default.unsubscribeFromStateChange();
},
};
}
/**
* Open Bluetooth settings
* @returns Promise resolving when settings are opened
*/
openSettings() {
return NativeBleNitro_1.default.openSettings();
}
}
exports.BleNitroManager = BleNitroManager;
//# sourceMappingURL=manager.js.map
;