Skip to content

Commit fed2a79

Browse files
berendsliedrechtBerend Sliedrecht
andauthored
fix: android ios interoperability (#65)
* fix(ios): wait for poweron state Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): typo in android event names Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): minor cleanup Signed-off-by: Berend Sliedrecht <[email protected]> * style(android): ran ktlint Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): set the descriptor when the mtu is changed Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): expected a body class Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): peripheral trigger on connect when mtu is set Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): call order Signed-off-by: Berend Sliedrecht <[email protected]> * fix(ios): minor cleanup Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): do not reconfigure the chunksize Signed-off-by: Berend Sliedrecht <[email protected]> * fix(android): remove log Signed-off-by: Berend Sliedrecht <[email protected]> --------- Signed-off-by: Berend Sliedrecht <[email protected]> Co-authored-by: Berend Sliedrecht <[email protected]>
1 parent 6eb258c commit fed2a79

File tree

9 files changed

+122
-95
lines changed

9 files changed

+122
-95
lines changed

android/src/main/java/com/reactnativebledidcomm/BleDidcommEvent.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ package com.reactnativebledidcomm
33
enum class BleDidcommEvent(val token: String) {
44
OnDiscoverPeripheral("onDiscoverPeripheral"),
55
OnConnectedPeripheral("onConnectedPeripheral"),
6-
OnConnectedCentral("OnConnectedCentral"),
6+
OnConnectedCentral("onConnectedCentral"),
77
OnReceivedWriteWithoutResponse("onReceivedWriteWithoutResponse"),
88
OnReceivedNotification("onReceivedNotification"),
9-
OnDisconnectedPeripheral("OnDisconnectedPeripheral"),
10-
OnDisconnectedCentral("OnDisconnectedCentral")
9+
OnDisconnectedPeripheral("onDisconnectedPeripheral"),
10+
OnDisconnectedCentral("onDisconnectedCentral"),
1111
}

android/src/main/java/com/reactnativebledidcomm/BleDidcommModule.kt

Lines changed: 78 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import com.reactnativebledidcomm.peripheral.PeripheralManager
1515
import com.reactnativebledidcomm.peripheral.PeripheralManagerException
1616
import java.util.*
1717

