react-native-ble-manager 7.6.1 → 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Before open an issue**
11
+ - Check the closed issues, your question maybe is not new.
12
+ - We can't debug or reproduce hardware issue.
13
+ - If the library is not working 99% you did something wrong, in the code, installation or in the phone permissions.
14
+
15
+ **Describe the bug**
16
+ A clear and concise description of what the bug is.
17
+
18
+ **To Reproduce**
19
+ Steps to reproduce the behavior:
20
+ 1. Go to '...'
21
+ 2. Click on '....'
22
+ 3. Scroll down to '....'
23
+ 4. See error
24
+
25
+ **Expected behavior**
26
+ A clear and concise description of what you expected to happen.
27
+
28
+ **Screenshots**
29
+ If applicable, add screenshots to help explain your problem.
30
+
31
+ **Smartphone (please complete the following information):**
32
+ - Device: [e.g. iPhone6]
33
+ - OS: [e.g. iOS8.1]
34
+ - react-native-ble-manager version:
35
+ - react-native version:
36
+
37
+ **Additional context**
38
+ Add any other context about the problem here.
package/README.md CHANGED
@@ -22,8 +22,8 @@ RN 0.30-0.39 supported until 2.4.3
22
22
 
23
23
  ```shell
24
24
  npm i --save react-native-ble-manager
25
- npx react-native link
26
25
  ```
26
+ The library support the react native autolink feature.
27
27
 
28
28
 
29
29
  ##### Android - Update Manifest
@@ -9,7 +9,7 @@ buildscript {
9
9
  }
10
10
 
11
11
  dependencies {
12
- classpath("com.android.tools.build:gradle:3.6.1")
12
+ classpath("com.android.tools.build:gradle:4.2.2")
13
13
  }
14
14
  }
15
15
  }
@@ -20,7 +20,7 @@ def safeExtGet(prop, fallback) {
20
20
  }
21
21
 
