Skip to content

Commit

Permalink
feat: disconnect for ios central and android peripheral
Browse files Browse the repository at this point in the history
Signed-off-by: Berend Sliedrecht <[email protected]>
  • Loading branch information
berendsliedrecht committed Aug 9, 2023
1 parent c1abff6 commit c6f42da
Show file tree
Hide file tree
Showing 18 changed files with 138 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.reactnativebledidcomm

import androidx.annotation.RequiresPermission
import com.facebook.react.bridge.*
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.reactnativebledidcomm.central.CentralManager
import com.reactnativebledidcomm.central.CentralManagerException
import com.reactnativebledidcomm.peripheral.PeripheralManager
Expand All @@ -20,7 +24,6 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
@ReactMethod
fun startCentral(
@Suppress("UNUSED_PARAMETER") options: ReadableMap,
promise: Promise,
) {
try {
this.centralManager = CentralManager(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,18 @@ class CentralManager(private val context: ReactContext) {
}
Log.d(
Constants.TAG,
"[CENTRAL]: Sending chunked message of ${chunkedMessage.size} bytes."
"[CENTRAL]: Sending chunked message of ${chunkedMessage.size} bytes.",
)
val didSend = connectedPeripheral.writeCharacteristic(characteristic)
if (didSend) {
Log.d(
Constants.TAG,
"[CENTRAL]: Send the message"
"[CENTRAL]: Send the message",
)
} else {
Log.d(
Constants.TAG,
"[CENTRAL]: Did not send the message"
"[CENTRAL]: Did not send the message",
)
}
isPeripheralReady = false
Expand All @@ -179,7 +179,7 @@ class CentralManager(private val context: ReactContext) {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
Log.d(
Constants.TAG,
"[CENTRAL]: Connection state has been changed to $newState with status $status"
"[CENTRAL]: Connection state has been changed to $newState with status $status",
)

if (status == BluetoothGatt.GATT_SUCCESS) {
Expand Down Expand Up @@ -231,7 +231,7 @@ class CentralManager(private val context: ReactContext) {
?: run {
Log.d(
Constants.TAG,
"[CENTRAL]: Indication Descriptor not found. Make sure CCC is set on the descriptor. Task of the peripheral"
"[CENTRAL]: Indication Descriptor not found. Make sure CCC is set on the descriptor. Task of the peripheral",
)
gatt.disconnect()
return
Expand Down Expand Up @@ -260,7 +260,7 @@ class CentralManager(private val context: ReactContext) {
) {
Log.d(
Constants.TAG,
"[CENTRAL]: Received an indication of ${characteristic.value.size} bytes."
"[CENTRAL]: Received an indication of ${characteristic.value.size} bytes.",
)

if (characteristic.uuid == characteristicIndicationUUID) {
Expand All @@ -282,7 +282,7 @@ class CentralManager(private val context: ReactContext) {
override fun onDescriptorWrite(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
status: Int
status: Int,
) {
super.onDescriptorWrite(gatt, descriptor, status)
Log.d(Constants.TAG, "[CENTRAL]: Descriptor write. Connection is ready")
Expand Down Expand Up @@ -317,40 +317,3 @@ class CentralManager(private val context: ReactContext) {
}
}
}





































Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.facebook.react.bridge.WritableMap
import com.facebook.react.modules.core.DeviceEventManagerModule
import com.reactnativebledidcomm.BleDidcommEvent
import com.reactnativebledidcomm.Constants
import java.util.Arrays
import java.util.UUID

class PeripheralManager(private val context: ReactContext) {
Expand Down Expand Up @@ -81,7 +82,7 @@ class PeripheralManager(private val context: ReactContext) {
)
val descriptor = BluetoothGattDescriptor(
UUID.fromString(Constants.CCC_DESCRIPTOR_UUID),
BluetoothGattDescriptor.PERMISSION_WRITE or BluetoothGattCharacteristic.PERMISSION_READ
BluetoothGattDescriptor.PERMISSION_WRITE or BluetoothGattCharacteristic.PERMISSION_READ,
)
indicationCharacteristic?.addDescriptor(descriptor)
service =
Expand Down Expand Up @@ -136,7 +137,7 @@ class PeripheralManager(private val context: ReactContext) {
isSending = true
val chunkSize = Integer.min(
connectedMtu - Constants.NUMBER_OF_BYTES_FOR_DATA_HEADER,
message.count()
message.count(),
)
for (chunkIndexStart in 0..message.count() step chunkSize) {
val chunkIndexEnd = Integer.min(chunkIndexStart + chunkSize, message.count()) - 1
Expand All @@ -147,7 +148,7 @@ class PeripheralManager(private val context: ReactContext) {
indicationCharacteristic.value = chunkedMessage
Log.d(
Constants.TAG,
"[PERIPHERAL]: Sending chunked message of ${chunkedMessage.size} bytes."
"[PERIPHERAL]: Sending chunked message of ${chunkedMessage.size} bytes.",
)
isConnectedClientReady = gattServer.notifyCharacteristicChanged(
connectedClient,
Expand All @@ -173,7 +174,7 @@ class PeripheralManager(private val context: ReactContext) {
override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
Log.d(
Constants.TAG,
"[PERIPHERAL]: Connection state has changed to $newState with status $status"
"[PERIPHERAL]: Connection state has changed to $newState with status $status",
)

if (newState == BluetoothProfile.STATE_CONNECTED) {
Expand Down Expand Up @@ -244,7 +245,7 @@ class PeripheralManager(private val context: ReactContext) {
device: BluetoothDevice,
requestId: Int,
offset: Int,
descriptor: BluetoothGattDescriptor
descriptor: BluetoothGattDescriptor,
) {
if (descriptor.uuid == UUID.fromString(Constants.CCC_DESCRIPTOR_UUID)) {
Log.d(Constants.TAG, "[PERIPHERAL]: Setting descriptor to enable indications")
Expand All @@ -253,12 +254,12 @@ class PeripheralManager(private val context: ReactContext) {
requestId,
BluetoothGatt.GATT_SUCCESS,
0,
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE,
)
} else {
Log.d(
Constants.TAG,
"[PERIPHERAL]: Tried to read descriptor which is not the indication descriptor"
"[PERIPHERAL]: Tried to read descriptor which is not the indication descriptor",
)
gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null)
}
Expand All @@ -277,25 +278,37 @@ class PeripheralManager(private val context: ReactContext) {
if (descriptor.uuid == UUID.fromString(Constants.CCC_DESCRIPTOR_UUID)) {
Log.d(
Constants.TAG,
"[PERIPHERAL]: Received a descriptor write request. Client likely wants to receive notifications."
"[PERIPHERAL]: Received a descriptor write request. Client likely wants to receive notifications or disconnect from us",
)
if (responseNeeded) {
gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null)
}
} else {
Log.d(
Constants.TAG,
"[PERIPHERAL]: Received a descriptor write request for unsupported descriptor."
"[PERIPHERAL]: Received a descriptor write request for unsupported descriptor.",
)
if (responseNeeded) {
gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null)
}
}

val params = Arguments.createMap().apply {
putString("identifier", device.address)
if (descriptor.uuid == UUID.fromString(Constants.CCC_DESCRIPTOR_UUID)) {
Log.e(Constants.TAG, "Eyo $value")
if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
Log.e(Constants.TAG, "Equal enable")
val params = Arguments.createMap().apply {
putString("identifier", device.address)
}
sendEvent(BleDidcommEvent.OnConnectedCentral, params)
} else if (Arrays.equals(value, BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)) {
Log.e(Constants.TAG, "Equal disable")
val params = Arguments.createMap().apply {
putString("identifier", device.address)
}
sendEvent(BleDidcommEvent.OnDisconnectedPeripheral, params)
}
}
sendEvent(BleDidcommEvent.OnConnectedCentral, params)
}

@SuppressLint("MissingPermission")
Expand Down Expand Up @@ -323,6 +336,6 @@ class PeripheralManager(private val context: ReactContext) {
private var gattServer: BluetoothGattServer =
bluetoothManager.openGattServer(
context,
gattServerCallback
gattServerCallback,
)
}
2 changes: 0 additions & 2 deletions example/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ module.exports = {
projectRoot: __dirname,
watchFolders: [root],

// We need to make sure that only one version is loaded for peerDependencies
// So we block them at the root, and alias them to the versions in example's node_modules
resolver: {
blacklistRE: exclusionList(
modules.map(
Expand Down
12 changes: 12 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ export default function App() {
</>
)}
<Spacer />
{(isCentral || isPeripheral) && (
<>
<Button
title="Back"
onPress={() => {
setIsCentral(false)
setIsPeripheral(false)
}}
/>
<Spacer />
</>
)}
{!isCentral && !isPeripheral && (
<>
<Button title="Central" onPress={asCentral} />
Expand Down
11 changes: 9 additions & 2 deletions example/src/Central.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { PropsWithChildren, useEffect, useMemo, useState } from 'react'
import { Button } from 'react-native'
import {
Central as BleCentral,
CentralProvider,
DEFAULT_DIDCOMM_SERVICE_UUID,
DEFAULT_DIDCOMM_MESSAGE_CHARACTERISTIC_UUID,
DEFAULT_DIDCOMM_INDICATE_CHARACTERISTIC_UUID,
Expand All @@ -16,10 +17,14 @@ import { Spacer } from './App'

const msg = 'Hello from Central!'

export const Central: React.FC<PropsWithChildren> = ({ children }) => {
export const Central: React.FC = () => {
const central = useMemo(() => new BleCentral(), [])

return <CentralProvider value={central}>{children}</CentralProvider>
return (
<CentralProvider central={central}>
<CentralChildren />
</CentralProvider>
)
}

const CentralChildren = () => {
Expand All @@ -46,6 +51,8 @@ const CentralChildren = () => {

useCentralOnDisconnected((identifier: string) => {
console.log(`[CENTRAL]: Disconnected from ${identifier}`)
setPeripheralId(undefined)
setIsConnected(false)
})

const start = central.start
Expand Down
21 changes: 14 additions & 7 deletions example/src/Peripheral.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,29 @@ import {
PeripheralProvider,
usePeripheralOnConnected,
usePeripheralOnDisconnected,
usePeripheralOnReceiveMessage,
usePeripheralOnReceivedMessage,
usePeripheralShutdownOnUnmount,
usePeripheral,
} from '@animo-id/react-native-ble-didcomm'
import { Spacer } from './App'

const msg = 'Hello from peripheral!'

export const Peripheral: React.FC<PropsWithChildren> = ({ children }) => {
const peripeheral = useMemo(() => new BlePeripheral(), [])
export const Peripheral: React.FC = () => {
const peripheral = useMemo(() => new BlePeripheral(), [])

return <PeripheralProvider value={peripheral}>{children}</PeripheralProvider>
return (
<PeripheralProvider peripheral={peripheral}>
<PeripheralChildren />
</PeripheralProvider>
)
}

const PeripheralChildren = () => {
usePeripheralShutdownOnUnmount()

const { peripheral } = usePeripheral()

const [isConnected, setIsConnected] = useState(false)

usePeripheralOnConnected((identifier: string) => {
Expand All @@ -32,11 +39,11 @@ const PeripheralChildren = () => {
})

usePeripheralOnDisconnected((identifier: string) => {
console.log(`[PERIPHERAL]: Connected to ${identifier}`)
setIsConnected(true)
console.log(`[PERIPHERAL]: Disconnected to ${identifier}`)
setIsConnected(false)
})

usePeripheralOnReceiveMessage((message: string) => {
usePeripheralOnReceivedMessage((message: string) => {
console.log(`[PERIPHERAL]: Received message: ${message}`)
})

Expand Down
5 changes: 4 additions & 1 deletion example/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"extends": "@tsconfig/react-native/tsconfig.json",
"compilerOptions": {
"skipLibCheck": true
"skipLibCheck": true,
"paths": {
"@animo-id/react-native-ble-didcomm": ["../"]
}
}
}
8 changes: 4 additions & 4 deletions ios/BleDidcomm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class BleDidcomm: React.RCTEventEmitter {
do {
try centralManager.scan()
resolve(nil)
} catch CentralManager.CentralManagerError.NoDefinedService {
} catch CentralManager.CentralManagerError.noDefinedService {
reject("error", "Set the service before calling the scan function", nil)
} catch {
reject("error", "unexpected error", nil)
Expand All @@ -170,7 +170,7 @@ class BleDidcomm: React.RCTEventEmitter {
do {
try centralManager.connect(peripheralId: peripheralId)
resolve(nil)
} catch CentralManager.CentralManagerError.PeripheralNotFound(let peripheralId) {
} catch CentralManager.CentralManagerError.peripheralNotFound(let peripheralId) {
reject("error", "Peripheral not found with id: \(peripheralId)", nil)
} catch {
reject("error", "unexpected error", nil)
Expand All @@ -195,9 +195,9 @@ class BleDidcomm: React.RCTEventEmitter {
do {
try centralManager.write(message: data)
resolve(nil)
} catch CentralManager.CentralManagerError.NotConnectedToPeripheral {
} catch CentralManager.CentralManagerError.notConnectedToPeripheral {
reject("error", "Not connected to any peripheral", nil)
} catch CentralManager.CentralManagerError.NoWriteableCharacteristicFound {
} catch CentralManager.CentralManagerError.noWriteableCharacteristicFound {
reject("error", "No writeable characteristic found", nil)
} catch {
reject("error", "unexpected error", nil)
Expand Down
Loading

0 comments on commit c6f42da

Please sign in to comment.