diff --git a/packages/quick_blue/android/src/main/AndroidManifest.xml b/packages/quick_blue/android/src/main/AndroidManifest.xml
index 919bc9c..6dbadaa 100644
--- a/packages/quick_blue/android/src/main/AndroidManifest.xml
+++ b/packages/quick_blue/android/src/main/AndroidManifest.xml
@@ -5,10 +5,8 @@
-
-
+
+
diff --git a/packages/quick_blue/android/src/main/kotlin/com/example/quick_blue/QuickBluePlugin.kt b/packages/quick_blue/android/src/main/kotlin/com/example/quick_blue/QuickBluePlugin.kt
index 7193b9b..b0a1761 100644
--- a/packages/quick_blue/android/src/main/kotlin/com/example/quick_blue/QuickBluePlugin.kt
+++ b/packages/quick_blue/android/src/main/kotlin/com/example/quick_blue/QuickBluePlugin.kt
@@ -80,120 +80,128 @@ class QuickBluePlugin: FlutterPlugin, MethodCallHandler, EventChannel.StreamHand
fun trace() = Arrays.toString(Throwable().stackTrace)
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
- when (call.method) {
- "isBluetoothAvailable" -> {
- result.success(bluetoothManager.adapter.isEnabled)
- }
- "startScan" -> {
- val serviceUUIDs = call.argument>("serviceUUIDs")!!
- if (serviceUUIDs != null && serviceUUIDs.size > 0) {
- val filters: ArrayList = ArrayList()
- for (serviceUUID in serviceUUIDs) {
- val filter = ScanFilter.Builder()
- .setServiceUuid(parseToParcelUuid(serviceUUID))
+ try {
+ when (call.method) {
+ "isBluetoothAvailable" -> {
+ result.success(bluetoothManager.adapter.isEnabled)
+ }
+ "startScan" -> {
+ val serviceUUIDs = call.argument>("serviceUUIDs")
+ if (serviceUUIDs != null && serviceUUIDs.size > 0) {
+ val filters: ArrayList = ArrayList()
+ for (serviceUUID in serviceUUIDs) {
+ val filter = ScanFilter.Builder()
+ .setServiceUuid(parseToParcelUuid(serviceUUID))
+ .build()
+ filters.add(filter)
+ }
+
+ val settings = ScanSettings.Builder()
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build()
- filters.add(filter)
- }
-
- val settings = ScanSettings.Builder()
- .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
- .build()
- bluetoothManager.adapter.bluetoothLeScanner?.startScan(filters, settings, scanCallback)
- } else {
- bluetoothManager.adapter.bluetoothLeScanner?.startScan(scanCallback)
+ bluetoothManager.adapter.bluetoothLeScanner?.startScan(filters, settings, scanCallback)
+ } else {
+ bluetoothManager.adapter.bluetoothLeScanner?.startScan(scanCallback)
+ }
+ result.success(null)
}
- result.success(null)
- }
- "stopScan" -> {
- bluetoothManager.adapter.bluetoothLeScanner?.stopScan(scanCallback)
- result.success(null)
- }
- "connect" -> {
- val deviceId = call.argument("deviceId")!!
- if (knownGatts.find { it.device.address == deviceId } != null) {
- return result.success(null)
+ "stopScan" -> {
+ bluetoothManager.adapter.bluetoothLeScanner?.stopScan(scanCallback)
+ result.success(null)
}
- val remoteDevice = bluetoothManager.adapter.getRemoteDevice(deviceId)
- val gatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- remoteDevice.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
- } else {
- remoteDevice.connectGatt(context, false, gattCallback)
+ "connect" -> {
+ val deviceId = call.argument("deviceId")!!
+ if (knownGatts.find { it.device.address == deviceId } != null) {
+ return result.success(null)
+ }
+ val remoteDevice = bluetoothManager.adapter.getRemoteDevice(deviceId)
+ val gatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ remoteDevice.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
+ } else {
+ remoteDevice.connectGatt(context, false, gattCallback)
+ }
+ knownGatts.add(gatt)
+ result.success(null)
+ // TODO connecting
}
- knownGatts.add(gatt)
- result.success(null)
- // TODO connecting
- }
- "disconnect" -> {
- val deviceId = call.argument("deviceId")!!
- val gatt = knownGatts.find { it.device.address == deviceId }
- ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
- cleanConnection(gatt)
- result.success(null)
- //FIXME If `disconnect` is called before BluetoothGatt.STATE_CONNECTED
- // there will be no `disconnected` message any more
- }
- "discoverServices" -> {
- val deviceId = call.argument("deviceId")!!
- val gatt = knownGatts.find { it.device.address == deviceId }
- ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
- gatt.discoverServices()
- result.success(null)
- }
- "setNotifiable" -> {
- val deviceId = call.argument("deviceId")!!
- val service = call.argument("service")!!
- val characteristic = call.argument("characteristic")!!
- val bleInputProperty = call.argument("bleInputProperty")!!
- val gatt = knownGatts.find { it.device.address == deviceId }
- ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
- val c = gatt.getCharacteristic(service, characteristic)
- ?: return result.error("IllegalArgument", "Unknown characteristic: $characteristic", trace())
- gatt.setNotifiable(c, bleInputProperty)
- result.success(null)
- }
- "readValue" -> {
- val deviceId = call.argument("deviceId")!!
- val service = call.argument("service")!!
- val characteristic = call.argument("characteristic")!!
- val gatt = knownGatts.find { it.device.address == deviceId }
- ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
- val c = gatt.getCharacteristic(service, characteristic)
- ?: return result.error("IllegalArgument", "Unknown characteristic: $characteristic", trace())
- if (gatt.readCharacteristic(c))
+ "disconnect" -> {
+ val deviceId = call.argument("deviceId")!!
+ val gatt = knownGatts.find { it.device.address == deviceId }
+ ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
+ cleanConnection(gatt)
result.success(null)
- else
- result.error("Characteristic unavailable", null, trace())
- }
- "writeValue" -> {
- val deviceId = call.argument("deviceId")!!
- val service = call.argument("service")!!
- val characteristic = call.argument("characteristic")!!
- val value = call.argument("value")!!
- val gatt = knownGatts.find { it.device.address == deviceId }
- ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
- val c = gatt.getCharacteristic(service, characteristic)
- ?: return result.error("IllegalArgument", "Unknown characteristic: $characteristic", trace())
- c.value = value
- if (gatt.writeCharacteristic(c))
+ //FIXME If `disconnect` is called before BluetoothGatt.STATE_CONNECTED
+ // there will be no `disconnected` message any more
+ }
+ "discoverServices" -> {
+ val deviceId = call.argument("deviceId")!!
+ val gatt = knownGatts.find { it.device.address == deviceId }
+ ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
+ gatt.discoverServices()
result.success(null)
- else
- result.error("Characteristic unavailable", null, trace())
- }
- "requestMtu" -> {
- val deviceId = call.argument("deviceId")!!
- val expectedMtu = call.argument("expectedMtu")!!
- val gatt = knownGatts.find { it.device.address == deviceId }
- ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
- val success = gatt.requestMtu(expectedMtu)
- if (success)
+ }
+ "setNotifiable" -> {
+ val deviceId = call.argument("deviceId")!!
+ val service = call.argument("service")!!
+ val characteristic = call.argument("characteristic")!!
+ val bleInputProperty = call.argument("bleInputProperty")!!
+ val gatt = knownGatts.find { it.device.address == deviceId }
+ ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
+ val s = gatt.getService(UUID.fromString(service))
+ ?: return result.error("IllegalArgument", "Unknown service: $service", trace())
+ val c = s.getCharacteristic(UUID.fromString(characteristic))
+ ?: return result.error("IllegalArgument", "Unknown characteristic: $characteristic", trace())
+ gatt.setNotifiable(c, bleInputProperty)
result.success(null)
- else
- result.error("Unable to set MTU", null, trace())
- }
- else -> {
- result.notImplemented()
+ }
+ "readValue" -> {
+ val deviceId = call.argument("deviceId")!!
+ val service = call.argument("service")!!
+ val characteristic = call.argument("characteristic")!!
+ val gatt = knownGatts.find { it.device.address == deviceId }
+ ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
+ val c = gatt.getCharacteristic(service, characteristic)
+ ?: return result.error("IllegalArgument", "Unknown characteristic: $characteristic", trace())
+ if (gatt.readCharacteristic(c))
+ result.success(null)
+ else
+ result.error("Characteristic unavailable", null, trace())
+ }
+ "writeValue" -> {
+ val deviceId = call.argument("deviceId")!!
+ val service = call.argument("service")!!
+ val characteristic = call.argument("characteristic")!!
+ val value = call.argument("value")!!
+ val gatt = knownGatts.find { it.device.address == deviceId }
+ ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
+ val c = gatt.getCharacteristic(service, characteristic)
+ ?: return result.error("IllegalArgument", "Unknown characteristic: $characteristic", trace())
+ c.value = value
+ if (gatt.writeCharacteristic(c)) {
+ result.success(null)
+ } else {
+ result.error("Characteristic unavailable", null, trace())
+ }
+ }
+ "requestMtu" -> {
+ val deviceId = call.argument("deviceId")!!
+ val expectedMtu = call.argument("expectedMtu")!!
+ val gatt = knownGatts.find { it.device.address == deviceId }
+ ?: return result.error("IllegalArgument", "Unknown deviceId: $deviceId", trace())
+ val success = gatt.requestMtu(expectedMtu)
+ if (success)
+ result.success(null)
+ else
+ result.error("Unable to set MTU", null, trace())
+ }
+ else -> {
+ result.notImplemented()
+ }
}
+ } catch (e: Throwable) {
+ e.printStackTrace()
+ result.error("Error", "Error", trace())
}
}
@@ -363,7 +371,7 @@ fun Short.toByteArray(byteOrder: ByteOrder = ByteOrder.LITTLE_ENDIAN): ByteArray
ByteBuffer.allocate(2 /*Short.SIZE_BYTES*/).order(byteOrder).putShort(this).array()
fun BluetoothGatt.getCharacteristic(service: String, characteristic: String): BluetoothGattCharacteristic? =
- getService(UUID.fromString(service)).getCharacteristic(UUID.fromString(characteristic))
+ getService(UUID.fromString(service))?.getCharacteristic(UUID.fromString(characteristic))
private val DESC__CLIENT_CHAR_CONFIGURATION = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
@@ -374,8 +382,10 @@ fun BluetoothGatt.setNotifiable(gattCharacteristic: BluetoothGattCharacteristic,
"indication" -> BluetoothGattDescriptor.ENABLE_INDICATION_VALUE to true
else -> BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE to false
}
- descriptor.value = value
- setCharacteristicNotification(descriptor.characteristic, enable) && writeDescriptor(descriptor)
+ if (setCharacteristicNotification(gattCharacteristic, enable) && descriptor != null) {
+ descriptor.value = value
+ writeDescriptor(descriptor)
+ }
}
const val baseBluetoothUuidPostfix = "0000-1000-8000-00805F9B34FB"
diff --git a/packages/quick_blue/lib/src/method_channel_quick_blue.dart b/packages/quick_blue/lib/src/method_channel_quick_blue.dart
index ab5d886..8c57a77 100644
--- a/packages/quick_blue/lib/src/method_channel_quick_blue.dart
+++ b/packages/quick_blue/lib/src/method_channel_quick_blue.dart
@@ -92,8 +92,7 @@ class MethodChannelQuickBlue extends QuickBluePlatform {
if (message['ServiceState'] == 'discovered') {
String deviceId = message['deviceId'];
String service = message['service'];
- List characteristics =
- (message['characteristics'] as List).cast();
+ List characteristics = ((message['characteristics'] ?? []) as List).cast();
onServiceDiscovered?.call(deviceId, service, characteristics);
}
} else if (message['characteristicValue'] != null) {
diff --git a/packages/quick_blue/windows/quick_blue_plugin.cpp b/packages/quick_blue/windows/quick_blue_plugin.cpp
index 31d184d..e4331bd 100644
--- a/packages/quick_blue/windows/quick_blue_plugin.cpp
+++ b/packages/quick_blue/windows/quick_blue_plugin.cpp
@@ -24,6 +24,10 @@
#include
#include
+#include
+#include
+#include
+
#define GUID_FORMAT "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
#define GUID_ARG(guid) guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]
@@ -620,6 +624,10 @@ namespace
winrt::fire_and_forget QuickBluePlugin::ConnectAsync(uint64_t bluetoothAddress)
{
auto device = co_await BluetoothLEDevice::FromBluetoothAddressAsync(bluetoothAddress);
+ if (!device) {
+ OutputDebugString((L"ConnectAsync null device! "+ std::to_wstring(bluetoothAddress) +L"\n").c_str());
+ co_return;
+ }
auto servicesResult = co_await device.GetGattServicesAsync();
if (servicesResult.Status() != GattCommunicationStatus::Success)
{