Working with Bluetooth and NFC
1. Setting Up Bluetooth Permissions
Example: Requesting Bluetooth Permissions
import { PermissionsAndroid, Platform } from 'react-native';
const requestBluetoothPermission = async () => {
if (Platform.OS === 'android') {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Bluetooth Permission',
message: 'This app needs access to Bluetooth to connect to devices',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK'
}
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('Bluetooth permission granted');
} else {
console.log('Bluetooth permission denied');
}
} catch (err) {
console.warn(err);
}
}
};
| Permission | Android Manifest | Description |
|---|---|---|
| ACCESS_FINE_LOCATION | ACCESS_FINE_LOCATION |
Required for Bluetooth scanning and device discovery on Android 6.0+ |
| BLUETOOTH_ADMIN | BLUETOOTH_ADMIN |
Required to enable/disable Bluetooth and discover devices |
| BLUETOOTH | BLUETOOTH |
Required to use Bluetooth features (e.g., connect to devices) |
Note: On Android 12+, you must also request
ACCESS_FINE_LOCATION for Bluetooth scanning. This is a runtime permission that must be requested at runtime.
Warning: On Android 10 and below,
ACCESS_COARSE_LOCATION is sufficient for Bluetooth scanning. However, starting from Android 11, ACCESS_FINE_LOCATION is required.
Permission Requirements Summary
- Android 6.0+:
ACCESS_FINE_LOCATIONis required for Bluetooth scanning - Android 10 and below:
ACCESS_COARSE_LOCATIONis sufficient for basic scanning - Android 12+:
ACCESS_FINE_LOCATIONis required for all Bluetooth operations - Always include:
BLUETOOTHandBLUETOOTH_ADMINin manifest
2. Scanning for Bluetooth Devices
Example: Scan for nearby Bluetooth devices
import { BleManager } from 'react-native-ble-manager';
const manager = new BleManager();
const scanForDevices = async () => {
try {
await manager.startScan([], 10000); // Scan for 10 seconds
console.log('Scanning started...');
} catch (error) {
console.error('Scan error:', error);
}
};
scanForDevices();
| Property | Description | Values |
|---|---|---|
| scanDuration | Duration to scan for devices in milliseconds | 10000 |
| scanFilters | Optional filters to apply during scan | [] |
Note: Make sure to request Bluetooth permissions before scanning.
Warning: Scanning can drain battery quickly. Always stop scanning when done.
3. Connecting to Bluetooth Devices
| Property | Description | Notes |
|---|---|---|
| bluetoothState | Current state of Bluetooth adapter | Can be 'unknown', 'unsupported', 'unauthorized', 'disabled', 'enabled' |
| isBluetoothEnabled | Boolean indicating if Bluetooth is enabled | Useful for checking before attempting to connect |
Example: Check Bluetooth State
import { BluetoothManager } from 'react-native-bluetooth-ble';
BluetoothManager.start();
BluetoothManager.on('bluetoothState', (state) => {
console.log('Bluetooth State:', state);
});
Example: Enable Bluetooth
import { PermissionsAndroid, Platform } from 'react-native';
import { BluetoothManager } from 'react-native-bluetooth-ble';
const requestBluetoothPermission = async () => {
if (Platform.OS === 'android') {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Location Permission',
message: 'This app needs access to location to scan for Bluetooth devices.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK'
}
);
return granted === PermissionsAndroid.RESULTS.GRANTED;
}
return true;
};
const enableBluetooth = async () => {
const hasPermission = await requestBluetoothPermission();
if (hasPermission) {
BluetoothManager.start();
}
};
Note: On Android, you must request location permission to scan for Bluetooth devices. This is a requirement from Google's Play Store policy.
Warning: Bluetooth operations are asynchronous and may take time to complete. Always handle potential errors gracefully.
| Method | Description | Return Type |
|---|---|---|
| start() | Initializes the Bluetooth manager | Promise<void> |
| scanForPeripherals() | Starts scanning for nearby Bluetooth peripherals | Promise<void> |
| connectToDevice(deviceId) | Attempts to connect to a specific Bluetooth device | Promise<void> |
| disconnectFromDevice(deviceId) | Disconnects from a specific Bluetooth device | Promise<void> |
Example: Scan and Connect to Device
import { BluetoothManager } from 'react-native-bluetooth-ble';
const scanAndConnect = async () => {
try {
await BluetoothManager.start();
const devices = await BluetoothManager.scanForPeripherals();
console.log('Found Devices:', devices);
if (devices.length > 0) {
const device = devices[0];
await BluetoothManager.connectToDevice(device.id);
console.log('Connected to:', device.name);
}
} catch (error) {
console.error('Bluetooth Error:', error);
}
};
4. Reading Bluetooth Characteristics
| Property | Description | Notes |
|---|---|---|
| serviceUUID | Unique identifier for the Bluetooth service | Must be a valid UUID string |
| characteristicUUID | Unique identifier for the characteristic within a service | Must be a valid UUID string |
| isNotifying | Indicates if notifications are enabled for the characteristic | Boolean value |
Example: Reading a Bluetooth Characteristic
import { BleManager } from 'react-native-ble-manager';
const readCharacteristic = async (deviceID, serviceUUID, characteristicUUID) => {
try {
const value = await BleManager.readCharacteristicForDevice(
deviceID,
serviceUUID,
characteristicUUID
);
console.log('Characteristic value:', value);
} catch (error) {
console.error('Failed to read characteristic:', error);
}
};
Note: Ensure the device is connected and the characteristic is readable before attempting to read.
5. Writing to Bluetooth Devices
| Property | Description | Notes |
|---|---|---|
| device.id | Unique identifier for the Bluetooth device | Required to establish connection |
| service.uuid | UUID of the Bluetooth service to write to | Must match the device's advertised services |
| characteristic.uuid | UUID of the characteristic to write to | Must be writable and supported by device |
| value | Data to write to the characteristic | Can be a byte array or string depending on device |
Example: Writing to a Bluetooth Characteristic
import { BleManager } from 'react-native-ble-manager';
const writeToDevice = async () => {
const deviceId = 'device-id-here';
const serviceUuid = 'service-uuid-here';
const characteristicUuid = 'characteristic-uuid-here';
const data = new Uint8Array([0x48, 0x65, 0x6C, 0x6C, 0x6F]); // "Hello"
try {
await BleManager.write(
deviceId,
serviceUuid,
characteristicUuid,
data
);
console.log('Data written successfully');
} catch (error) {
console.error('Failed to write data:', error);
}
};
Note: Ensure the device is connected and the characteristic supports write operations before attempting to write data.
Warning: Writing invalid data or to a read-only characteristic may cause device errors or disconnection.
6. Implementing BLE Communication
Example: Connecting to a BLE Device
import { BleManager } from 'react-native-ble-manager';
const manager = new BleManager();
const connectToDevice = async (deviceId) => {
try {
await manager.connectToDevice(deviceId);
console.log('Connected to device');
} catch (error) {
console.error('Connection failed:', error);
}
};
| Method | Description | Notes |
|---|---|---|
| connectToDevice(deviceId) | Connects to a BLE device by ID | Must be called after scanning |
| discoverServices(deviceId) | Discovers GATT services | Required before reading/writing characteristics |
| readCharacteristic(deviceId, serviceId, characteristicId) | Reads a characteristic value | Returns data in base64 format |
| writeCharacteristic(deviceId, serviceId, characteristicId, value) | Writes a value to a characteristic | Value must be base64 encoded |
Note: BLE operations are asynchronous and must be handled with proper error handling.
Example: Reading a BLE Characteristic
const readData = async (deviceId, serviceId, characteristicId) => {
try {
const data = await manager.readCharacteristic(deviceId, serviceId, characteristicId);
const stringValue = Buffer.from(data, 'base64').toString();
console.log('Received data:', stringValue);
} catch (error) {
console.error('Read failed:', error);
}
};
Example: Writing to a BLE Characteristic
const writeData = async (deviceId, serviceId, characteristicId, message) => {
try {
const buffer = Buffer.from(message);
const base64Data = buffer.toString('base64');
await manager.writeCharacteristic(deviceId, serviceId, characteristicId, base64Data);
console.log('Data written successfully');
} catch (error) {
console.error('Write failed:', error);
}
};
7. Setting Up NFC Permissions
Example: Android Manifest Permissions
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.NFC" />
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
</manifest>
| Permission | Description | Platform Support |
|---|---|---|
| android.permission.NFC | Required to access NFC functionality on Android devices. | Android |
Note: On iOS, NFC is only available on devices that support NFC tags and requires specific hardware capabilities.
8. Reading NFC Tags
| Property | Description | Values |
|---|---|---|
| tag.id | Unique identifier of the NFC tag | string |
| tag.type | Type of NFC tag (e.g., NDEF, Mifare) | string |
| tag.payload | Data payload stored on the NFC tag | string |
Example: Reading NFC Tag Data
import { NfcManager } from 'react-native-nfc-manager';
const readNfcTag = async () => {
try {
await NfcManager.requestTechnology(NfcTech.Ndef);
const tag = await NfcManager.getTag();
console.log('Tag ID:', tag.id);
console.log('Tag Payload:', tag.payload);
} catch (error) {
console.error('Failed to read NFC tag', error);
}
};
Note: Ensure NFC permissions are granted in your app's manifest and runtime.
Warning: NFC reading may not work on all devices due to hardware or OS limitations.
9. Writing to NFC Tags
| Property | Description | Values |
|---|---|---|
| tagId | Unique identifier for the NFC tag | string |
| data | Data to be written to the NFC tag | string |
| format | Format of the data to be written (e.g., NDEF, Text) | string |
Example: Writing to an NFC Tag
import { NfcManager } from 'react-native-nfc-manager';
const writeNfcTag = async () => {
try {
await NfcManager.registerTagEvent();
const tag = await NfcManager.getTag();
const data = 'Hello, NFC!';
await NfcManager.writeNdefMessage(tag.id, data);
console.log('Data written to NFC tag');
} catch (error) {
console.error('Failed to write to NFC tag', error);
}
};
Note: Ensure NFC is enabled on the device and the tag is within range before attempting to write.
10. Handling NFC Errors
| Error Code | Description | Solution |
|---|---|---|
| NFC_ERROR_UNKNOWN | Unspecified NFC error occurred | Check device NFC support and permissions |
| NFC_ERROR_NOT_SUPPORTED | Device does not support NFC | Gracefully degrade or notify user |
| NFC_ERROR_PERMISSION_DENIED | App lacks NFC permissions | Request necessary permissions from user |
| NFC_ERROR_TAG_LOST | Tag was removed before read/write completed | Implement retry logic or notify user |
| NFC_ERROR_IO_ERROR | Input/output error during NFC operation | Verify tag is readable/writable and retry |
Example: Error Handling in NFC Read
import { NfcManager } from 'react-native-nfc-manager';
const readNfcTag = async () => {
try {
const tag = await NfcManager.readNdef();
console.log('Tag data:', tag);
} catch (error) {
if (error.code === 'NFC_ERROR_TAG_LOST') {
console.warn('NFC tag was removed too quickly');
} else if (error.code === 'NFC_ERROR_PERMISSION_DENIED') {
console.error('NFC permission denied');
} else {
console.error('Unknown NFC error:', error);
}
}
};
Note: Always handle NFC errors gracefully to provide a good user experience.