UNPKG

react-native-bluetooth-classic

Version:

Implement bluetooth classic (serial) on Android (Bluetooth Adapter) and IOS (External Accessory)

395 lines (394 loc) 15.1 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import BluetoothDevice from './BluetoothDevice'; import { BluetoothEventType, } from './BluetoothEvent'; import { NativeEventEmitter, Platform } from 'react-native'; import { Buffer } from 'buffer'; /** * Provides access to native module. In general the methods will be direct calls * through to {@code NativeModules.RNBluetoothClassc}, although there are instances * where methods are overwritten where additional information is required. These * methods are related to {@code BluetoothConnection} requests, where the response * must be wrapped. * * @author kenjdavidson */ export default class BluetoothModule { constructor(nativeModule) { this._nativeModule = nativeModule; this._eventEmitter = new NativeEventEmitter(new NativeModule()); } /** * Requests availability status of Bluetooth for the device. * * @return Promise resolved with whether Bluetooth is available for the current device. */ isBluetoothAvailable() { if (Platform.OS == 'ios') return Promise.resolve(true); return this._nativeModule.isBluetoothAvailable(); } /** * Requests enabled status from the BluetoothAdapter. * * @return Promise resolved with whether Bluetooth is enabled */ isBluetoothEnabled() { return this._nativeModule.isBluetoothEnabled(); } /** * Requests whether there is data availabled on the Device. At this point * this is a yes/no, it may be wise to turn it into number of bytes based * on devices that send messages of set size with no delimiter. * * @param address of the Device we wish to check * @return Promise resolved with whether data is available */ availableFromDevice(address) { return this._nativeModule.availableFromDevice(address); } /** * Read from the specified device. This uses the configured device read * functionality - see the Native documentation for how that is configured. * * @param address address from which to read * @return Promise resovled with individual read */ readFromDevice(address) { return this._nativeModule.readFromDevice(address); } /** * Clears the device buffer. * * @param address for which device we will clear * @return Promise resolved with whether clear was successful */ clearFromDevice(address) { return this._nativeModule.clearFromDevice(address); } /** * Disconnect from device. * * @param address of Device we will disconnect * @return Promise resolved with disconnection success status */ disconnectFromDevice(address) { return this._nativeModule.disconnectFromDevice(address); } /** * Determines whether device is currently connected. Connected means that there * is an actual Socket open (not just pairing) * * @param address of which we are checking for connection * @returns Promise resolved with whether there is a connection */ isDeviceConnected(address) { return this._nativeModule.isDeviceConnected(address); } /** * Wraps the bonded native devices with a BluetoothDevice to allow for * event management. * * @return Promise containing array of pair devices */ getBondedDevices() { return __awaiter(this, void 0, void 0, function* () { let bonded = yield this._nativeModule.getBondedDevices(); let devices = []; for (let device of bonded) { devices.push(new BluetoothDevice(device, this)); } return devices; }); } /** * Wraps the connected native devices with a BluetoothDevice to allow for * event management. * * @return Promise resolved with array of connected devices */ getConnectedDevices() { return __awaiter(this, void 0, void 0, function* () { let connected = yield this._nativeModule.getConnectedDevices(); let devices = []; for (let device of connected) { devices.push(new BluetoothDevice(device, this)); } return devices; }); } /** * Attempts to connect to the requested device. Defaults the properties to an empty * map. * * @param address the address to which we are connecting * @param properties extra properties required for the connection. */ connectToDevice(address, options) { return __awaiter(this, void 0, void 0, function* () { // Comming from the Java world this is nuts - not being able to assign anything to // options because it's a <T extends StandardOptions> even with something that matches // the StandardOptions interface let connected = yield this._nativeModule.connectToDevice(address, options || {}); return new BluetoothDevice(connected, this); }); } /** * Wraps connected NativeDevice. * * @param address the address to check for connection */ getConnectedDevice(address) { return __awaiter(this, void 0, void 0, function* () { let nativeDevice = yield this._nativeModule.getConnectedDevice(address); return new BluetoothDevice(nativeDevice, this); }); } /** * Write the provided message to the device. The `message` can be provided * as either: * - A String which will be encoded (using the optional `encoding`) * - A Buffer * * Both of which will eventually be base64 encoded in order to ensure that the data * is transferred in a common format through React Natives allowed parameter types. * * @param address the address to which we will send data * @param message string|Buffer which will be sent. * @param encoding "utf-8" | "ascii" | "utf8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex" | undefined */ writeToDevice(address, message, encoding) { let data = Buffer.isBuffer(message) ? message : Buffer.from(message, encoding); return this._nativeModule.writeToDevice(address, data.toString('base64')); } /** * Starts discovery on the bluetooth adatper. * * This is an Anroid only function. */ startDiscovery() { return __awaiter(this, void 0, void 0, function* () { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); let discoveredDevices = yield this._nativeModule.startDiscovery(); let devices = []; for (let discovered of discoveredDevices) { devices.push(new BluetoothDevice(discovered, this)); } return devices; }); } /** * Cancels discovery. If discovery was alreayd stopped, this will end gracefully * by resolving the promise. * * This is an Android only feature. */ cancelDiscovery() { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); return this._nativeModule.cancelDiscovery(); } /** * Pair the device request. * * This is an Android only feature. * * @param address address of the device we wish to pair */ pairDevice(address) { return __awaiter(this, void 0, void 0, function* () { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); let paired = yield this._nativeModule.pairDevice(address); return new BluetoothDevice(paired, this); }); } /** * Unpair the device request. * * This is an Android only feature. * * @param address address of the device we wish to unpair */ unpairDevice(address) { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); return this._nativeModule.unpairDevice(address); } /** * Attempt to start accepting connections. Accepts only one connection at a time, * once this has been established the device is returned and accepting is disabled. * * This is an Android only feature. * * @param properties used during the connection and connected process(es) */ accept(properties) { return __awaiter(this, void 0, void 0, function* () { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); let paired = yield this._nativeModule.accept(properties); return new BluetoothDevice(paired, this); }); } /** * Attempt to cancel the accepting state. * * This is an Android only feature. */ cancelAccept() { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); return this._nativeModule.cancelAccept(); } /** * Request user to turn on Bluetooth Adapter * * This is an Android only feature. * * @param state */ requestBluetoothEnabled() { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); return this._nativeModule.requestBluetoothEnabled(); } /** * Attempts to set the bluetooth adapter name. * * This is an Android only feature. * * @param name the name to which we will change BluetoothAdapter */ setBluetoothAdapterName(name) { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); return this._nativeModule.setBluetoothAdapterName(name); } createBluetoothEventSubscription(eventType, listener) { this._nativeModule.addListener(eventType); let subscription = this._eventEmitter.addListener(eventType, listener); return { remove: () => { this._nativeModule.removeListener(eventType); subscription.remove(); }, }; } /** * Creates an EventSubscription which calls the provided listener when the native * device is notified of the BluetoothAdapter being enabled. * * @param listener */ onBluetoothEnabled(listener) { return this.createBluetoothEventSubscription(BluetoothEventType.BLUETOOTH_ENABLED, listener); } /** * Creates an EventSubscription which calls the provided listener when the native * device is notified of the BluetoothAdapter being disabled. * * @param listener */ onBluetoothDisabled(listener) { return this.createBluetoothEventSubscription(BluetoothEventType.BLUETOOTH_DISABLED, listener); } /** * Creates an EventSubscription which wraps both enabled and disabled. * * @param listener */ onStateChanged(listener) { let enabledSubscription = this._eventEmitter.addListener(BluetoothEventType.BLUETOOTH_ENABLED, listener); let disabledSubscription = this._eventEmitter.addListener(BluetoothEventType.BLUETOOTH_DISABLED, listener); return { remove() { enabledSubscription.remove(); disabledSubscription.remove(); }, }; } /** * Creates an EventSubscription which wraps the DEVICE_CONNECTED event type. * * @param listener */ onDeviceConnected(listener) { return this.createBluetoothEventSubscription(BluetoothEventType.DEVICE_CONNECTED, listener); } /** * Creates an EventSubscription which wraps the DEVICE_DISCONNECTED event type. Device disconnected events * can be thrown for the following: * - During a read the DeviceConnection receives an un-cancelled exception (generally a closure) * - The AclReceiver receives an on disconnect (this seems less informative as it will still fire a disconnect * event if the connect had been cancelled. So at this point it may need to be removed.) * * @param listener */ onDeviceDisconnected(listener) { return this.createBluetoothEventSubscription(BluetoothEventType.DEVICE_DISCONNECTED, listener); } /** * Creates an EventSubscription based on the read event from a specified device. If the device * is not currently connected an exception will be thrown, although I'm not sure if * this is required, since it may be annoying to continually add/remove subscriptions. * * @param address device address to which we will start listening * @param listener onReadListener */ onDeviceRead(address, listener) { let eventType = `${BluetoothEventType.DEVICE_READ}@${address}`; this._nativeModule.addListener(eventType); let subscription = this._eventEmitter.addListener(eventType, listener); return { remove: () => { this._nativeModule.removeListener(eventType); subscription.remove(); }, }; } /** * Creates an EventSubscription which wraps the ERROR event. * * @param listener */ onError(listener) { return this.createBluetoothEventSubscription(BluetoothEventType.ERROR, listener); } /** * Creates an event subscription wrapping the DEVICE_DISCOVERED events. DEVICE_DISCOVERED is fired during the * discovery process, when a new device is found. Note this is only fired on the first discovery, it will not * be fired (at this point) with the updated RSSI value on the next device discovery. * * Remember to remove the subscription when you've found your device, or you stop discovery. * * @param listener */ onDeviceDiscovered(listener) { return this.createBluetoothEventSubscription(BluetoothEventType.DEVICE_DISCOVERED, listener); } /** * Opens Android's Bluetooth Settings activity. */ openBluetoothSettings() { if (Platform.OS == 'ios') throw new Error('Method not implemented.'); return this._nativeModule.openBluetoothSettings(); } } /** * Internal `NativeModule` to get around the fact that React doesn't actually make this * type available, but we need it in order to create our BluetoothModule. */ class NativeModule { addListener(eventType) { } removeListeners(count) { } }