22
22
  android {
23
- compileSdkVersion safeExtGet("compileSdkVersion", 29)
23
+ compileSdkVersion safeExtGet("compileSdkVersion", 30)
24
24
 
25
25
  defaultConfig {
26
26
  minSdkVersion safeExtGet("minSdkVersion", 21)
@@ -36,8 +36,8 @@ repositories {
36
36
  jcenter()
37
37
  maven {
38
38
  // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
39
- url "$rootDir/../node_modules/react-native/android"
40
- // To test url "$rootDir/../example/node_modules/react-native/android"
39
+ //url "$rootDir/../node_modules/react-native/android"
40
+ url "$rootDir/../example/node_modules/react-native/android"
41
41
  }
42
42
  }
43
43
 
@@ -722,4 +722,14 @@ class BleManager extends ReactContextBaseJavaModule {
722
722
  return peripheral;
723
723
  }
724
724
 
725
+ @ReactMethod
726
+ public void addListener(String eventName) {
727
+ // Keep: Required for RN built in Event Emitter Calls.
728
+ }
729
+
730
+ @ReactMethod
731
+ public void removeListeners(Integer count) {
732
+ // Keep: Required for RN built in Event Emitter Calls.
733
+ }
734
+
725
735
  }
@@ -33,6 +33,8 @@ import java.util.Arrays;
33
33
  import java.util.Iterator;
34
34
  import java.util.List;
35
35
  import java.util.UUID;
36
+ import java.util.Queue;
37
+ import java.util.concurrent.ConcurrentLinkedQueue;
36
38
 
37
39
  import static android.os.Build.VERSION_CODES.LOLLIPOP;
38
40
  import static com.facebook.react.common.ReactConstants.TAG;
@@ -43,6 +45,8 @@ import static com.facebook.react.common.ReactConstants.TAG;
43
45
  public class Peripheral extends BluetoothGattCallback {
44
46
 
45
47
  private static final String CHARACTERISTIC_NOTIFICATION_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
48
+ public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5;
49
+ public static final int GATT_AUTH_FAIL = 137;
46
50
 
47
51
  private final BluetoothDevice device;
48
52
  private final Map<String, NotifyBufferContainer> bufferedCharacteristics;
@@ -61,6 +65,11 @@ public class Peripheral extends BluetoothGattCallback {
61
65
  private Callback registerNotifyCallback;
62
66
  private Callback requestMTUCallback;
63
67
 
68
+ private final Queue<Runnable> commandQueue = new ConcurrentLinkedQueue<>();
69
+ private final Handler mainHandler = new Handler(Looper.getMainLooper());
70
+ private Runnable discoverServicesRunnable;
71
+ private boolean commandQueueBusy = false;
72
+
64
73
  private List<byte[]> writeQueue = new ArrayList<>();
65
74
 
66
75
  public Peripheral(BluetoothDevice device, int advertisingRSSI, byte[] scanRecord, ReactContext reactContext) {
@@ -127,6 +136,9 @@ public class Peripheral extends BluetoothGattCallback {
127
136
  connectCallback = null;
128
137
  connected = false;
129
138
  clearBuffers();
139
+ commandQueue.clear();
140
+ commandQueueBusy = false;
141
+
130
142
  if (gatt != null) {
131
143
  try {
132
144
  gatt.disconnect();
@@ -272,11 +284,27 @@ public class Peripheral extends BluetoothGattCallback {
272
284
 
273
285
  if (status != BluetoothGatt.GATT_SUCCESS) {
274
286
  gatt.close();
287
+ // change the state to ensure the connection is teared down properly in the code below
288
+ newState = BluetoothProfile.STATE_DISCONNECTED;
275
289
  }
276
290
 
277
291
  if (newState == BluetoothProfile.STATE_CONNECTED) {
278
292
  connected = true;
279
293
 
294
+ discoverServicesRunnable = new Runnable() {
295
+ @Override
296
+ public void run() {
297
+ try {
298
+ gatt.discoverServices();
299
+ } catch (NullPointerException e) {
300
+ Log.d(BleManager.LOG_TAG, "onConnectionStateChange connected but gatt of Run method was null");
301
+ }
302
+ discoverServicesRunnable = null;
303
+ }
304
+ };
305
+
306
+ mainHandler.post(discoverServicesRunnable);
307
+
280
308
  sendConnectionEvent(device, "BleManagerConnectPeripheral", status);
281
309
 
282
310
  if (connectCallback != null) {
@@ -287,9 +315,11 @@ public class Peripheral extends BluetoothGattCallback {
287
315
 
288
316
  } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
289
317
 
290
- this.disconnect(true);
318
+ if (discoverServicesRunnable != null) {
319
+ mainHandler.removeCallbacks(discoverServicesRunnable);
320
+ discoverServicesRunnable = null;
321
+ }
291
322
 
292
- sendConnectionEvent(device, "BleManagerDisconnectPeripheral", status);
293
323
  List<Callback> callbacks = Arrays.asList(writeCallback, retrieveServicesCallback, readRSSICallback,
294
324
  readCallback, registerNotifyCallback, requestMTUCallback);
295
325
  for (Callback currentCallback : callbacks) {
@@ -308,6 +338,10 @@ public class Peripheral extends BluetoothGattCallback {
308
338
  readRSSICallback = null;
309
339
  registerNotifyCallback = null;
310
340
  requestMTUCallback = null;
341
+ commandQueue.clear();
342
+ commandQueueBusy = false;
343
+
344
+ this.disconnect(true);
311
345
  }
312
346
 
313
347
  }
@@ -367,54 +401,60 @@ public class Peripheral extends BluetoothGattCallback {
367
401
  @Override
368
402
  public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
369
403
  super.onCharacteristicRead(gatt, characteristic, status);
370
- Log.d(BleManager.LOG_TAG, "onCharacteristicRead " + characteristic);
371
-
372
- if (readCallback != null) {
373
404
 
374
- if (status == BluetoothGatt.GATT_SUCCESS) {
375
- byte[] dataValue = characteristic.getValue();
376
-
377
- if (readCallback != null) {
378
- readCallback.invoke(null, BleManager.bytesToWritableArray(dataValue));
379
- }
380
- } else {
381
- readCallback.invoke("Error reading " + characteristic.getUuid() + " status=" + status, null);
405
+ if (status != BluetoothGatt.GATT_SUCCESS) {
406
+ if (status == GATT_AUTH_FAIL || status == GATT_INSUFFICIENT_AUTHENTICATION) {
407
+ Log.d(BleManager.LOG_TAG, "Read needs bonding");
408
+ // *not* doing completedCommand()
409
+ return;
382
410
  }
383
-
411
+ sendBackrError(readCallback, "Error reading " + characteristic.getUuid() + " status=" + status);
412
+ } else if (readCallback != null) {
413
+ final byte[] dataValue = copyOf(characteristic.getValue());
414
+ final Callback callback = readCallback;
384
415
  readCallback = null;
385
-
416
+ mainHandler.post(new Runnable() {
417
+ @Override
418
+ public void run() {
419
+ callback.invoke(null, BleManager.bytesToWritableArray(dataValue));
420
+ }
421
+ });
386
422
  }
423
+
424
+ completedCommand();
387
425
  }
388
426
 
389
427
  @Override
390
428
  public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
391
429
  super.onCharacteristicWrite(gatt, characteristic, status);
392
430
 
393
- if (writeCallback != null) {
394
-
395
- if (writeQueue.size() > 0) {
396
- byte[] data = writeQueue.get(0);
397
- writeQueue.remove(0);
398
- doWrite(characteristic, data);
399
- } else {
400
-
401
- if (status == BluetoothGatt.GATT_SUCCESS) {
402
- writeCallback.invoke();
403
- } else {
404
- Log.e(BleManager.LOG_TAG, "Error onCharacteristicWrite:" + status);
405
- writeCallback.invoke("Error writing status: " + status);
406
- }
407
-
408
- writeCallback = null;
431
+ if (writeQueue.size() > 0) {
432
+ byte[] data = writeQueue.get(0);
433
+ writeQueue.remove(0);
434
+ doWrite(characteristic, data, writeCallback);
435
+ } else if (status != BluetoothGatt.GATT_SUCCESS) {
436
+ if (status == GATT_AUTH_FAIL || status == GATT_INSUFFICIENT_AUTHENTICATION) {
437
+ Log.d(BleManager.LOG_TAG, "Write needs bonding");
438
+ // *not* doing completedCommand()
439
+ return;
409
440
  }
410
- } else {
411
- Log.e(BleManager.LOG_TAG, "No callback on write");
441
+ sendBackrError(writeCallback, "Error writing " + characteristic.getUuid() + " status=" + status);
442
+ } else if (writeCallback != null) {
443
+ final Callback callback = writeCallback;
444
+ mainHandler.post(new Runnable() {
445
+ @Override
446
+ public void run() {
447
+ callback.invoke();
448
+ }
449
+ });
450
+ writeCallback = null;
412
451
  }
452
+
453
+ completedCommand();
413
454
  }
414
455
 
415
456
  @Override
416
457
  public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
417
- super.onDescriptorWrite(gatt, descriptor, status);
418
458
  if (registerNotifyCallback != null) {
419
459
  if (status == BluetoothGatt.GATT_SUCCESS) {
420
460
  registerNotifyCallback.invoke();
@@ -428,6 +468,8 @@ public class Peripheral extends BluetoothGattCallback {
428
468
  } else {
429
469
  Log.e(BleManager.LOG_TAG, "onDescriptorWrite with no callback");
430
470
  }
471
+
472
+ completedCommand();
431
473
  }
432
474
 
433
475
  @Override
@@ -454,85 +496,90 @@ public class Peripheral extends BluetoothGattCallback {
454
496
  entry.getValue().resetBuffer();
455
497
  }
456
498
 
457
- private void setNotify(UUID serviceUUID, UUID characteristicUUID, Boolean notify, Integer buffer,
458
- Callback callback) {
459
- if (!isConnected()) {
499
+ private void setNotify(UUID serviceUUID, UUID characteristicUUID, final Boolean notify, Callback callback) {
500
+ if (! isConnected() || gatt == null) {
460
501
  callback.invoke("Device is not connected", null);
461
502
  return;
462
503
  }
463
- Log.d(BleManager.LOG_TAG, "setNotify");
464
504
 
465
- if (gatt == null) {
466
- callback.invoke("BluetoothGatt is null");
505
+ BluetoothGattService service = gatt.getService(serviceUUID);
506
+ final BluetoothGattCharacteristic characteristic = findNotifyCharacteristic(service, characteristicUUID);
507
+
508
+ if (characteristic == null) {
509
+ callback.invoke("Characteristic " + characteristicUUID + " not found");
510
+ return;
511
+ }
512
+
513
+ if (! gatt.setCharacteristicNotification(characteristic, notify)) {
514
+ callback.invoke("Failed to register notification for " + characteristicUUID);
467
515
  return;
468
516
  }
469
- BluetoothGattService service = gatt.getService(serviceUUID);
470
- BluetoothGattCharacteristic characteristic = findNotifyCharacteristic(service, characteristicUUID);
471
517
 
472
- if (characteristic != null) {
473
- if (gatt.setCharacteristicNotification(characteristic, notify)) {
518
+ final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUIDHelper.uuidFromString(CHARACTERISTIC_NOTIFICATION_CONFIG));
519
+ if (descriptor == null) {
520
+ callback.invoke("Set notification failed for " + characteristicUUID);
521
+ return;
522
+ }
474
523
 
475
- if (buffer > 1) {
476
- Log.d(BleManager.LOG_TAG, "Characteristic buffering " + characteristicUUID + " count:" + buffer);
477
- String key = this.bufferedCharacteristicsKey(serviceUUID.toString(), characteristicUUID.toString());
478
- this.bufferedCharacteristics.put(key, new NotifyBufferContainer(key, buffer));
479
- }
524
+ // Prefer notify over indicate
525
+ byte[] value;
526
+ if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
527
+ Log.d(BleManager.LOG_TAG, "Characteristic " + characteristicUUID + " set NOTIFY");
528
+ value = notify ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
529
+ } else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
530
+ Log.d(BleManager.LOG_TAG, "Characteristic " + characteristicUUID + " set INDICATE");
531
+ value = notify ? BluetoothGattDescriptor.ENABLE_INDICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
532
+ } else {
533
+ String msg = "Characteristic " + characteristicUUID + " does not have NOTIFY or INDICATE property set";
534
+ Log.d(BleManager.LOG_TAG, msg);
535
+ callback.invoke(msg);
536
+ return;
537
+ }
538
+ final byte[] finalValue = notify ? value : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
539
+ final Callback finalCallback = callback;
480
540
 
481
- BluetoothGattDescriptor descriptor = characteristic
482
- .getDescriptor(UUIDHelper.uuidFromString(CHARACTERISTIC_NOTIFICATION_CONFIG));
483
- if (descriptor != null) {
484
-
485
- // Prefer notify over indicate
486
- if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
487
- Log.d(BleManager.LOG_TAG, "Characteristic " + characteristicUUID + " set NOTIFY");
488
- descriptor.setValue(notify ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
489
- : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
490
- } else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
491
- Log.d(BleManager.LOG_TAG, "Characteristic " + characteristicUUID + " set INDICATE");
492
- descriptor.setValue(notify ? BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
493
- : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
494
- } else {
495
- Log.d(BleManager.LOG_TAG, "Characteristic " + characteristicUUID
496
- + " does not have NOTIFY or INDICATE property set");
541
+ boolean result = commandQueue.add(new Runnable() {
542
+ @Override
543
+ public void run() {
544
+ if (! isConnected()) {
545
+ completedCommand();
546
+ return;
497
547
  }
498
548
 
549
+ boolean result = false;
499
550
  try {
500
- registerNotifyCallback = callback;
501
- if (gatt.writeDescriptor(descriptor)) {
502
- Log.d(BleManager.LOG_TAG, "setNotify complete");
503
- } else {
504
- registerNotifyCallback = null;
505
- callback.invoke(
506
- "Failed to set client characteristic notification for " + characteristicUUID);
507
- }
508
- } catch (Exception e) {
509
- Log.d(BleManager.LOG_TAG, "Error on setNotify", e);
510
- callback.invoke("Failed to set client characteristic notification for " + characteristicUUID
511
- + ", error: " + e.getMessage());
551
+ result = gatt.setCharacteristicNotification(characteristic, notify);
552
+ // Then write to descriptor
553
+ descriptor.setValue(finalValue);
554
+ registerNotifyCallback = finalCallback;
555
+ result = gatt.writeDescriptor(descriptor);
556
+ } catch(Exception e) {
557
+ Log.d(BleManager.LOG_TAG, "Exception in setNotify", e);
512
558
  }
513
559
 
514
- } else {
515
- callback.invoke("Set notification failed for " + characteristicUUID);
560
+ if (! result) {
561
+ sendBackrError(registerNotifyCallback, "writeDescriptor failed for descriptor: " + descriptor.getUuid());
562
+ registerNotifyCallback = null;
563
+ completedCommand();
564
+ }
516
565
  }
566
+ });
517
567
 
518
- } else {
519
- callback.invoke("Failed to register notification for " + characteristicUUID);
520
- }
521
-
568
+ if (result) {
569
+ nextCommand();
522
570
  } else {
523
- callback.invoke("Characteristic " + characteristicUUID + " not found");
571
+ Log.e(BleManager.LOG_TAG, "Could not enqueue setNotify command");
524
572
  }
525
-
526
573
  }
527
574
 
528
575
  public void registerNotify(UUID serviceUUID, UUID characteristicUUID, Integer buffer, Callback callback) {
529
576
  Log.d(BleManager.LOG_TAG, "registerNotify");
530
- this.setNotify(serviceUUID, characteristicUUID, true, buffer, callback);
577
+ this.setNotify(serviceUUID, characteristicUUID, true, callback);
531
578
  }
532
579
 
533
580
  public void removeNotify(UUID serviceUUID, UUID characteristicUUID, Callback callback) {
534
581
  Log.d(BleManager.LOG_TAG, "removeNotify");
535
- this.setNotify(serviceUUID, characteristicUUID, false, 1, callback);
582
+ this.setNotify(serviceUUID, characteristicUUID, false, callback);
536
583
  }
537
584
 
538
585
  // Some devices reuse UUIDs across characteristics, so we can't use
@@ -572,30 +619,100 @@ public class Peripheral extends BluetoothGattCallback {
572
619
 
573
620
  public void read(UUID serviceUUID, UUID characteristicUUID, Callback callback) {
574
621
 
575
- if (!isConnected()) {
622
+ if (!isConnected() || gatt == null) {
576
623
  callback.invoke("Device is not connected", null);
577
624
  return;
578
625
  }
579
- if (gatt == null) {
580
- callback.invoke("BluetoothGatt is null", null);
581
- return;
582
- }
583
626
 
584
627
  BluetoothGattService service = gatt.getService(serviceUUID);
585
- BluetoothGattCharacteristic characteristic = findReadableCharacteristic(service, characteristicUUID);
628
+ final BluetoothGattCharacteristic characteristic = findReadableCharacteristic(service, characteristicUUID);
586
629
 
587
630
  if (characteristic == null) {
588
631
  callback.invoke("Characteristic " + characteristicUUID + " not found.", null);
632
+ return;
633
+ }
634
+
635
+ final Callback reactcb = callback;
636
+ boolean result = commandQueue.add(new Runnable() {
637
+ @Override
638
+ public void run() {
639
+ readCallback = reactcb;
640
+ if (! gatt.readCharacteristic(characteristic)) {
641
+ readCallback = null;
642
+ sendBackrError(reactcb, "Read failed");
643
+ completedCommand();
644
+ }
645
+ }
646
+ });
647
+
648
+ if (result) {
649
+ nextCommand();
589
650
  } else {
590
- readCallback = callback;
591
- if (!gatt.readCharacteristic(characteristic)) {
592
- readCallback = null;
593
- callback.invoke("Read failed", null);
651
+ Log.d(BleManager.LOG_TAG, "Could not queue read characteristic command");
652
+ }
653
+ }
654
+
655
+ private void sendBackrError(final Callback callback, final String message) {
656
+ new Handler(Looper.getMainLooper()).post(new Runnable() {
657
+ @Override
658
+ public void run() {
659
+ callback.invoke(message, null);
660
+ }
661
+ });
662
+ }
663
+
664
+ private byte[] copyOf(byte[] source) {
665
+ if (source == null) return new byte[0];
666
+ final int sourceLength = source.length;
667
+ final byte[] copy = new byte[sourceLength];
668
+ System.arraycopy(source, 0, copy, 0, sourceLength);
669
+ return copy;
670
+ }
671
+
672
+ private void completedCommand() {
673
+ commandQueue.poll();
674
+ commandQueueBusy = false;
675
+ nextCommand();
676
+ }
677
+
678
+ private void nextCommand() {
679
+ synchronized (this) {
680
+ if (commandQueueBusy) {
681
+ Log.d(BleManager.LOG_TAG, "Command queue busy");
682
+ return;
683
+ }
684
+
685
+ final Runnable nextCommand = commandQueue.peek();
686
+ if (nextCommand == null) {
687
+ Log.d(BleManager.LOG_TAG, "Command queue empty");
688
+ return;
689
+ }
690
+
691
+ // Check if we still have a valid gatt object
692
+ if (gatt == null) {
693
+ Log.d(BleManager.LOG_TAG, "Error, gatt is null");
694
+ commandQueue.clear();
695
+ commandQueueBusy = false;
696
+ return;
594
697
  }
698
+
699
+ // Execute the next command in the queue
700
+ commandQueueBusy = true;
701
+ mainHandler.post(new Runnable() {
702
+ @Override
703
+ public void run() {
704
+ try {
705
+ nextCommand.run();
706
+ } catch (Exception ex) {
707
+ Log.d(BleManager.LOG_TAG, "Error, command exception");
708
+ completedCommand();
709
+ }
710
+ }
711
+ });
595
712
  }
596
713
  }
597
714
 
598
- public void readRSSI(Callback callback) {
715
+ public void readRSSI(final Callback callback) {
599
716
  if (!isConnected()) {
600
717
  callback.invoke("Device is not connected", null);
601
718
  return;
@@ -605,11 +722,26 @@ public class Peripheral extends BluetoothGattCallback {
605
722
  return;
606
723
  }
607
724
 
608
- readRSSICallback = callback;
725
+ final boolean result = commandQueue.add(new Runnable() {
726
+ @Override
727
+ public void run() {
728
+ if (isConnected()) {
729
+ readRSSICallback = callback;
730
+ if (! gatt.readRemoteRssi()) {
731
+ readCallback = null;
732
+ sendBackrError(callback, "Read RSSI failed");
733
+ completedCommand();
734
+ }
735
+ } else {
736
+ completedCommand();
737
+ }
738
+ }
739
+ });
609
740
 
610
- if (!gatt.readRemoteRssi()) {
611
- readCallback = null;
612
- callback.invoke("Read RSSI failed", null);
741
+ if (result) {
742
+ nextCommand();
743
+ } else {
744
+ Log.d(BleManager.LOG_TAG, "Could not queue readRemoteRssi command");
613
745
  }
614
746
  }
615
747
 
@@ -667,112 +799,105 @@ public class Peripheral extends BluetoothGattCallback {
667
799
  return null;
668
800
  }
669
801
 
670
- public boolean doWrite(BluetoothGattCharacteristic characteristic, byte[] data) {
671
- characteristic.setValue(data);
802
+ public boolean doWrite(final BluetoothGattCharacteristic characteristic, byte[] data, final Callback callback) {
803
+ final byte[] copyOfData = copyOf(data);
804
+ boolean result = commandQueue.add(new Runnable() {
805
+ @Override
806
+ public void run() {
807
+ characteristic.setValue(copyOfData);
808
+ if (characteristic.getWriteType() == BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
809
+ writeCallback = callback;
810
+ else
811
+ writeCallback = null;
812
+ if (!gatt.writeCharacteristic(characteristic)) {
813
+ sendBackrError(writeCallback, "Write failed");
814
+ writeCallback = null;
815
+ completedCommand();
816
+ }
817
+ }
818
+ });
672
819
 
673
- if (!gatt.writeCharacteristic(characteristic)) {
674
- Log.d(BleManager.LOG_TAG, "Error on doWrite");
675
- return false;
820
+ if (result) {
821
+ nextCommand();
822
+ } else {
823
+ Log.d(BleManager.LOG_TAG, "Could not queue write characteristic command");
676
824
  }
677
- return true;
825
+
826
+ return result;
678
827
  }
679
828
 
680
- public void write(UUID serviceUUID, UUID characteristicUUID, byte[] data, Integer maxByteSize,
681
- Integer queueSleepTime, Callback callback, int writeType) {
682
- if (!isConnected()) {
829
+ public void write(UUID serviceUUID, UUID characteristicUUID, byte[] data, Integer maxByteSize, Integer queueSleepTime, Callback callback, int writeType) {
830
+ if (!isConnected() || gatt == null) {
683
831
  callback.invoke("Device is not connected", null);
684
832
  return;
685
833
  }
686
- if (gatt == null) {
687
- callback.invoke("BluetoothGatt is null");
688
- } else {
689
- BluetoothGattService service = gatt.getService(serviceUUID);
690
- BluetoothGattCharacteristic characteristic = findWritableCharacteristic(service, characteristicUUID,
691
- writeType);
692
834
 
693
- if (characteristic == null) {
694
- callback.invoke("Characteristic " + characteristicUUID + " not found.");
695
- } else {
696
- characteristic.setWriteType(writeType);
835
+ BluetoothGattService service = gatt.getService(serviceUUID);
836
+ BluetoothGattCharacteristic characteristic = findWritableCharacteristic(service, characteristicUUID, writeType);
697
837
 
698
- if (writeQueue.size() > 0) {
699
- callback.invoke("You have already an queued message");
700
- return;
701
- }
838
+ if (characteristic == null) {
839
+ callback.invoke("Characteristic " + characteristicUUID + " not found.");
840
+ return;
841
+ }
702
842
 
703
- if (writeCallback != null) {
704
- callback.invoke("You're already writing");
705
- return;
706
- }
843
+ characteristic.setWriteType(writeType);
707
844
 
708
- if (writeQueue.size() == 0 && writeCallback == null) {
845
+ if (data.length <= maxByteSize) {
846
+ if (! doWrite(characteristic, data, callback)) {
847
+ callback.invoke("Write failed");
848
+ writeCallback = null;
849
+ }
850
+ } else {
851
+ int dataLength = data.length;
852
+ int count = 0;
853
+ byte[] firstMessage = null;
854
+ List<byte[]> splittedMessage = new ArrayList<>();
855
+
856
+ while (count < dataLength && (dataLength - count > maxByteSize)) {
857
+ if (count == 0) {
858
+ firstMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
859
+ } else {
860
+ byte[] splitMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
861
+ splittedMessage.add(splitMessage);
862
+ }
863
+ count += maxByteSize;
864
+ }
865
+ if (count < dataLength) {
866
+ // Other bytes in queue
867
+ byte[] splitMessage = Arrays.copyOfRange(data, count, data.length);
868
+ splittedMessage.add(splitMessage);
869
+ }
709
870
 
710
- if (BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT == writeType) {
711
- writeCallback = callback;
871
+ if (BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT == writeType) {
872
+ writeQueue.addAll(splittedMessage);
873
+ if (! doWrite(characteristic, firstMessage, callback)) {
874
+ writeQueue.clear();
875
+ writeCallback = null;
876
+ callback.invoke("Write failed");
877
+ }
878
+ } else {
879
+ try {
880
+ boolean writeError = false;
881
+ if (! doWrite(characteristic, firstMessage, callback)) {
882
+ writeError = true;
883
+ callback.invoke("Write failed");
712
884
  }
713
-
714
- if (data.length > maxByteSize) {
715
- int dataLength = data.length;
716
- int count = 0;
717
- byte[] firstMessage = null;
718
- List<byte[]> splittedMessage = new ArrayList<>();
719
-
720
- while (count < dataLength && (dataLength - count > maxByteSize)) {
721
- if (count == 0) {
722
- firstMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
723
- } else {
724
- byte[] splitMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
725
- splittedMessage.add(splitMessage);
726
- }
727
- count += maxByteSize;
728
- }
729
- if (count < dataLength) {
730
- // Other bytes in queue
731
- byte[] splitMessage = Arrays.copyOfRange(data, count, data.length);
732
- splittedMessage.add(splitMessage);
733
- }
734
-
735
- if (BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT == writeType) {
736
- writeQueue.addAll(splittedMessage);
737
- if (!doWrite(characteristic, firstMessage)) {
738
- writeQueue.clear();
739
- writeCallback = null;
885
+ if (! writeError) {
886
+ Thread.sleep(queueSleepTime);
887
+ for (byte[] message : splittedMessage) {
888
+ if (! doWrite(characteristic, message, callback)) {
889
+ writeError = true;
740
890
  callback.invoke("Write failed");
891
+ break;
741
892
  }
742
- } else {
743
- try {
744
- boolean writeError = false;
745
- if (!doWrite(characteristic, firstMessage)) {
746
- writeError = true;
747
- callback.invoke("Write failed");
748
- }
749
- if (!writeError) {
750
- Thread.sleep(queueSleepTime);
751
- for (byte[] message : splittedMessage) {
752
- if (!doWrite(characteristic, message)) {
753
- writeError = true;
754
- callback.invoke("Write failed");
755
- break;
756
- }
757
- Thread.sleep(queueSleepTime);
758
- }
759
- if (!writeError) {
760
- callback.invoke();
761
- }
762
- }
763
- } catch (InterruptedException e) {
764
- callback.invoke("Error during writing");
765
- }
893
+ Thread.sleep(queueSleepTime);
766
894
  }
767
- } else if (doWrite(characteristic, data)) {
768
- Log.d(BleManager.LOG_TAG, "Write completed");
769
- if (BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE == writeType) {
895
+ if (! writeError) {
770
896
  callback.invoke();
771
897
  }
772
- } else {
773
- callback.invoke("Write failed");
774
- writeCallback = null;
775
898
  }
899
+ } catch (InterruptedException e) {
900
+ callback.invoke("Error during writing");
776
901
  }
777
902
  }
778
903
  }
package/index.d.ts CHANGED
@@ -120,9 +120,42 @@ declare module "react-native-ble-manager" {
120
120
  export function getBondedPeripherals(): Promise<Peripheral[]>;
121
121
  export function removePeripheral(peripheralID: string): Promise<void>;
122
122
 
123
- export interface PeripheralInfo {
123
+
124
+ export interface Service {
125
+ uuid: string;
126
+ }
127
+
128
+ export interface Descriptor {
129
+ value: string;
130
+ uuid: string;
131
+ }
132
+
133
+ export interface Characteristic {
134
+ // See https://developer.apple.com/documentation/corebluetooth/cbcharacteristicproperties
135
+ properties: {
136
+ Broadcast?: "Broadcast";
137
+ Read?: "Read";
138
+ WriteWithoutResponse?: "WriteWithoutResponse";
139
+ Write?: "Write";
140
+ Notify?: "Notify";
141
+ Indicate?: "Indicate";
142
+ AuthenticatedSignedWrites?: "AuthenticatedSignedWrites";
143
+ ExtendedProperties?: "ExtendedProperties";
144
+ NotifyEncryptionRequired?: "NotifyEncryptionRequired";
145
+ IndicateEncryptionRequired?: "IndicateEncryptionRequired";
146
+ }
147
+ characteristic: string;
148
+ service: string;
149
+ descriptors?: Descriptor[];
150
+
151
+ }
152
+
153
+ export interface PeripheralInfo extends Peripheral {
124
154
  serviceUUIDs?: string[];
155
+ characteristics?: Characteristic[];
156
+ services?: Service[];
125
157
  }
158
+
126
159
  export function retrieveServices(
127
160
  peripheralID: string,
128
161
  serviceUUIDs?: string[]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-ble-manager",
3
- "version": "7.6.1",
3
+ "version": "8.0.1",
4
4
  "description": "A BLE module for react native.",
5
5
  "main": "BleManager",
6
6
  "types": "./index.d.ts",
package/ISSUE_TEMPLATE.md DELETED
@@ -1,33 +0,0 @@
1
- ### Before open an issue
2
- - Check the closed issues, your question maybe is not new.
3
- - We can't debug your physical devices.
4
- - If the library is not working 99% you did something wrong, in the code or in the phone permissions.
5
-
6
- ### Version
7
-
8
- Tell us which versions you are using:
9
-
10
- - react-native-ble-manager v?.?.?
11
- - react-native v?.?
12
- - iOS/Android v.?
13
-
14
- ### Expected behaviour
15
-
16
- Tell us what should happen
17
-
18
- ### Actual behaviour
19
-
20
- Tell us what happens instead
21
-
22
- ### Steps to reproduce
23
-
24
- 1.
25
- 2.
26
- 3.
27
-
28
- ### Stack trace and console log
29
-
30
- Hint: it would help a lot if you enable the debugger ("Pause on exceptions" in the "Source" panel of Chrome dev tools) and spot the place where the error is thrown
31
-
32
- ```
33
- ```