18-
1918
class BleDidcommModule(private val context: ReactApplicationContext) :
2019
ReactContextBaseJavaModule(context) {
2120
private var centralManager: CentralManager? = null
@@ -28,7 +27,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
2827
@ReactMethod
2928
fun startCentral(
3029
@Suppress("UNUSED_PARAMETER") options: ReadableMap,
31-
promise: Promise
30+
promise: Promise,
3231
) {
3332
try {
3433
this.centralManager = CentralManager(context)
@@ -42,10 +41,10 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
4241
@RequiresPermission(value = "android.permission.BLUETOOTH_CONNECT")
4342
fun startPeripheral(
4443
@Suppress("UNUSED_PARAMETER") options: ReadableMap,
45-
promise: Promise
44+
promise: Promise,
4645
) {
4746
try {
48-
this.peripheralManager = PeripheralManager(context, GattServerCallback())
47+
this.peripheralManager = PeripheralManager(context, gattServerCallback)
4948
promise.resolve(null)
5049
} catch (e: Exception) {
5150
promise.reject("error", e)
@@ -55,7 +54,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
5554
@ReactMethod
5655
fun shutdownCentral(
5756
@Suppress("UNUSED_PARAMETER") options: ReadableMap,
58-
promise: Promise
57+
promise: Promise,
5958
) {
6059
try {
6160
this.centralManager?.shutdownCentral()
@@ -69,7 +68,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
6968
@ReactMethod
7069
fun shutdownPeripheral(
7170
@Suppress("UNUSED_PARAMETER") options: ReadableMap,
72-
promise: Promise
71+
promise: Promise,
7372
) {
7473
try {
7574
this.peripheralManager?.shutdownPeripheral()
@@ -85,15 +84,15 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
8584
serviceUUID: String,
8685
writeCharacteristicUUID: String,
8786
indicationCharacteristicUUID: String,
88-
promise: Promise
87+
promise: Promise,
8988
) {
9089
try {
9190
val centralManager =
9291
this.centralManager ?: throw CentralManagerException.NotStarted()
9392
centralManager.setService(
9493
UUID.fromString(serviceUUID),
9594
UUID.fromString(writeCharacteristicUUID),
96-
UUID.fromString(indicationCharacteristicUUID)
95+
UUID.fromString(indicationCharacteristicUUID),
9796
)
9897
promise.resolve(null)
9998
} catch (e: Exception) {
@@ -106,15 +105,15 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
106105
serviceUUID: String,
107106
writeCharacteristicUUID: String,
108107
indicationCharacteristicUUID: String,
109-
promise: Promise
108+
promise: Promise,
110109
) {
111110
try {
112111
val peripheralManager =
113112
this.peripheralManager ?: throw PeripheralManagerException.NotStarted()
114113
peripheralManager.setService(
115114
UUID.fromString(serviceUUID),
116115
UUID.fromString(writeCharacteristicUUID),
117-
UUID.fromString(indicationCharacteristicUUID)
116+
UUID.fromString(indicationCharacteristicUUID),
118117
)
119118
promise.resolve(null)
120119
} catch (e: Exception) {
@@ -128,7 +127,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
128127
try {
129128
val centralManager =
130129
this.centralManager ?: throw CentralManagerException.NotStarted()
131-
centralManager.scan(BluetoothScanCallback())
130+
centralManager.scan(bluetoothScanCallback)
132131
promise.resolve(null)
133132
} catch (e: Exception) {
134133
promise.reject("error", e)
@@ -141,7 +140,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
141140
try {
142141
val peripheralManager =
143142
this.peripheralManager ?: throw PeripheralManagerException.NotStarted()
144-
peripheralManager.advertise(DeviceAdvertiseCallback())
143+
peripheralManager.advertise(deviceAdvertiseCallback)
145144
promise.resolve(null)
146145
} catch (e: Exception) {
147146
promise.reject("error", e)
@@ -154,7 +153,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
154153
try {
155154
val centralManager =
156155
this.centralManager ?: throw CentralManagerException.NotStarted()
157-
centralManager.connect(peripheralId, GattClientCallback())
156+
centralManager.connect(peripheralId, gattClientCallback)
158157
promise.resolve(null)
159158
} catch (e: Exception) {
160159
promise.reject("error", e)
@@ -187,12 +186,10 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
187186
}
188187
}
189188

190-
191189
@ReactMethod
192190
fun addListener(@Suppress("UNUSED_PARAMETER") eventName: String) {
193191
}
194192

195-
196193
@ReactMethod
197194
fun removeListeners(@Suppress("UNUSED_PARAMETER") count: Int) {
198195
}
@@ -203,12 +200,13 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
203200
.emit(event.token, params)
204201
}
205202

206-
private inner class GattClientCallback : BluetoothGattCallback() {
203+
private val gattClientCallback = object : BluetoothGattCallback() {
207204
var message: ByteArray = byteArrayOf()
208205

206+
// Triggered when client receives an indication
209207
override fun onCharacteristicChanged(
210208
gatt: BluetoothGatt,
211-
characteristic: BluetoothGattCharacteristic
209+
characteristic: BluetoothGattCharacteristic,
212210
) {
213211
super.onCharacteristicChanged(gatt, characteristic)
214212
val msg = characteristic.value
@@ -223,61 +221,68 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
223221
}
224222
}
225223

224+
// Triggered when the client is ready to send the next message
226225
override fun onCharacteristicWrite(
227226
gatt: BluetoothGatt,
228227
characteristic: BluetoothGattCharacteristic,
229-
status: Int
228+
status: Int,
230229
) {
231230
super.onCharacteristicWrite(gatt, characteristic, status)
232231
if (status == BluetoothGatt.GATT_SUCCESS) {
233232
centralManager?.isPeripheralReady = true
234233
}
235234
}
236235

236+
// Triggered when the MTU has been changed.
237237
@SuppressLint("MissingPermission")
238-
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
238+
override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
239239
super.onMtuChanged(gatt, mtu, status)
240240
if (status != BluetoothGatt.GATT_SUCCESS) {
241241
Log.e(Constants.TAG, "error occurred while requesting MTU. Status $status")
242242
return
243243
}
244244
centralManager?.connectedMtu = mtu
245-
val descriptor =
246-
centralManager?.indicationCharacteristic?.getDescriptor(UUID.fromString(Constants.CCC_DESCRIPTOR_UUID))
247-
descriptor?.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
248-
gatt?.writeDescriptor(descriptor)
245+
gatt.discoverServices()
249246
}
250247

248+
// Triggered when client discovered services
251249
@SuppressLint("MissingPermission")
252250
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
253251
super.onServicesDiscovered(gatt, status)
254252
val service = gatt.getService(centralManager?.serviceUUID)
253+
255254
centralManager?.writeCharacteristic =
256255
service.getCharacteristic(centralManager?.writeCharacteristicUUID)
256+
257257
centralManager?.indicationCharacteristic =
258258
service.getCharacteristic(centralManager?.indicationCharacteristicUUID)
259-
gatt.setCharacteristicNotification(centralManager?.indicationCharacteristic, true)
260-
gatt.requestMtu(512)
259+
260+
val indicationCharacteristic = centralManager?.indicationCharacteristic ?: return
261+
gatt.setCharacteristicNotification(indicationCharacteristic, true)
262+
val descriptor = indicationCharacteristic.getDescriptor(UUID.fromString(Constants.CCC_DESCRIPTOR_UUID))
263+
descriptor?.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
264+
gatt.writeDescriptor(descriptor)
261265
}
262266

267+
// Triggered when the connection state is updated
263268
@SuppressLint("MissingPermission")
264269
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
265270
super.onConnectionStateChange(gatt, status, newState)
266271
val params = Arguments.createMap().apply {
267272
putString("identifier", gatt.device.address)
268273
}
269274
if (newState == BluetoothProfile.STATE_CONNECTED) {
270-
sendEvent(BleDidcommEvent.OnConnectedPeripheral, params)
271-
gatt.discoverServices()
275+
gatt.requestMtu(512)
272276
centralManager?.stopScan()
277+
sendEvent(BleDidcommEvent.OnConnectedPeripheral, params)
273278
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
274279
sendEvent(BleDidcommEvent.OnDisconnectedPeripheral, params)
275280
centralManager?.connectedPeripheral = null
276281
}
277282
}
278283
}
279284

280-
private inner class BluetoothScanCallback : ScanCallback() {
285+
private val bluetoothScanCallback = object : ScanCallback() {
281286
override fun onScanResult(callbackType: Int, result: ScanResult?) {
282287
super.onScanResult(callbackType, result)
283288
val device = result?.device ?: return
@@ -289,9 +294,17 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
289294
}
290295
}
291296

292-
private inner class GattServerCallback : BluetoothGattServerCallback() {
297+
private val gattServerCallback = object : BluetoothGattServerCallback() {
293298
var message: ByteArray = byteArrayOf()
294299

300+
// Triggered when the mtu is updated for the peripheral
301+
override fun onMtuChanged(device: BluetoothDevice, mtu: Int) {
302+
super.onMtuChanged(device, mtu)
303+
peripheralManager?.connectedMtu = mtu
304+
}
305+
306+
// Triggered the peripheral received a write request.
307+
// It appends it to a buffer and when "EOM" is received, it will emit a React Native event
295308
@SuppressLint("MissingPermission")
296309
override fun onCharacteristicWriteRequest(
297310
device: BluetoothDevice,
@@ -300,7 +313,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
300313
preparedWrite: Boolean,
301314
responseNeeded: Boolean,
302315
offset: Int,
303-
value: ByteArray
316+
value: ByteArray,
304317
) {
305318
super.onCharacteristicWriteRequest(
306319
device,
@@ -309,7 +322,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
309322
preparedWrite,
310323
responseNeeded,
311324
offset,
312-
value
325+
value,
313326
)
314327

315328
if ("EOM" == value.toString(Charsets.UTF_8)) {
@@ -328,18 +341,44 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
328341
requestId,
329342
BluetoothGatt.GATT_SUCCESS,
330343
offset,
331-
value
344+
value,
332345
)
333346
}
334347
}
335348

349+
override fun onDescriptorWriteRequest(
350+
device: BluetoothDevice,
351+
requestId: Int,
352+
descriptor: BluetoothGattDescriptor,
353+
preparedWrite: Boolean,
354+
responseNeeded: Boolean,
355+
offset: Int,
356+
value: ByteArray,
357+
) {
358+
super.onDescriptorWriteRequest(
359+
device,
360+
requestId,
361+
descriptor,
362+
preparedWrite,
363+
responseNeeded,
364+
offset,
365+
value,
366+
)
367+
val params = Arguments.createMap().apply {
368+
putString("identifier", device.address)
369+
}
370+
sendEvent(BleDidcommEvent.OnConnectedCentral, params)
371+
}
372+
373+
// Triggered when the peripheral is ready to send again
336374
override fun onNotificationSent(device: BluetoothDevice?, status: Int) {
337375
super.onNotificationSent(device, status)
338376
if (status == BluetoothGatt.GATT_SUCCESS) {
339377
peripheralManager?.isConnectedClientReady = true
340378
}
341379
}
342380

381+
// TODO: can we do this without this function?
343382
@SuppressLint("MissingPermission")
344383
override fun onExecuteWrite(device: BluetoothDevice?, requestId: Int, execute: Boolean) {
345384
super.onExecuteWrite(device, requestId, execute)
@@ -348,46 +387,25 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
348387
requestId,
349388
BluetoothGatt.GATT_SUCCESS,
350389
0,
351-
null
390+
null,
352391
)
353392
}
354393

394+
// Triggered when the connection state is updated for the peripheral
355395
@SuppressLint("MissingPermission")
356396
override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
357397
super.onConnectionStateChange(device, status, newState)
358-
val params = Arguments.createMap().apply {
359-
putString("identifier", device.address)
360-
}
361398
if (newState == BluetoothProfile.STATE_CONNECTED) {
362399
peripheralManager?.connectedClient = device
363-
peripheralManager?.gattClientCallback = GattClientMtuOnlyCallback()
364-
device.connectGatt(context, false, peripheralManager?.gattClientCallback)
365-
sendEvent(BleDidcommEvent.OnConnectedCentral, params)
366400
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
367-
sendEvent(BleDidcommEvent.OnDisconnectedCentral, params)
368401
peripheralManager?.connectedClient = null
402+
val params = Arguments.createMap().apply {
403+
putString("identifier", device.address)
404+
}
405+
sendEvent(BleDidcommEvent.OnDisconnectedCentral, params)
369406
}
370407
}
371408
}
372409

373-
private inner class GattClientMtuOnlyCallback : BluetoothGattCallback() {
374-
@SuppressLint("MissingPermission")
375-
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
376-
super.onConnectionStateChange(gatt, status, newState)
377-
if (newState == BluetoothProfile.STATE_CONNECTED) {
378-
gatt.requestMtu(512)
379-
}
380-
}
381-
382-
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
383-
super.onMtuChanged(gatt, mtu, status)
384-
if (status != BluetoothGatt.GATT_SUCCESS) {
385-
Log.e(Constants.TAG, "error occurred while requesting the MTU. Status: $status")
386-
return
387-
}
388-
peripheralManager?.connectedMtu = mtu
389-
}
390-
}
391-
392-
private inner class DeviceAdvertiseCallback : AdvertiseCallback()
410+
private val deviceAdvertiseCallback = object : AdvertiseCallback() {}
393411
}

android/src/main/java/com/reactnativebledidcomm/Constants.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object Constants {
99
const val TAG = "BleDidcomm"
1010
const val CCC_DESCRIPTOR_UUID = "00002902-0000-1000-8000-00805f9b34fb"
1111

12-
/* The number of bytes we adjust for in the chunking algorithm to account for the data header
12+
/* The number of bytes we adjust for in the chunking algorithm to account for the data header
1313
(3 bytes) + 9 extra bytes to be sure = 12 bytes */
1414
const val NUMBER_OF_BYTES_FOR_DATA_HEADER = 12
1515
}

android/src/main/java/com/reactnativebledidcomm/central/CentralManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class CentralManager(private val context: ReactContext) {
3838
fun setService(
3939
serviceUUID: UUID,
4040
writeCharacteristicUUID: UUID,
41-
indicationCharacteristicUUID: UUID
41+
indicationCharacteristicUUID: UUID,
4242
) {
4343
this.serviceUUID = serviceUUID
4444
this.writeCharacteristicUUID = writeCharacteristicUUID

0 commit comments

Comments
 (0)