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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/README.md +1 -1
- package/android/build.gradle +4 -4
- package/android/src/main/java/it/innove/BleManager.java +10 -0
- package/android/src/main/java/it/innove/Peripheral.java +314 -189
- package/index.d.ts +34 -1
- package/package.json +1 -1
- package/ISSUE_TEMPLATE.md +0 -33
|
@@ -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
package/android/build.gradle
CHANGED
|
@@ -9,7 +9,7 @@ buildscript {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
dependencies {
|
|
12
|
-
classpath("com.android.tools.build:gradle:
|
|
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",
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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 (
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
|
|
411
|
-
|
|
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,
|
|
458
|
-
|
|
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
|
-
|
|
466
|
-
|
|
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
|
-
|
|
473
|
-
|
|
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
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
515
|
-
|
|
560
|
+
if (! result) {
|
|
561
|
+
sendBackrError(registerNotifyCallback, "writeDescriptor failed for descriptor: " + descriptor.getUuid());
|
|
562
|
+
registerNotifyCallback = null;
|
|
563
|
+
completedCommand();
|
|
564
|
+
}
|
|
516
565
|
}
|
|
566
|
+
});
|
|
517
567
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
|
|
568
|
+
if (result) {
|
|
569
|
+
nextCommand();
|
|
522
570
|
} else {
|
|
523
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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
|
-
|
|
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 (
|
|
611
|
-
|
|
612
|
-
|
|
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
|
-
|
|
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 (
|
|
674
|
-
|
|
675
|
-
|
|
820
|
+
if (result) {
|
|
821
|
+
nextCommand();
|
|
822
|
+
} else {
|
|
823
|
+
Log.d(BleManager.LOG_TAG, "Could not queue write characteristic command");
|
|
676
824
|
}
|
|
677
|
-
|
|
825
|
+
|
|
826
|
+
return result;
|
|
678
827
|
}
|
|
679
828
|
|
|
680
|
-
public void write(UUID serviceUUID, UUID characteristicUUID, byte[] data, Integer maxByteSize,
|
|
681
|
-
|
|
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
|
-
|
|
694
|
-
|
|
695
|
-
} else {
|
|
696
|
-
characteristic.setWriteType(writeType);
|
|
835
|
+
BluetoothGattService service = gatt.getService(serviceUUID);
|
|
836
|
+
BluetoothGattCharacteristic characteristic = findWritableCharacteristic(service, characteristicUUID, writeType);
|
|
697
837
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
838
|
+
if (characteristic == null) {
|
|
839
|
+
callback.invoke("Characteristic " + characteristicUUID + " not found.");
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
702
842
|
|
|
703
|
-
|
|
704
|
-
callback.invoke("You're already writing");
|
|
705
|
-
return;
|
|
706
|
-
}
|
|
843
|
+
characteristic.setWriteType(writeType);
|
|
707
844
|
|
|
708
|
-
|
|
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
|
-
|
|
711
|
-
|
|
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
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
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
|
-
```
|