Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,34 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
}
}

@ReactMethod
fun stopCentral(
@Suppress("UNUSED_PARAMETER") options: ReadableMap,
promise: Promise
) {
try {
this.centralManager?.shutdownCentral()
this.centralManager = null
promise.resolve(null)
} catch (e: Exception) {
promise.reject("error", e)
}
}

@ReactMethod
fun stopPeripheral(
@Suppress("UNUSED_PARAMETER") options: ReadableMap,
promise: Promise
) {
try {
this.peripheralManager?.shutdownPeripheral()
this.peripheralManager = null
promise.resolve(null)
} catch (e: Exception) {
promise.reject("error", e)
}
}

@ReactMethod
fun setCentralService(
serviceUUID: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ class CentralManager(private val context: ReactContext) {
this.indicationCharacteristicUUID = indicationCharacteristicUUID
}

fun shutdownCentral() {
try {
this.stopScan()
} catch (e: CentralManagerException.NotScanning) {
// Not Scanning
} finally {
this.serviceUUID = null
this.writeCharacteristicUUID = null
this.indicationCharacteristicUUID = null
this.connectedPeripheral = null
this.discoveredPeripherals.clear()
}
}

@RequiresPermission(value = "android.permission.BLUETOOTH_SCAN")
fun scan(scanCallback: ScanCallback) {
if (this.scanCallback !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ class PeripheralManager(
gattServer.addService(this.service)
}

fun shutdownPeripheral() {
this.stopAdvertising()
this.writeCharacteristic = null
this.connectedClient = null
this.indicationCharacteristic = null
this.service = null
}

@RequiresPermission(value = "android.permission.BLUETOOTH_ADVERTISE")
fun advertise(advertiseCallback: AdvertiseCallback) {
val service =
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 7e2e1772ef7b97168c880eeaf3749d8c145ffd6e
React-jsinspector: 0553c9fe7218e1f127be070bd5a4d2fc19fb8190
React-logger: cffcc09e8aba8a3014be8d18da7f922802e9f19e
react-native-ble-didcomm: c69fc0a192219416d8ff791b1130b4ecbfb731a0
react-native-ble-didcomm: aaf5cf8b7ef1e946f6b2fcdcd0d07bcd936e4419
React-perflogger: 082b4293f0b3914ff41da35a6c06ac4490fcbcc8
React-RCTActionSheet: 83da3030deb5dea54b398129f56540a44e64d3ae
React-RCTAnimation: bac3a4f4c0436554d9f7fbb1352a0cdcb1fb0f1c
Expand Down
10 changes: 10 additions & 0 deletions ios/BleDidcomm.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@ @interface RCT_EXTERN_MODULE(BleDidcomm, RCTEventEmitter)
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(stopCentral
:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(startPeripheral
:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(stopPeripheral
:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(setPeripheralService
:(NSString *)serviceUUID
writeCharacteristicUUID:(NSString *)writeCharacteristicUUID
Expand Down
24 changes: 24 additions & 0 deletions ios/BleDidcomm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ class BleDidcomm: React.RCTEventEmitter {
resolve(nil)
}

@objc func stopPeripheral(
_: [String: String],
resolve: RCTPromiseResolveBlock,
reject _: RCTPromiseRejectBlock
) {
guard let peripheralManager = self.peripheralManager else {
return
}
peripheralManager.stopPeripheral()
resolve(nil)
}

@objc func setPeripheralService(
_ serviceUUID: String,
writeCharacteristicUUID: String,
Expand Down Expand Up @@ -67,6 +79,18 @@ class BleDidcomm: React.RCTEventEmitter {
resolve(nil)
}

@objc func stopCentral(
_: [String: String],
resolve: RCTPromiseResolveBlock,
reject: RCTPromiseRejectBlock
) {
guard let centralManager = self.centralManager else {
return
}
centralManager.stopCentral()
resolve(nil)
}

@objc func advertise(
_: [String: String],
resolve: RCTPromiseResolveBlock,
Expand Down
13 changes: 13 additions & 0 deletions ios/CentralManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ class CentralManager: NSObject {
)
}

func stopCentral() {
if (self.centralManager.isScanning) {
self.stopScan()
}
self.peripherals = []
self.writeCharacteristic = nil
self.connectedPeripheral = nil
self.receivedMessage = nil
self.serviceUUID = nil
self.writeCharacteristicUUID = nil
self.indicationCharacteristicUUID = nil
}

func setService(
serviceUUID: String,
writeCharacteristicUUID: String,
Expand Down
21 changes: 21 additions & 0 deletions ios/PeripheralManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ class PeripheralManager: NSObject {
while !isPoweredOn { Thread.sleep(forTimeInterval: 0.05) }
}

func stopPeripheral() {
if (self.peripheralManager.isAdvertising) {
do {
try self.stopAdvertise()
} catch {
// we don't care and proceed
}
}
self.service = nil
self.writeCharacteristic = nil
self.indicationCharacteristic = nil
self.peripheralManager.removeAllServices()
}

func setService(
serviceUUID: String, writeCharacteristicUUID: String, indicationCharacteristicUUID: String
) throws {
Expand Down Expand Up @@ -61,6 +75,13 @@ class PeripheralManager: NSObject {
self.peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [service.uuid]])
}

func stopAdvertise() throws {
guard let service = self.service else {
throw PeripheralManagerError.NoDefinedService
}
self.peripheralManager.stopAdvertising()
}

func indicate(message: Data) throws {
guard let connectedCentral = connectedCentral else {
throw PeripheralManagerError.NotConnectedToCentral
Expand Down
9 changes: 9 additions & 0 deletions src/ble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ export type ServiceOptions = {
indicationUUID: string
}

export type BLEState = {
isRunning?: boolean
isScanning?: boolean
isAdvertising?: boolean
isConnected?: boolean
}

export interface Ble {
state: BLEState
sendMessage(message: string): Promise<void>
start(): Promise<void>
setService(options: ServiceOptions): Promise<void>
getState(): BLEState
shutdown(): Promise<void>
registerMessageListener(
cb: (data: { message: string }) => void
Expand Down
26 changes: 24 additions & 2 deletions src/central.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import type { ServiceOptions, Ble } from './ble'
import type { ServiceOptions, Ble, BLEState } from './ble'
import { NativeEventEmitter, NativeModules } from 'react-native'
import { sdk } from './register'

const initialState: BLEState = {
isRunning: false,
isScanning: false,
}

export class Central implements Ble {
bleDidcommEmitter = new NativeEventEmitter(NativeModules.BleDidcomm)
state: BLEState = initialState

public getState(): BLEState {
try {
return this.state
} catch (e) {
throw new Error('An error occurred setting internal module state: ' + e)
}
}

public async sendMessage(message: string) {
try {
Expand All @@ -16,6 +30,7 @@ export class Central implements Ble {
public async start() {
try {
await sdk.startCentral({})
this.state.isRunning = true
} catch (e) {
throw new Error('An error occurred during startup: ' + e)
}
Expand All @@ -35,7 +50,12 @@ export class Central implements Ble {

public async shutdown() {
// TODO: Implement native
throw new Error('Not implemented')
try {
await sdk.shutdownCentral({})
} catch (e) {
throw new Error('Failed to shutdown central: ' + e)
}
this.state = initialState
}

registerMessageListener(cb: (data: { message: string }) => void) {
Expand All @@ -50,6 +70,7 @@ export class Central implements Ble {
public async scan() {
try {
await sdk.scan({})
this.state.isScanning = true
} catch (e) {
throw new Error('An error occurred while scanning for devices: ' + e)
}
Expand All @@ -58,6 +79,7 @@ export class Central implements Ble {
public async connect(peripheralId: string) {
try {
await sdk.connect(peripheralId)
this.state.isConnected = true
} catch (e) {
throw new Error(
`An error occurred while trying to connect to ${peripheralId}: ` + e
Expand Down
26 changes: 23 additions & 3 deletions src/peripheral.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import type { Ble, ServiceOptions } from './ble'
import type { Ble, BLEState, ServiceOptions } from './ble'
import { NativeEventEmitter, NativeModules } from 'react-native'
import { sdk } from './register'

const initialState: BLEState = {
isRunning: false,
isAdvertising: false,
}

export class Peripheral implements Ble {
bleDidcommEmitter = new NativeEventEmitter(NativeModules.BleDidcomm)
state: BLEState = initialState

public getState(): BLEState {
try {
return this.state
} catch (e) {
throw new Error('An error occurred setting internal module state: ' + e)
}
}

public async sendMessage(message: string) {
try {
Expand All @@ -16,6 +30,7 @@ export class Peripheral implements Ble {
public async start() {
try {
await sdk.startPeripheral({})
this.state.isRunning = true
} catch (e) {
throw new Error('An error occurred during startup: ' + e)
}
Expand All @@ -34,13 +49,18 @@ export class Peripheral implements Ble {
}

public async shutdown() {
// TODO: Implement native
throw new Error('Not implemented')
try {
await sdk.shutdownPeripheral({})
} catch (e) {
throw new Error('Failed to shutdown peripheral: ' + e)
}
this.state = initialState
}

public async advertise() {
try {
await sdk.advertise({})
this.state.isAdvertising = true
} catch (e) {
throw new Error('An error occurred while trying to advertise: ' + e)
}
Expand Down
4 changes: 4 additions & 0 deletions src/register.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { NativeModules, Platform } from 'react-native'
import type { BLEState } from './ble'

const LINKING_ERROR =
'The package "react-native-ble-didcomm" doesn\'t seem to be linked. Make sure: \n\n' +
Expand All @@ -25,6 +26,7 @@ type Sdk = {
characteristicUUID: string,
notifyCharacteristicUUID: string
): Promise<void>
getState(): BLEState
setPeripheralService(
serviceUUID: string,
characteristicUUID: string,
Expand All @@ -33,7 +35,9 @@ type Sdk = {
shutdownCentral({}: Record<never, never>): Promise<void>
shutdownPeripheral({}: Record<never, never>): Promise<void>
scan({}: Record<never, never>): Promise<void>
stopScan(): void
advertise({}: Record<never, never>): Promise<void>
stopAdvertise(): Promise<void>
connect(peripheralId: string): Promise<void>
write(message: string): Promise<void>
indicate(message: string): Promise<void>
Expand Down