From f8cb467d4ca05646cd555ef6d88483bc818ed10c Mon Sep 17 00:00:00 2001 From: Dominik Czupryna Date: Wed, 4 Oct 2023 09:09:45 +0200 Subject: [PATCH 1/8] chore: recreate native error --- .eslintignore | 3 ++- .../screens/MainStack/DashboardScreen/DashboardScreen.tsx | 1 + example/src/services/BLEService/BLEService.ts | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.eslintignore b/.eslintignore index 3ef8f41d..fddf3ca8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ /**/node_modules/* node_modules/ -docs/** \ No newline at end of file +docs/** +lib/** \ No newline at end of file diff --git a/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx b/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx index d2c5e85b..26df86b2 100644 --- a/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx +++ b/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx @@ -79,6 +79,7 @@ export function DashboardScreen({ navigation }: DashboardScreenProps) { /> navigation.navigate('DEVICE_NRF_TEST_SCREEN')} /> + BLEService.isDeviceWithIdConnected('asd')} /> { - this.onError(error) - }) + return this.manager.isDeviceConnected(this.device.id) } + isDeviceWithIdConnected = (id: string) => this.manager.isDeviceConnected(id).catch(console.error) + getConnectedDevices = (expectedServices: UUID[]) => { if (!this.device) { this.showErrorToast(deviceNotConnectedErrorText) From 789b9ab26d969fece0335f94efe9be401adc3b4a Mon Sep 17 00:00:00 2001 From: Dominik Czupryna Date: Thu, 5 Oct 2023 17:10:57 +0200 Subject: [PATCH 2/8] test: android device disconnecting example --- .../TestStateDisplay/TestStateDisplay.tsx | 4 +- example/src/consts/nRFDeviceConsts.ts | 13 + .../src/navigation/navigators/MainStack.tsx | 8 + .../DashboardScreen/DashboardScreen.tsx | 4 + .../DeviceConnectDisconnectTestScreen.tsx | 231 ++++++++++++++++++ .../DevicenRFTestScreen.tsx | 23 +- example/src/screens/MainStack/index.ts | 1 + example/src/services/BLEService/BLEService.ts | 16 ++ 8 files changed, 286 insertions(+), 14 deletions(-) create mode 100644 example/src/consts/nRFDeviceConsts.ts create mode 100644 example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx diff --git a/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx b/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx index 44f88be0..41def81b 100644 --- a/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx +++ b/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx @@ -5,7 +5,7 @@ import { Container, Header, Label } from './TestStateDisplay.styled' export type TestStateDisplayProps = { label?: string - state: TestStateType + state?: TestStateType value?: string } @@ -21,7 +21,7 @@ export function TestStateDisplay({ label, state, value }: TestStateDisplayProps)
- {marks[state]} + {state && {marks[state]}}
{value && {value}}
diff --git a/example/src/consts/nRFDeviceConsts.ts b/example/src/consts/nRFDeviceConsts.ts new file mode 100644 index 00000000..66395ca6 --- /dev/null +++ b/example/src/consts/nRFDeviceConsts.ts @@ -0,0 +1,13 @@ +import { fullUUID } from 'react-native-ble-plx' +import base64 from 'react-native-base64' +import { getDateAsBase64 } from '../utils/getDateAsBase64' + +export const deviceTimeService = fullUUID('1847') +export const currentTimeCharacteristic = fullUUID('2A2B') +export const deviceTimeCharacteristic = fullUUID('2B90') +export const currentTimeCharacteristicTimeTriggerDescriptor = fullUUID('290E') + +export const writeWithResponseBase64Time = getDateAsBase64(new Date('2022-08-11T08:17:19Z')) +export const writeWithoutResponseBase64Time = getDateAsBase64(new Date('2023-09-12T10:12:16Z')) +export const monitorExpectedMessage = 'Hi, it works!' +export const currentTimeCharacteristicTimeTriggerDescriptorValue = base64.encode('BLE-PLX') diff --git a/example/src/navigation/navigators/MainStack.tsx b/example/src/navigation/navigators/MainStack.tsx index adbabf63..8efa01a2 100644 --- a/example/src/navigation/navigators/MainStack.tsx +++ b/example/src/navigation/navigators/MainStack.tsx @@ -7,6 +7,7 @@ export type MainStackParamList = { DASHBOARD_SCREEN: undefined DEVICE_DETAILS_SCREEN: undefined DEVICE_NRF_TEST_SCREEN: undefined + DEVICE_CONNECT_DISCONNECT_TEST_SCREEN: undefined } const MainStack = createNativeStackNavigator() @@ -37,6 +38,13 @@ export function MainStackComponent() { headerTitle: 'nRF device test' }} /> + ) } diff --git a/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx b/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx index 26df86b2..0fc6c65f 100644 --- a/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx +++ b/example/src/screens/MainStack/DashboardScreen/DashboardScreen.tsx @@ -80,6 +80,10 @@ export function DashboardScreen({ navigation }: DashboardScreenProps) { navigation.navigate('DEVICE_NRF_TEST_SCREEN')} /> BLEService.isDeviceWithIdConnected('asd')} /> + navigation.navigate('DEVICE_CONNECT_DISCONNECT_TEST_SCREEN')} + /> + +export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnectTestScreenProps) { + const [expectedDeviceName, setExpectedDeviceName] = useState('') + const [testScanDevicesState, setTestScanDevicesState] = useState('WAITING') + const [deviceId, setDeviceId] = useState('') + const [connectCounter, setConnectCounter] = useState(0) + const [characteristicDiscoverCounter, setCharacteristicDiscoverCounter] = useState(0) + const [connectInDisconnectTestCounter, setConnectInDisconnectTestCounter] = useState(0) + const [disconnectCounter, setDisconnectCounter] = useState(0) + const [monitorMessages, setMonitorMessages] = useState([]) + const monitorSubscriptionRef = useRef(null) + + const addMonitorMessage = (message: string) => setMonitorMessages(prevMessages => [...prevMessages, message]) + + const checkDeviceName = (device: Device) => + device.name?.toLocaleLowerCase() === expectedDeviceName.toLocaleLowerCase() + + const startConnectAndDiscover = async () => { + setTestScanDevicesState('IN_PROGRESS') + await BLEService.initializeBLE() + await BLEService.scanDevices(connectAndDiscoverOnDeviceFound, [deviceTimeService]) + } + + const startConnectAndDisconnect = async () => { + setTestScanDevicesState('IN_PROGRESS') + await BLEService.initializeBLE() + await BLEService.scanDevices(connectAndDisconnectOnDeviceFound, [deviceTimeService]) + } + + const startConnectOnly = async () => { + setTestScanDevicesState('IN_PROGRESS') + await BLEService.initializeBLE() + await BLEService.scanDevices( + async (device: Device) => { + if (checkDeviceName(device)) { + console.info(`connecting to ${device.id}`) + await startConnectToDevice(device) + setConnectCounter(prevCount => prevCount + 1) + setTestScanDevicesState('DONE') + setDeviceId(device.id) + } + }, + [deviceTimeService] + ) + } + + const connectAndDiscoverOnDeviceFound = async (device: Device) => { + if (checkDeviceName(device)) { + setTestScanDevicesState('DONE') + setDeviceId(device.id) + try { + for (let i = 0; i < 10; i += 1) { + console.info(`connecting to ${device.id}`) + await startConnectToDevice(device) + setConnectCounter(prevCount => prevCount + 1) + console.info(`discovering in ${device.id}`) + await startDiscoverServices() + setCharacteristicDiscoverCounter(prevCount => prevCount + 1) + } + console.info('Multiple connect success') + } catch (error) { + console.error('Multiple connect error') + } + } + } + const connectAndDisconnectOnDeviceFound = async (device: Device) => { + if (checkDeviceName(device)) { + setTestScanDevicesState('DONE') + setDeviceId(device.id) + try { + for (let i = 0; i < 10; i += 1) { + await startConnectToDevice(device) + console.info(`connecting to ${device.id}`) + setConnectInDisconnectTestCounter(prevCount => prevCount + 1) + await startDisconnect(device) + console.info(`disconnecting from ${device.id}`) + setDisconnectCounter(prevCount => prevCount + 1) + } + console.info('connect/disconnect success') + } catch (error) { + console.error('Connect/disconnect error') + } + } + } + + const discoverCharacteristicsOnly = async () => { + if (!deviceId) { + console.error('Device not ready') + return + } + try { + for (let i = 0; i < 10; i += 1) { + console.info(`discovering in ${deviceId}`) + await startDiscoverServices() + setCharacteristicDiscoverCounter(prevCount => prevCount + 1) + } + console.info('Multiple discovering success') + } catch (error) { + console.error('Multiple discovering error') + } + } + + const startConnectToDevice = (device: Device) => BLEService.connectToDevice(device.id) + + const startDiscoverServices = () => BLEService.discoverAllServicesAndCharacteristicsForDevice() + + const startDisconnect = (device: Device) => BLEService.disconnectDeviceById(device.id) + + const startCharacteristicMonitor = (directDeviceId?: string) => { + if (!deviceId && !directDeviceId) { + console.error('Device not ready') + return + } + monitorSubscriptionRef.current = BLEService.setupCustomMonitor( + directDeviceId || deviceId, + deviceTimeService, + currentTimeCharacteristic, + characteristicListener + ) + } + + const characteristicListener = (error: BleError | null, characteristic: Characteristic | null) => { + if (error) { + if (error.errorCode === 302) { + startDiscoverServices().then(() => startCharacteristicMonitor()) + return + } + console.error(JSON.stringify(error)) + } + if (characteristic) { + if (characteristic.value) { + const message = base64.decode(characteristic.value) + console.info(message) + addMonitorMessage(message) + } + } + } + + const setupOnDeviceDisconnected = (directDeviceId?: string) => { + if (!deviceId && !directDeviceId) { + console.error('Device not ready') + return + } + BLEService.onDeviceDisconnectedCustom(directDeviceId || deviceId, disconnectedListener) + } + + const disconnectedListener = (error: BleError | null, device: Device | null) => { + if (error) { + console.error('onDeviceDisconnected') + console.error(JSON.stringify(error, null, 4)) + } + if (device) { + console.info(JSON.stringify(device, null, 4)) + } + } + + const show1103Crash = async () => { + setTestScanDevicesState('IN_PROGRESS') + await BLEService.initializeBLE() + await BLEService.scanDevices( + async (device: Device) => { + if (checkDeviceName(device)) { + console.info(`connecting to ${device.id}`) + await startConnectToDevice(device) + setConnectCounter(prevCount => prevCount + 1) + setTestScanDevicesState('DONE') + setDeviceId(device.id) + await startDiscoverServices() + await wait(1000) + setupOnDeviceDisconnected(device.id) + await wait(1000) + startCharacteristicMonitor(device.id) + await wait(1000) + const info = 'Now disconnect device' + console.info(info) + Toast.show({ + type: 'info', + text1: info + }) + } + }, + [deviceTimeService] + ) + } + + return ( + + + + + + setupOnDeviceDisconnected()} /> + + + + + + + + + startCharacteristicMonitor()} /> + + + + + ) +} diff --git a/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx b/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx index 1784f1a9..b0bcf6c2 100644 --- a/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx +++ b/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx @@ -1,27 +1,26 @@ import React, { useState, type Dispatch } from 'react' import type { TestStateType } from 'example/types' import type { NativeStackScreenProps } from '@react-navigation/native-stack' -import { Device, fullUUID, type Base64 } from 'react-native-ble-plx' +import { Device, type Base64 } from 'react-native-ble-plx' import { Platform, ScrollView } from 'react-native' import base64 from 'react-native-base64' -import { getDateAsBase64 } from '../../../utils/getDateAsBase64' import { BLEService } from '../../../services' import type { MainStackParamList } from '../../../navigation/navigators' import { AppButton, AppTextInput, ScreenDefaultContainer, TestStateDisplay } from '../../../components/atoms' import { wait } from '../../../utils/wait' +import { + currentTimeCharacteristic, + currentTimeCharacteristicTimeTriggerDescriptor, + currentTimeCharacteristicTimeTriggerDescriptorValue, + deviceTimeCharacteristic, + deviceTimeService, + monitorExpectedMessage, + writeWithResponseBase64Time, + writeWithoutResponseBase64Time +} from '../../../consts/nRFDeviceConsts' type DevicenRFTestScreenProps = NativeStackScreenProps -const deviceTimeService = fullUUID('1847') -const currentTimeCharacteristic = fullUUID('2A2B') -const deviceTimeCharacteristic = fullUUID('2B90') -const currentTimeCharacteristicTimeTriggerDescriptor = fullUUID('290E') - -const writeWithResponseBase64Time = getDateAsBase64(new Date('2022-08-11T08:17:19Z')) -const writeWithoutResponseBase64Time = getDateAsBase64(new Date('2023-09-12T10:12:16Z')) -const monitorExpectedMessage = 'Hi, it works!' -const currentTimeCharacteristicTimeTriggerDescriptorValue = base64.encode('BLE-PLX') - export function DevicenRFTestScreen(_props: DevicenRFTestScreenProps) { const [expectedDeviceName, setExpectedDeviceName] = useState('') const [testScanDevicesState, setTestScanDevicesState] = useState('WAITING') diff --git a/example/src/screens/MainStack/index.ts b/example/src/screens/MainStack/index.ts index afb59930..20784153 100644 --- a/example/src/screens/MainStack/index.ts +++ b/example/src/screens/MainStack/index.ts @@ -1,3 +1,4 @@ export * from './DashboardScreen/DashboardScreen' export * from './DeviceDetailsScreen/DeviceDetailsScreen' export * from './DevicenRFTestScreen/DevicenRFTestScreen' +export * from './DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen' diff --git a/example/src/services/BLEService/BLEService.ts b/example/src/services/BLEService/BLEService.ts index a5ebc4e2..aa83935f 100644 --- a/example/src/services/BLEService/BLEService.ts +++ b/example/src/services/BLEService/BLEService.ts @@ -77,6 +77,16 @@ class BLEServiceInstance { }) } + disconnectDeviceById = (id: string) => + this.manager + .cancelDeviceConnection(id) + .then(() => this.showSuccessToast('Device disconnected')) + .catch(error => { + if (error?.code !== BleErrorCode.DeviceDisconnected) { + this.onError(error) + } + }) + onBluetoothPowerOff = () => { this.showErrorToast('Bluetooth is turned off') } @@ -211,6 +221,9 @@ class BLEServiceInstance { ) } + setupCustomMonitor: BleManager['monitorCharacteristicForDevice'] = (...args) => + this.manager.monitorCharacteristicForDevice(...args) + finishMonitor = () => { this.isCharacteristicMonitorDisconnectExpected = true this.characteristicMonitor?.remove() @@ -313,6 +326,9 @@ class BLEServiceInstance { return this.manager.onDeviceDisconnected(this.device.id, listener) } + onDeviceDisconnectedCustom: BleManager['onDeviceDisconnected'] = (...args) => + this.manager.onDeviceDisconnected(...args) + readRSSIForDevice = () => { if (!this.device) { this.showErrorToast(deviceNotConnectedErrorText) From 95ae38b7331c7fe5eb68b6037534680397bbb477 Mon Sep 17 00:00:00 2001 From: Grzegorz Miszewski Date: Tue, 10 Oct 2023 11:49:45 +0200 Subject: [PATCH 3/8] fix: resolves #1103 - crash on disconnect --- .../src/main/java/com/bleplx/BlePlxModule.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/bleplx/BlePlxModule.java b/android/src/main/java/com/bleplx/BlePlxModule.java index 1464bd27..b165a1b3 100644 --- a/android/src/main/java/com/bleplx/BlePlxModule.java +++ b/android/src/main/java/com/bleplx/BlePlxModule.java @@ -36,22 +36,36 @@ import com.bleplx.converter.ServiceToJsObjectConverter; import com.bleplx.utils.ReadableArrayConverter; import com.bleplx.utils.SafePromise; +import com.polidea.rxandroidble2.internal.RxBleLog; import java.util.HashMap; import java.util.List; import java.util.Map; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.app.Activity; +import io.reactivex.exceptions.UndeliverableException; +import io.reactivex.plugins.RxJavaPlugins; + @ReactModule(name = BlePlxModule.NAME) public class BlePlxModule extends ReactContextBaseJavaModule { public static final String NAME = "BlePlx"; public BlePlxModule(ReactApplicationContext reactContext) { super(reactContext); + RxJavaPlugins.setErrorHandler(throwable -> { + if (throwable instanceof UndeliverableException) { + RxBleLog.e("Handle all unhandled exceptions from RxJava: " + throwable.getMessage()); + } else { + Thread currentThread = Thread.currentThread(); + Thread.UncaughtExceptionHandler errorHandler = currentThread.getUncaughtExceptionHandler(); + if (errorHandler != null) { + errorHandler.uncaughtException(currentThread, throwable); + } + } + }); } @Override From a2c6b9a2621bb4291c0bce7b2bc2b206904ad6d9 Mon Sep 17 00:00:00 2001 From: Grzegorz Miszewski Date: Tue, 10 Oct 2023 12:01:11 +0200 Subject: [PATCH 4/8] refactor: sorted imports --- .../DeviceConnectDisconnectTestScreen.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx b/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx index 5814d6ec..509c0e7d 100644 --- a/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx +++ b/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx @@ -4,12 +4,12 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack' import { BleError, Characteristic, Device, type Subscription } from 'react-native-ble-plx' import { ScrollView } from 'react-native' import base64 from 'react-native-base64' +import Toast from 'react-native-toast-message' import { BLEService } from '../../../services' import type { MainStackParamList } from '../../../navigation/navigators' import { AppButton, AppTextInput, ScreenDefaultContainer, TestStateDisplay } from '../../../components/atoms' -import { deviceTimeService, currentTimeCharacteristic } from '../../../consts/nRFDeviceConsts' +import { currentTimeCharacteristic, deviceTimeService } from '../../../consts/nRFDeviceConsts' import { wait } from '../../../utils/wait' -import Toast from 'react-native-toast-message' type DeviceConnectDisconnectTestScreenProps = NativeStackScreenProps< MainStackParamList, From 9b93a1c6bf02d33c4dd470c0cabbbebb5bd733d6 Mon Sep 17 00:00:00 2001 From: Dominik Czupryna Date: Wed, 11 Oct 2023 11:03:47 +0200 Subject: [PATCH 5/8] refactor: types --- .../atoms/TestStateDisplay/TestStateDisplay.tsx | 6 +++--- .../DeviceConnectDisconnectTestScreen.tsx | 8 ++++---- .../DevicenRFTestScreen/DevicenRFTestScreen.tsx | 2 +- example/src/services/BLEService/BLEService.ts | 13 +++++++------ example/{ => src}/types/TestStateType.ts | 0 example/{ => src}/types/index.ts | 0 6 files changed, 15 insertions(+), 14 deletions(-) rename example/{ => src}/types/TestStateType.ts (100%) rename example/{ => src}/types/index.ts (100%) diff --git a/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx b/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx index 41def81b..29366514 100644 --- a/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx +++ b/example/src/components/atoms/TestStateDisplay/TestStateDisplay.tsx @@ -1,5 +1,5 @@ import React from 'react' -import type { TestStateType } from 'example/types' +import type { TestStateType } from '../../../types' import { AppText } from '../AppText/AppText' import { Container, Header, Label } from './TestStateDisplay.styled' @@ -21,9 +21,9 @@ export function TestStateDisplay({ label, state, value }: TestStateDisplayProps)
- {state && {marks[state]}} + {!!state && {marks[state]}}
- {value && {value}} + {!!value && {value}}
) } diff --git a/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx b/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx index 509c0e7d..fee3fc83 100644 --- a/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx +++ b/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx @@ -1,10 +1,10 @@ import React, { useRef, useState } from 'react' -import type { TestStateType } from 'example/types' import type { NativeStackScreenProps } from '@react-navigation/native-stack' -import { BleError, Characteristic, Device, type Subscription } from 'react-native-ble-plx' +import { BleError, Characteristic, Device, type Subscription, type DeviceId } from 'react-native-ble-plx' import { ScrollView } from 'react-native' import base64 from 'react-native-base64' import Toast from 'react-native-toast-message' +import type { TestStateType } from '../../../types' import { BLEService } from '../../../services' import type { MainStackParamList } from '../../../navigation/navigators' import { AppButton, AppTextInput, ScreenDefaultContainer, TestStateDisplay } from '../../../components/atoms' @@ -123,7 +123,7 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec const startDisconnect = (device: Device) => BLEService.disconnectDeviceById(device.id) - const startCharacteristicMonitor = (directDeviceId?: string) => { + const startCharacteristicMonitor = (directDeviceId?: DeviceId) => { if (!deviceId && !directDeviceId) { console.error('Device not ready') return @@ -153,7 +153,7 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec } } - const setupOnDeviceDisconnected = (directDeviceId?: string) => { + const setupOnDeviceDisconnected = (directDeviceId?: DeviceId) => { if (!deviceId && !directDeviceId) { console.error('Device not ready') return diff --git a/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx b/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx index b0bcf6c2..1b3715b3 100644 --- a/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx +++ b/example/src/screens/MainStack/DevicenRFTestScreen/DevicenRFTestScreen.tsx @@ -1,9 +1,9 @@ import React, { useState, type Dispatch } from 'react' -import type { TestStateType } from 'example/types' import type { NativeStackScreenProps } from '@react-navigation/native-stack' import { Device, type Base64 } from 'react-native-ble-plx' import { Platform, ScrollView } from 'react-native' import base64 from 'react-native-base64' +import type { TestStateType } from '../../../types' import { BLEService } from '../../../services' import type { MainStackParamList } from '../../../navigation/navigators' import { AppButton, AppTextInput, ScreenDefaultContainer, TestStateDisplay } from '../../../components/atoms' diff --git a/example/src/services/BLEService/BLEService.ts b/example/src/services/BLEService/BLEService.ts index aa83935f..2f175525 100644 --- a/example/src/services/BLEService/BLEService.ts +++ b/example/src/services/BLEService/BLEService.ts @@ -5,6 +5,7 @@ import { Device, State as BluetoothState, LogLevel, + type DeviceId, type TransactionId, type UUID, type Characteristic, @@ -77,7 +78,7 @@ class BLEServiceInstance { }) } - disconnectDeviceById = (id: string) => + disconnectDeviceById = (id: DeviceId) => this.manager .cancelDeviceConnection(id) .then(() => this.showSuccessToast('Device disconnected')) @@ -105,7 +106,7 @@ class BLEServiceInstance { }) } - connectToDevice = (deviceId: string) => + connectToDevice = (deviceId: DeviceId) => new Promise((resolve, reject) => { this.manager.stopDeviceScan() this.manager @@ -268,7 +269,7 @@ class BLEServiceInstance { }) } - getCharacteristicsForDevice = (serviceUUID: string) => { + getCharacteristicsForDevice = (serviceUUID: UUID) => { if (!this.device) { this.showErrorToast(deviceNotConnectedErrorText) throw new Error(deviceNotConnectedErrorText) @@ -278,7 +279,7 @@ class BLEServiceInstance { }) } - getDescriptorsForDevice = (serviceUUID: string, characteristicUUID: string) => { + getDescriptorsForDevice = (serviceUUID: UUID, characteristicUUID: UUID) => { if (!this.device) { this.showErrorToast(deviceNotConnectedErrorText) throw new Error(deviceNotConnectedErrorText) @@ -296,7 +297,7 @@ class BLEServiceInstance { return this.manager.isDeviceConnected(this.device.id) } - isDeviceWithIdConnected = (id: string) => this.manager.isDeviceConnected(id).catch(console.error) + isDeviceWithIdConnected = (id: DeviceId) => this.manager.isDeviceConnected(id).catch(console.error) getConnectedDevices = (expectedServices: UUID[]) => { if (!this.device) { @@ -349,7 +350,7 @@ class BLEServiceInstance { }) } - cancelTransaction = (transactionId: string) => this.manager.cancelTransaction(transactionId) + cancelTransaction = (transactionId: TransactionId) => this.manager.cancelTransaction(transactionId) enable = () => this.manager.enable().catch(error => { diff --git a/example/types/TestStateType.ts b/example/src/types/TestStateType.ts similarity index 100% rename from example/types/TestStateType.ts rename to example/src/types/TestStateType.ts diff --git a/example/types/index.ts b/example/src/types/index.ts similarity index 100% rename from example/types/index.ts rename to example/src/types/index.ts From 4d67f28ab7f5bfd6e5d4796d698703f9c754487a Mon Sep 17 00:00:00 2001 From: Grzegorz Miszewski Date: Wed, 11 Oct 2023 15:42:08 +0200 Subject: [PATCH 6/8] fix: fast reuse of connect to device leads to 'device not connected error' --- src/BleManager.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/BleManager.js b/src/BleManager.js index cc401555..f15e2849 100644 --- a/src/BleManager.js +++ b/src/BleManager.js @@ -457,6 +457,9 @@ export class BleManager { * @returns {Promise} Connected {@link Device} object if successful. */ async connectToDevice(deviceIdentifier: DeviceId, options: ?ConnectionOptions): Promise { + if (await this.isDeviceConnected(deviceIdentifier)) { + await this.cancelDeviceConnection(deviceIdentifier) + } const nativeDevice = await this._callPromise(BleModule.connectToDevice(deviceIdentifier, options)) return new Device(nativeDevice, this) } From c262e3d673e39b4ad3ed08bd3dcc6bd48d7517b4 Mon Sep 17 00:00:00 2001 From: Grzegorz Miszewski Date: Wed, 11 Oct 2023 15:57:04 +0200 Subject: [PATCH 7/8] fix: fast reuse of connect to device leads to 'device not connected error' (only for Android) --- src/BleManager.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BleManager.js b/src/BleManager.js index f15e2849..9f16a5b1 100644 --- a/src/BleManager.js +++ b/src/BleManager.js @@ -28,6 +28,7 @@ import type { ConnectionOptions, BleManagerOptions } from './TypeDefinition' +import { Platform } from 'react-native' const enableDisableDeprecatedMessage = 'react-native-ble-plx: The enable and disable feature is no longer supported. In Android SDK 31+ there were major changes in permissions, which may cause problems with these functions, and in SDK 33+ they were completely removed.' @@ -457,7 +458,7 @@ export class BleManager { * @returns {Promise} Connected {@link Device} object if successful. */ async connectToDevice(deviceIdentifier: DeviceId, options: ?ConnectionOptions): Promise { - if (await this.isDeviceConnected(deviceIdentifier)) { + if (Platform.OS === 'android' && (await this.isDeviceConnected(deviceIdentifier))) { await this.cancelDeviceConnection(deviceIdentifier) } const nativeDevice = await this._callPromise(BleModule.connectToDevice(deviceIdentifier, options)) From dacc4770477d394035ef1cd12388f1ac472f269a Mon Sep 17 00:00:00 2001 From: Dominik Czupryna Date: Fri, 13 Oct 2023 09:19:50 +0200 Subject: [PATCH 8/8] refactor: change numbers into variables --- .../DeviceConnectDisconnectTestScreen.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx b/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx index fee3fc83..d7af5e41 100644 --- a/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx +++ b/example/src/screens/MainStack/DeviceConnectDisconnectTestScreen/DeviceConnectDisconnectTestScreen.tsx @@ -1,6 +1,6 @@ import React, { useRef, useState } from 'react' import type { NativeStackScreenProps } from '@react-navigation/native-stack' -import { BleError, Characteristic, Device, type Subscription, type DeviceId } from 'react-native-ble-plx' +import { BleError, Characteristic, Device, type Subscription, type DeviceId, BleErrorCode } from 'react-native-ble-plx' import { ScrollView } from 'react-native' import base64 from 'react-native-base64' import Toast from 'react-native-toast-message' @@ -15,6 +15,7 @@ type DeviceConnectDisconnectTestScreenProps = NativeStackScreenProps< MainStackParamList, 'DEVICE_CONNECT_DISCONNECT_TEST_SCREEN' > +const NUMBER_OF_CALLS_IN_THE_TEST_SCENARIO = 10 export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnectTestScreenProps) { const [expectedDeviceName, setExpectedDeviceName] = useState('') @@ -66,7 +67,7 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec setTestScanDevicesState('DONE') setDeviceId(device.id) try { - for (let i = 0; i < 10; i += 1) { + for (let i = 0; i < NUMBER_OF_CALLS_IN_THE_TEST_SCENARIO; i += 1) { console.info(`connecting to ${device.id}`) await startConnectToDevice(device) setConnectCounter(prevCount => prevCount + 1) @@ -85,7 +86,7 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec setTestScanDevicesState('DONE') setDeviceId(device.id) try { - for (let i = 0; i < 10; i += 1) { + for (let i = 0; i < NUMBER_OF_CALLS_IN_THE_TEST_SCENARIO; i += 1) { await startConnectToDevice(device) console.info(`connecting to ${device.id}`) setConnectInDisconnectTestCounter(prevCount => prevCount + 1) @@ -106,7 +107,7 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec return } try { - for (let i = 0; i < 10; i += 1) { + for (let i = 0; i < NUMBER_OF_CALLS_IN_THE_TEST_SCENARIO; i += 1) { console.info(`discovering in ${deviceId}`) await startDiscoverServices() setCharacteristicDiscoverCounter(prevCount => prevCount + 1) @@ -138,7 +139,7 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec const characteristicListener = (error: BleError | null, characteristic: Characteristic | null) => { if (error) { - if (error.errorCode === 302) { + if (error.errorCode === BleErrorCode.ServiceNotFound || error.errorCode === BleErrorCode.ServicesNotDiscovered) { startDiscoverServices().then(() => startCharacteristicMonitor()) return } @@ -171,7 +172,8 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec } } - const show1103Crash = async () => { + // https://github.com/dotintent/react-native-ble-plx/issues/1103 + const showIssue1103Crash = async () => { setTestScanDevicesState('IN_PROGRESS') await BLEService.initializeBLE() await BLEService.scanDevices( @@ -208,7 +210,7 @@ export function DeviceConnectDisconnectTestScreen(_props: DeviceConnectDisconnec value={expectedDeviceName} onChangeText={setExpectedDeviceName} /> - + setupOnDeviceDisconnected()} />