-
Notifications
You must be signed in to change notification settings - Fork 529
Open
Labels
Description
Prerequisites
- I checked the documentation and FAQ without finding a solution
- I checked to make sure that this issue has not already been filed
Expected Behavior
I hit a weird bug on Android where after disconnecting from a BLE device, it no longer shows up in the device scan. I have confirmed through "nrf connect for mobile" that the device is indeed advertising and scannable. Sometimes the device will suddenly show up during the scan again. Very strange.
Current Behavior
It stops showing the device in the scan after disconnecting from it.
Library version
3.5.0
Device
Android 15 (pixel 9 pro)
Environment info
info Fetching system and libraries information...
System:
OS: macOS 15.3.1
CPU: (8) arm64 Apple M1
Memory: 131.61 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 23.9.0
path: ~/.local/state/fnm_multishells/42435_1741810219145/bin/node
Yarn: Not Found
npm:
version: 10.9.2
path: ~/.local/state/fnm_multishells/42435_1741810219145/bin/npm
Watchman:
version: 2025.03.03.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 24.2
- iOS 18.2
- macOS 15.2
- tvOS 18.2
- visionOS 2.2
- watchOS 11.2
Android SDK:
API Levels:
- "21"
- "26"
- "27"
- "31"
- "32"
- "34"
- "35"
Build Tools:
- 30.0.2
- 30.0.3
- 31.0.0
- 34.0.0
- 35.0.0
System Images:
- android-28 | Google ARM64-V8a Play ARM 64 v8a
- android-31 | Google APIs ARM 64 v8a
- android-34 | Google Play ARM 64 v8a
Android NDK: 26.1.10909125
IDEs:
Android Studio: 2024.1 AI-241.18034.62.2411.12071903
Xcode:
version: 16.2/16C5032a
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.11
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 18.0.0
wanted: ^18.0.0
react:
installed: 18.3.1
wanted: 18.3.1
react-native:
installed: 0.76.7
wanted: 0.76.7
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
info React Native v0.78.0 is now available (your project is running on v0.76.7).
info Changelog: https://github.com/facebook/react-native/releases/tag/v0.78.0
info Diff: https://react-native-community.github.io/upgrade-helper/?from=0.76.7&to=0.78.0
info For more info, check out "https://reactnative.dev/docs/upgrading?os=macos".
Steps to reproduce
- Connect to BLE device
- Disconnect from BLE device
- Scan
Formatted code sample or link to a repository
import { BleManager, Device, State } from 'react-native-ble-plx';
import { Platform, PermissionsAndroid } from 'react-native';
import { Buffer } from "buffer";
// Nordic UART Service UUID
const NUS_SERVICE_UUID = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
// Nordic UART TX characteristic (for receiving data from the device)
const NUS_TX_CHAR_UUID = '6e400003-b5a3-f393-e0a9-e50e24dcca9e';
// Nordic UART RX characteristic (for sending data to the device)
const NUS_RX_CHAR_UUID = '6e400002-b5a3-f393-e0a9-e50e24dcca9e';
class BleService {
private manager: BleManager;
private device: Device | null = null;
private isConnecting: boolean = false;
private isScanning: boolean = false;
constructor() {
this.manager = new BleManager();
}
async requestPermissions(): Promise<boolean> {
if (Platform.OS === 'android') {
try {
const permissionsToRequest = [
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT
].filter(Boolean); // Filter out undefined permissions
const results = await PermissionsAndroid.requestMultiple(permissionsToRequest);
return Object.values(results).every(
result => result === PermissionsAndroid.RESULTS.GRANTED
);
} catch (error) {
console.error('Error requesting permissions:', error);
return false;
}
}
return true; // iOS handles permissions differently via Info.plist
}
async startScan(onDeviceFound: (device: Device) => void): Promise<void> {
if (this.isScanning) return;
try {
this.isScanning = true;
console.log('Starting BLE scan...');
// Check if Bluetooth is enabled
const state = await this.manager.state();
if (state !== State.PoweredOn) {
console.log('Bluetooth is not powered on');
this.isScanning = false;
return;
}
// Request permissions
const hasPermission = await this.requestPermissions();
if (!hasPermission) {
console.log('Bluetooth permissions not granted');
this.isScanning = false;
return;
}
// Start scanning for BLE devices
this.manager.startDeviceScan(
null, // null means scan for all services
{ allowDuplicates: false },
(error, device) => {
if (error) {
console.error('Scan error:', error);
this.isScanning = false;
return;
}
if (device && device.name) {
console.log(`Found device: ${device.name} (${device.id})`);
onDeviceFound(device);
}
}
);
} catch (error) {
console.error('Error starting scan:', error);
this.isScanning = false;
}
}
stopScan(): void {
if (this.isScanning) {
this.manager.stopDeviceScan();
this.isScanning = false;
console.log('BLE scan stopped');
}
}
async connectToDevice(deviceId: string): Promise<boolean> {
if (this.isConnecting) return false;
try {
this.isConnecting = true;
console.log(`Connecting to device: ${deviceId}`);
// Stop scanning before connecting
this.stopScan();
// Connect to the device
const device = await this.manager.connectToDevice(deviceId);
console.log('Connected, discovering services and characteristics...');
// Discover services and characteristics
await device.discoverAllServicesAndCharacteristics();
// Check if device has the Nordic UART Service
const services = await device.services();
const hasNusService = services.some(service =>
service.uuid.toLowerCase() === NUS_SERVICE_UUID
);
if (!hasNusService) {
console.log('Device does not have the Nordic UART Service');
await device.cancelConnection();
this.isConnecting = false;
return false;
}
// Setup notification for receiving data
await this.setupNotifications(device);
this.device = device;
this.isConnecting = false;
console.log('Connected successfully');
return true;
} catch (error) {
console.error('Connection error:', error);
this.isConnecting = false;
return false;
}
}
async setupNotifications(device: Device): Promise<void> {
try {
// Monitor for incoming data on the TX characteristic
device.monitorCharacteristicForService(
NUS_SERVICE_UUID,
NUS_TX_CHAR_UUID,
(error, characteristic) => {
if (error) {
console.error('Notification error:', error);
return;
}
if (characteristic?.value) {
const decodedValue = this.decodeBase64(characteristic.value);
console.log('Received:', decodedValue);
}
}
);
} catch (error) {
console.error('Error setting up notifications:', error);
}
}
decodeBase64(data: string): string {
try {
return Buffer.from(data, 'base64').toString('utf8');
} catch (error) {
console.error('Error decoding base64:', error);
return '';
}
}
async sendCommand(command: string): Promise<boolean> {
if (!this.device) {
console.log('No device connected');
return false;
}
try {
// Convert string to base64 encoded data
const data = Buffer.from(command).toString('base64');
// Write to the RX characteristic
await this.device.writeCharacteristicWithResponseForService(
NUS_SERVICE_UUID,
NUS_RX_CHAR_UUID,
data
);
console.log(`Command sent: ${command}`);
return true;
} catch (error) {
console.error('Error sending command:', error);
return false;
}
}
async startRelay(): Promise<boolean> {
return this.sendCommand('start');
}
async stopRelay(): Promise<boolean> {
return this.sendCommand('stop');
}
async disconnect(): Promise<void> {
if (this.device) {
try {
await this.device.cancelConnection();
console.log('Disconnected from device');
} catch (error) {
console.error('Error disconnecting:', error);
} finally {
this.device = null;
}
}
}
cleanup(): void {
this.stopScan();
this.disconnect();
this.manager.destroy();
}
}
// Create singleton instance
const bleService = new BleService();
export default bleService;
Relevant log output
(NOBRIDGE) LOG Starting BLE scan...
(NOBRIDGE) LOG Found device: BLE_Relay (E7:15:B1:4E:A4:59)
(NOBRIDGE) LOG Found device: BLE_Relay (E7:15:B1:4E:A4:59)
(NOBRIDGE) LOG Found device: BLE_Relay (E7:15:B1:4E:A4:59)
(NOBRIDGE) LOG Found device: BLE_Relay (E7:15:B1:4E:A4:59)
(NOBRIDGE) LOG Connecting to device: E7:15:B1:4E:A4:59
(NOBRIDGE) LOG BLE scan stopped
(NOBRIDGE) LOG Connected, discovering services and characteristics...
(NOBRIDGE) LOG Connected successfully
(NOBRIDGE) LOG Disconnected from device
(NOBRIDGE) ERROR Notification error: [BleError: Device E7:15:B1:4E:A4:59 was disconnected]
(NOBRIDGE) LOG Starting BLE scan...
(NOBRIDGE) LOG Found device: M10K3QE (78:9C:85:1B:FF:AF)
(NOBRIDGE) LOG Found device: M10K3QE (78:9C:85:1B:FF:AF)
(NOBRIDGE) LOG Found device: M10K3QE (78:9C:85:1B:FF:AF)
etc.
Additional information
No response