Implement unified and type safe error messages (#186)

* Implement unified and type safe error messages

* Fix Apple error handling

* improve linux exception handling

* improve web exception handling

* fix window imports

* update pigeon generated files

* Fix compilaton issue

* Fix windows error parsing

* Fix windows compilation

* Improve error handling on dart side

* rename _wrapFuture to _executeWithErrorHandling

* Add pigeon generation script and format generated dart file

* Update changelog

* Update readme

---------

Co-authored-by: Foti Dim <foti@navideck.com>
This commit is contained in:
Rohit Sangwan
2025-11-12 00:04:29 +05:30
committed by GitHub
parent b52ca9ee84
commit acfa3200ca
32 changed files with 3399 additions and 1721 deletions
+3
View File
@@ -1,3 +1,6 @@
## 1.0.0
* Unified error codes for all platforms
## 0.21.1 ## 0.21.1
* Fix device name resolution on Windows * Fix device name resolution on Windows
* Add `exclusionFilters` to filter out devices from scan results * Add `exclusionFilters` to filter out devices from scan results
+51
View File
@@ -17,6 +17,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE
- [Requesting MTU](#requesting-mtu) - [Requesting MTU](#requesting-mtu)
- [Command Queue](#command-queue) - [Command Queue](#command-queue)
- [Timeout](#timeout) - [Timeout](#timeout)
- [Error Handling](#error-handling)
- [UUID Format Agnostic](#uuid-format-agnostic) - [UUID Format Agnostic](#uuid-format-agnostic)
## API Support ## API Support
@@ -456,6 +457,56 @@ UniversalBle.timeout = null;
You can also specify the `timeout` parameter when sending a command. This will override the global timeout. You can also specify the `timeout` parameter when sending a command. This will override the global timeout.
## Error Handling
Universal BLE provides a unified and type-safe error handling system across all platforms. All errors are represented using the `UniversalBleException` base class with typed error codes from the `UniversalBleErrorCode` enum.
### Exception Types
- **`UniversalBleException`**: Base exception class for all BLE errors
- **`ConnectionException`**: Thrown for connection-related errors
- **`PairingException`**: Thrown for pairing-related errors
- **`WebBluetoothGloballyDisabled`**: Thrown when Web Bluetooth is globally disabled
### Error Codes
All errors are categorized using the `UniversalBleErrorCode` enum, which includes codes for:
- Connection errors (timeout, failed, rejected, etc.)
- Pairing errors (failed, cancelled, not allowed, etc.)
- Operation errors (not supported, timeout, cancelled, etc.)
- Permission errors (not allowed, unauthorized, access denied, etc.)
- Device errors (not found, disconnected, etc.)
- Service/Characteristic errors (not found, invalid UUID, etc.)
- And many more...
### Usage
```dart
try {
await bleDevice.connect();
} on ConnectionException catch (e) {
// Handle connection-specific errors
switch (e.code) {
case UniversalBleErrorCode.connectionTimeout:
// Handle timeout
break;
case UniversalBleErrorCode.connectionFailed:
// Handle connection failure
break;
case UniversalBleErrorCode.deviceDisconnected:
// Handle disconnection
break;
default:
// Handle other connection errors
}
} on UniversalBleException catch (e) {
// Handle other BLE errors
print('Error code: ${e.code}, Message: ${e.message}');
}
```
The error parser automatically converts platform-specific error formats (strings, numeric codes, PlatformExceptions) into the unified `UniversalBleErrorCode` enum, ensuring consistent error handling across all platforms.
## UUID Format Agnostic ## UUID Format Agnostic
Universal BLE is agnostic to the UUID format of services and characteristics regardless of the platform the app runs on. When passing a UUID, you can pass it in any format (long/short) or character case (upper/lower case) you want. Universal BLE will take care of necessary conversions, across all platforms, so that you don't need to worry about underlying platform differences. Universal BLE is agnostic to the UUID format of services and characteristics regardless of the platform the app runs on. When passing a UUID, you can pass it in any format (long/short) or character case (upper/lower case) you want. Universal BLE will take care of necessary conversions, across all platforms, so that you don't need to worry about underlying platform differences.
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v22.6.1), do not edit directly. // Autogenerated from Pigeon (v26.0.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -7,16 +7,22 @@ package com.navideck.universal_ble
import android.util.Log import android.util.Log
import io.flutter.plugin.common.BasicMessageChannel import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MessageCodec import io.flutter.plugin.common.MessageCodec
import io.flutter.plugin.common.StandardMethodCodec
import io.flutter.plugin.common.StandardMessageCodec import io.flutter.plugin.common.StandardMessageCodec
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer import java.nio.ByteBuffer
private object UniversalBlePigeonUtils {
private fun wrapResult(result: Any?): List<Any?> { fun createConnectionError(channelName: String): FlutterError {
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") }
fun wrapResult(result: Any?): List<Any?> {
return listOf(result) return listOf(result)
} }
private fun wrapError(exception: Throwable): List<Any?> { fun wrapError(exception: Throwable): List<Any?> {
return if (exception is FlutterError) { return if (exception is FlutterError) {
listOf( listOf(
exception.code, exception.code,
@@ -30,10 +36,38 @@ private fun wrapError(exception: Throwable): List<Any?> {
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)
) )
} }
} }
fun deepEquals(a: Any?, b: Any?): Boolean {
if (a is ByteArray && b is ByteArray) {
return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
return a.contentEquals(b)
}
if (a is Array<*> && b is Array<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is List<*> && b is List<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is Map<*, *> && b is Map<*, *>) {
return a.size == b.size && a.all {
(b as Map<Any?, Any?>).contains(it.key) &&
deepEquals(it.value, b[it.key])
}
}
return a == b
}
private fun createConnectionError(channelName: String): FlutterError { }
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "")}
/** /**
* Error class for passing custom error details to Flutter via a thrown PlatformException. * Error class for passing custom error details to Flutter via a thrown PlatformException.
@@ -47,6 +81,77 @@ class FlutterError (
val details: Any? = null val details: Any? = null
) : Throwable() ) : Throwable()
/** Unified error codes for all platforms */
enum class UniversalBleErrorCode(val raw: Int) {
UNKNOWN_ERROR(0),
FAILED(1),
NOT_SUPPORTED(2),
NOT_IMPLEMENTED(3),
CHANNEL_ERROR(4),
BLUETOOTH_NOT_AVAILABLE(5),
BLUETOOTH_NOT_ENABLED(6),
BLUETOOTH_NOT_ALLOWED(7),
BLUETOOTH_UNAUTHORIZED(8),
DEVICE_DISCONNECTED(9),
CONNECTION_TIMEOUT(10),
CONNECTION_FAILED(11),
CONNECTION_REJECTED(12),
CONNECTION_LIMIT_EXCEEDED(13),
CONNECTION_ALREADY_EXISTS(14),
CONNECTION_TERMINATED(15),
CONNECTION_IN_PROGRESS(16),
ILLEGAL_ARGUMENT(17),
DEVICE_NOT_FOUND(18),
SERVICE_NOT_FOUND(19),
CHARACTERISTIC_NOT_FOUND(20),
INVALID_SERVICE_UUID(21),
INVALID_CHARACTERISTIC_UUID(22),
INVALID_OFFSET(23),
INVALID_ATTRIBUTE_LENGTH(24),
INVALID_PDU(25),
INVALID_HANDLE(26),
READ_FAILED(27),
READ_NOT_PERMITTED(28),
WRITE_FAILED(29),
WRITE_NOT_PERMITTED(30),
WRITE_REQUEST_BUSY(31),
INVALID_ACTION(32),
OPERATION_NOT_SUPPORTED(33),
OPERATION_TIMEOUT(34),
OPERATION_CANCELLED(35),
OPERATION_IN_PROGRESS(36),
CHARACTERISTIC_DOES_NOT_SUPPORT_READ(37),
CHARACTERISTIC_DOES_NOT_SUPPORT_WRITE(38),
CHARACTERISTIC_DOES_NOT_SUPPORT_WRITE_WITHOUT_RESPONSE(39),
CHARACTERISTIC_DOES_NOT_SUPPORT_NOTIFY(40),
CHARACTERISTIC_DOES_NOT_SUPPORT_INDICATE(41),
NOT_PAIRED(42),
NOT_PAIRABLE(43),
ALREADY_PAIRED(44),
PAIRING_FAILED(45),
PAIRING_CANCELLED(46),
PAIRING_TIMEOUT(47),
PAIRING_NOT_ALLOWED(48),
AUTHENTICATION_FAILURE(49),
INSUFFICIENT_AUTHENTICATION(50),
INSUFFICIENT_AUTHORIZATION(51),
INSUFFICIENT_ENCRYPTION(52),
INSUFFICIENT_KEY_SIZE(53),
PROTECTION_LEVEL_NOT_MET(54),
ACCESS_DENIED(55),
UNPAIRING_FAILED(56),
ALREADY_UNPAIRED(57),
SCAN_FAILED(58),
STOPPING_SCAN_IN_PROGRESS(59),
WEB_BLUETOOTH_GLOBALLY_DISABLED(60);
companion object {
fun ofRaw(raw: Int): UniversalBleErrorCode? {
return values().firstOrNull { it.raw == raw }
}
}
}
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
data class UniversalBleScanResult ( data class UniversalBleScanResult (
val deviceId: String, val deviceId: String,
@@ -78,6 +183,16 @@ data class UniversalBleScanResult (
services, services,
) )
} }
override fun equals(other: Any?): Boolean {
if (other !is UniversalBleScanResult) {
return false
}
if (this === other) {
return true
}
return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
} }
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
@@ -99,6 +214,16 @@ data class UniversalBleService (
characteristics, characteristics,
) )
} }
override fun equals(other: Any?): Boolean {
if (other !is UniversalBleService) {
return false
}
if (this === other) {
return true
}
return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
} }
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
@@ -120,6 +245,16 @@ data class UniversalBleCharacteristic (
properties, properties,
) )
} }
override fun equals(other: Any?): Boolean {
if (other !is UniversalBleCharacteristic) {
return false
}
if (this === other) {
return true
}
return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
} }
/** /**
@@ -148,6 +283,16 @@ data class UniversalScanFilter (
withManufacturerData, withManufacturerData,
) )
} }
override fun equals(other: Any?): Boolean {
if (other !is UniversalScanFilter) {
return false
}
if (this === other) {
return true
}
return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
} }
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
@@ -172,6 +317,16 @@ data class UniversalManufacturerDataFilter (
mask, mask,
) )
} }
override fun equals(other: Any?): Boolean {
if (other !is UniversalManufacturerDataFilter) {
return false
}
if (this === other) {
return true
}
return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
} }
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
@@ -193,36 +348,51 @@ data class UniversalManufacturerData (
data, data,
) )
} }
override fun equals(other: Any?): Boolean {
if (other !is UniversalManufacturerData) {
return false
}
if (this === other) {
return true
}
return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
} }
private open class UniversalBlePigeonCodec : StandardMessageCodec() { private open class UniversalBlePigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) { return when (type) {
129.toByte() -> { 129.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { return (readValue(buffer) as Long?)?.let {
UniversalBleScanResult.fromList(it) UniversalBleErrorCode.ofRaw(it.toInt())
} }
} }
130.toByte() -> { 130.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { return (readValue(buffer) as? List<Any?>)?.let {
UniversalBleService.fromList(it) UniversalBleScanResult.fromList(it)
} }
} }
131.toByte() -> { 131.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { return (readValue(buffer) as? List<Any?>)?.let {
UniversalBleCharacteristic.fromList(it) UniversalBleService.fromList(it)
} }
} }
132.toByte() -> { 132.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { return (readValue(buffer) as? List<Any?>)?.let {
UniversalScanFilter.fromList(it) UniversalBleCharacteristic.fromList(it)
} }
} }
133.toByte() -> { 133.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { return (readValue(buffer) as? List<Any?>)?.let {
UniversalManufacturerDataFilter.fromList(it) UniversalScanFilter.fromList(it)
} }
} }
134.toByte() -> { 134.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
UniversalManufacturerDataFilter.fromList(it)
}
}
135.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { return (readValue(buffer) as? List<Any?>)?.let {
UniversalManufacturerData.fromList(it) UniversalManufacturerData.fromList(it)
} }
@@ -232,30 +402,34 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() {
} }
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
when (value) { when (value) {
is UniversalBleScanResult -> { is UniversalBleErrorCode -> {
stream.write(129) stream.write(129)
writeValue(stream, value.toList()) writeValue(stream, value.raw.toLong())
} }
is UniversalBleService -> { is UniversalBleScanResult -> {
stream.write(130) stream.write(130)
writeValue(stream, value.toList()) writeValue(stream, value.toList())
} }
is UniversalBleCharacteristic -> { is UniversalBleService -> {
stream.write(131) stream.write(131)
writeValue(stream, value.toList()) writeValue(stream, value.toList())
} }
is UniversalScanFilter -> { is UniversalBleCharacteristic -> {
stream.write(132) stream.write(132)
writeValue(stream, value.toList()) writeValue(stream, value.toList())
} }
is UniversalManufacturerDataFilter -> { is UniversalScanFilter -> {
stream.write(133) stream.write(133)
writeValue(stream, value.toList()) writeValue(stream, value.toList())
} }
is UniversalManufacturerData -> { is UniversalManufacturerDataFilter -> {
stream.write(134) stream.write(134)
writeValue(stream, value.toList()) writeValue(stream, value.toList())
} }
is UniversalManufacturerData -> {
stream.write(135)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value) else -> super.writeValue(stream, value)
} }
} }
@@ -302,10 +476,10 @@ interface UniversalBlePlatformChannel {
api.getBluetoothAvailabilityState{ result: Result<Long> -> api.getBluetoothAvailabilityState{ result: Result<Long> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -320,10 +494,10 @@ interface UniversalBlePlatformChannel {
api.enableBluetooth{ result: Result<Boolean> -> api.enableBluetooth{ result: Result<Boolean> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -338,10 +512,10 @@ interface UniversalBlePlatformChannel {
api.disableBluetooth{ result: Result<Boolean> -> api.disableBluetooth{ result: Result<Boolean> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -359,7 +533,7 @@ interface UniversalBlePlatformChannel {
api.startScan(filterArg) api.startScan(filterArg)
listOf(null) listOf(null)
} catch (exception: Throwable) { } catch (exception: Throwable) {
wrapError(exception) UniversalBlePigeonUtils.wrapError(exception)
} }
reply.reply(wrapped) reply.reply(wrapped)
} }
@@ -375,7 +549,7 @@ interface UniversalBlePlatformChannel {
api.stopScan() api.stopScan()
listOf(null) listOf(null)
} catch (exception: Throwable) { } catch (exception: Throwable) {
wrapError(exception) UniversalBlePigeonUtils.wrapError(exception)
} }
reply.reply(wrapped) reply.reply(wrapped)
} }
@@ -393,7 +567,7 @@ interface UniversalBlePlatformChannel {
api.connect(deviceIdArg) api.connect(deviceIdArg)
listOf(null) listOf(null)
} catch (exception: Throwable) { } catch (exception: Throwable) {
wrapError(exception) UniversalBlePigeonUtils.wrapError(exception)
} }
reply.reply(wrapped) reply.reply(wrapped)
} }
@@ -411,7 +585,7 @@ interface UniversalBlePlatformChannel {
api.disconnect(deviceIdArg) api.disconnect(deviceIdArg)
listOf(null) listOf(null)
} catch (exception: Throwable) { } catch (exception: Throwable) {
wrapError(exception) UniversalBlePigeonUtils.wrapError(exception)
} }
reply.reply(wrapped) reply.reply(wrapped)
} }
@@ -431,9 +605,9 @@ interface UniversalBlePlatformChannel {
api.setNotifiable(deviceIdArg, serviceArg, characteristicArg, bleInputPropertyArg) { result: Result<Unit> -> api.setNotifiable(deviceIdArg, serviceArg, characteristicArg, bleInputPropertyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
reply.reply(wrapResult(null)) reply.reply(UniversalBlePigeonUtils.wrapResult(null))
} }
} }
} }
@@ -450,10 +624,10 @@ interface UniversalBlePlatformChannel {
api.discoverServices(deviceIdArg) { result: Result<List<UniversalBleService>> -> api.discoverServices(deviceIdArg) { result: Result<List<UniversalBleService>> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -472,10 +646,10 @@ interface UniversalBlePlatformChannel {
api.readValue(deviceIdArg, serviceArg, characteristicArg) { result: Result<ByteArray> -> api.readValue(deviceIdArg, serviceArg, characteristicArg) { result: Result<ByteArray> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -493,10 +667,10 @@ interface UniversalBlePlatformChannel {
api.requestMtu(deviceIdArg, expectedMtuArg) { result: Result<Long> -> api.requestMtu(deviceIdArg, expectedMtuArg) { result: Result<Long> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -517,9 +691,9 @@ interface UniversalBlePlatformChannel {
api.writeValue(deviceIdArg, serviceArg, characteristicArg, valueArg, bleOutputPropertyArg) { result: Result<Unit> -> api.writeValue(deviceIdArg, serviceArg, characteristicArg, valueArg, bleOutputPropertyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
reply.reply(wrapResult(null)) reply.reply(UniversalBlePigeonUtils.wrapResult(null))
} }
} }
} }
@@ -536,10 +710,10 @@ interface UniversalBlePlatformChannel {
api.isPaired(deviceIdArg) { result: Result<Boolean> -> api.isPaired(deviceIdArg) { result: Result<Boolean> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -556,10 +730,10 @@ interface UniversalBlePlatformChannel {
api.pair(deviceIdArg) { result: Result<Boolean> -> api.pair(deviceIdArg) { result: Result<Boolean> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -577,7 +751,7 @@ interface UniversalBlePlatformChannel {
api.unPair(deviceIdArg) api.unPair(deviceIdArg)
listOf(null) listOf(null)
} catch (exception: Throwable) { } catch (exception: Throwable) {
wrapError(exception) UniversalBlePigeonUtils.wrapError(exception)
} }
reply.reply(wrapped) reply.reply(wrapped)
} }
@@ -594,10 +768,10 @@ interface UniversalBlePlatformChannel {
api.getSystemDevices(withServicesArg) { result: Result<List<UniversalBleScanResult>> -> api.getSystemDevices(withServicesArg) { result: Result<List<UniversalBleScanResult>> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
reply.reply(wrapError(error)) reply.reply(UniversalBlePigeonUtils.wrapError(error))
} else { } else {
val data = result.getOrNull() val data = result.getOrNull()
reply.reply(wrapResult(data)) reply.reply(UniversalBlePigeonUtils.wrapResult(data))
} }
} }
} }
@@ -614,7 +788,7 @@ interface UniversalBlePlatformChannel {
val wrapped: List<Any?> = try { val wrapped: List<Any?> = try {
listOf(api.getConnectionState(deviceIdArg)) listOf(api.getConnectionState(deviceIdArg))
} catch (exception: Throwable) { } catch (exception: Throwable) {
wrapError(exception) UniversalBlePigeonUtils.wrapError(exception)
} }
reply.reply(wrapped) reply.reply(wrapped)
} }
@@ -650,7 +824,7 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
callback(Result.success(Unit)) callback(Result.success(Unit))
} }
} else { } else {
callback(Result.failure(createConnectionError(channelName))) callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName)))
} }
} }
} }
@@ -667,7 +841,7 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
callback(Result.success(Unit)) callback(Result.success(Unit))
} }
} else { } else {
callback(Result.failure(createConnectionError(channelName))) callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName)))
} }
} }
} }
@@ -684,7 +858,7 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
callback(Result.success(Unit)) callback(Result.success(Unit))
} }
} else { } else {
callback(Result.failure(createConnectionError(channelName))) callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName)))
} }
} }
} }
@@ -701,7 +875,7 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
callback(Result.success(Unit)) callback(Result.success(Unit))
} }
} else { } else {
callback(Result.failure(createConnectionError(channelName))) callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName)))
} }
} }
} }
@@ -718,7 +892,7 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
callback(Result.success(Unit)) callback(Result.success(Unit))
} }
} else { } else {
callback(Result.failure(createConnectionError(channelName))) callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName)))
} }
} }
} }
@@ -2,11 +2,8 @@ package com.navideck.universal_ble
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.bluetooth.le.ScanFilter import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.os.ParcelUuid import android.os.ParcelUuid
import android.util.Log import android.util.Log
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.UUID import java.util.UUID
import kotlin.experimental.and import kotlin.experimental.and
@@ -46,7 +43,7 @@ class UniversalBleFilterUtil {
} }
private fun isNameMatchingFilters(scanFilter: UniversalScanFilter, name: String?): Boolean { private fun isNameMatchingFilters(scanFilter: UniversalScanFilter, name: String?): Boolean {
val namePrefixFilter = scanFilter.withNamePrefix.filterNotNull() val namePrefixFilter = scanFilter.withNamePrefix
if (namePrefixFilter.isEmpty()) { if (namePrefixFilter.isEmpty()) {
return true return true
} }
@@ -74,7 +71,7 @@ class UniversalBleFilterUtil {
scanFilter: UniversalScanFilter, scanFilter: UniversalScanFilter,
manufacturerDataList: List<UniversalManufacturerData>, manufacturerDataList: List<UniversalManufacturerData>,
): Boolean { ): Boolean {
val filters = scanFilter.withManufacturerData.filterNotNull() val filters = scanFilter.withManufacturerData
if (filters.isEmpty()) return true if (filters.isEmpty()) return true
if (manufacturerDataList.isEmpty()) return false if (manufacturerDataList.isEmpty()) return false
return manufacturerDataList.any { msd -> return manufacturerDataList.any { msd ->
@@ -122,8 +119,8 @@ fun UniversalScanFilter.toScanFilters(serviceUuids: List<UUID>): List<ScanFilter
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, e.toString()) Log.e(TAG, e.toString())
throw FlutterError( throw createFlutterError(
"illegalIllegalArgument", UniversalBleErrorCode.INVALID_SERVICE_UUID,
"Invalid serviceId: $service", "Invalid serviceId: $service",
e.toString() e.toString()
) )
@@ -133,7 +130,7 @@ fun UniversalScanFilter.toScanFilters(serviceUuids: List<UUID>): List<ScanFilter
// Add ManufacturerData Filter // Add ManufacturerData Filter
for (manufacturerData in this.withManufacturerData) { for (manufacturerData in this.withManufacturerData) {
try { try {
manufacturerData?.companyIdentifier?.let { manufacturerData.companyIdentifier.let {
val data: ByteArray = manufacturerData.data ?: ByteArray(0) val data: ByteArray = manufacturerData.data ?: ByteArray(0)
val mask: ByteArray? = manufacturerData.mask val mask: ByteArray? = manufacturerData.mask
if (mask == null) { if (mask == null) {
@@ -152,9 +149,9 @@ fun UniversalScanFilter.toScanFilters(serviceUuids: List<UUID>): List<ScanFilter
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, e.toString()) Log.e(TAG, e.toString())
throw FlutterError( throw createFlutterError(
"illegalIllegalArgument", UniversalBleErrorCode.FAILED,
"Invalid manufacturerData: ${manufacturerData?.companyIdentifier} ${manufacturerData?.data} ${manufacturerData?.mask}", "Invalid manufacturerData: ${manufacturerData.companyIdentifier} ${manufacturerData.data} ${manufacturerData.mask}",
e.toString() e.toString()
) )
} }
@@ -17,6 +17,7 @@ import android.util.SparseArray
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
import java.util.UUID import java.util.UUID
import androidx.core.util.size
private const val TAG = "UniversalBlePlugin" private const val TAG = "UniversalBlePlugin"
@@ -46,8 +47,8 @@ enum class BleInputProperty(val value: Long) {
} }
enum class BleOutputProperty(val value: Long) { enum class BleOutputProperty(val value: Long) {
withResponse(0), WithResponse(0),
withoutResponse(1); WithoutResponse(1);
} }
@@ -80,7 +81,10 @@ fun List<String>.toUUIDList(): List<UUID> {
fun String.toBluetoothGatt(): BluetoothGatt { fun String.toBluetoothGatt(): BluetoothGatt {
return this.findGatt() return this.findGatt()
?: throw FlutterError("IllegalArgument", "Unknown deviceId: $this", null) ?: throw createFlutterError(
UniversalBleErrorCode.DEVICE_NOT_FOUND,
"Unknown deviceId: $this",
)
} }
fun String.isKnownGatt(): Boolean { fun String.isKnownGatt(): Boolean {
@@ -122,53 +126,6 @@ fun Int.parseScanErrorMessage(): String {
} }
} }
fun Int.parseBluetoothStatusCodeError(): String? {
if (this == BluetoothStatusCodes.SUCCESS) return null
return when (this) {
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED -> "ERROR_BLUETOOTH_NOT_ENABLED"
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED -> "ERROR_BLUETOOTH_NOT_ALLOWED"
BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED -> "ERROR_DEVICE_NOT_BONDED"
BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED -> "ERROR_GATT_WRITE_NOT_ALLOWED"
BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY -> "ERROR_GATT_WRITE_REQUEST_BUSY"
BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION -> "ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION"
BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND -> "ERROR_PROFILE_SERVICE_NOT_BOUND"
BluetoothStatusCodes.ERROR_UNKNOWN -> "ERROR_UNKNOWN"
BluetoothStatusCodes.FEATURE_NOT_CONFIGURED -> "FEATURE_NOT_CONFIGURED"
BluetoothStatusCodes.FEATURE_NOT_SUPPORTED -> "FEATURE_NOT_SUPPORTED"
BluetoothStatusCodes.FEATURE_SUPPORTED -> "FEATURE_SUPPORTED"
else -> "ErrorCode: $this"
}
}
fun Int.parseGattErrorCode(): String? {
return when (this) {
BluetoothGatt.GATT_SUCCESS -> null
BluetoothGatt.GATT_READ_NOT_PERMITTED -> "GATT_READ_NOT_PERMITTED"
BluetoothGatt.GATT_WRITE_NOT_PERMITTED -> "GATT_WRITE_NOT_PERMITTED"
BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION -> "GATT_INSUFFICIENT_AUTHENTICATION"
BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED -> "GATT_REQUEST_NOT_SUPPORTED"
BluetoothGatt.GATT_INVALID_OFFSET -> "GATT_INVALID_OFFSET"
BluetoothGatt.GATT_INSUFFICIENT_AUTHORIZATION -> "GATT_INSUFFICIENT_AUTHORIZATION"
BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH -> "GATT_INVALID_ATTRIBUTE_LENGTH"
BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION -> "GATT_INSUFFICIENT_ENCRYPTION"
BluetoothGatt.GATT_CONNECTION_CONGESTED -> "GATT_CONNECTION_CONGESTED"
BluetoothGatt.GATT_FAILURE -> "GATT_FAILURE"
BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED -> "ERROR_GATT_WRITE_NOT_ALLOWED"
BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY -> "ERROR_GATT_WRITE_REQUEST_BUSY"
BluetoothStatusCodes.FEATURE_NOT_CONFIGURED -> "FEATURE_NOT_CONFIGURED"
0x01 -> "GATT_INVALID_HANDLE"
0x04 -> "GATT_INVALID_PDU"
0x09 -> "GATT_PREPARE_QUEUE_FULL"
0x0a -> "GATT_ATTR_NOT_FOUND"
0x0b -> "GATT_ATTR_NOT_LONG"
0x0c -> "GATT_INSUFFICIENT_KEY_SIZE"
0x0e -> "GATT_UNLIKELY"
0x10 -> "GATT_UNSUPPORTED_GROUP"
0x11 -> "GATT_INSUFFICIENT_RESOURCES"
else -> "Unknown Error: $this"
}
}
val ScanResult.manufacturerDataList: List<UniversalManufacturerData> val ScanResult.manufacturerDataList: List<UniversalManufacturerData>
get() { get() {
return scanRecord?.manufacturerSpecificData?.toList()?.map { (key, value) -> return scanRecord?.manufacturerSpecificData?.toList()?.map { (key, value) ->
@@ -177,7 +134,7 @@ val ScanResult.manufacturerDataList: List<UniversalManufacturerData>
} }
fun <T> SparseArray<T>.toList(): List<Pair<Int, T>> { fun <T> SparseArray<T>.toList(): List<Pair<Int, T>> {
return (0 until size()).map { index -> return (0 until size).map { index ->
keyAt(index) to valueAt(index) keyAt(index) to valueAt(index)
} }
} }
@@ -189,16 +146,6 @@ fun BluetoothGatt.getCharacteristic(
return getService(UUID.fromString(service))?.getCharacteristic(UUID.fromString(characteristic)) return getService(UUID.fromString(service))?.getCharacteristic(UUID.fromString(characteristic))
} }
fun subscriptionFailedError(error: String? = null): Result<Unit> {
return Result.failure(
FlutterError(
"Failed",
"Failed to update subscription state",
error
)
)
}
fun BluetoothDevice.removeBond() { fun BluetoothDevice.removeBond() {
try { try {
javaClass.getMethod("removeBond").invoke(this) javaClass.getMethod("removeBond").invoke(this)
@@ -207,7 +154,6 @@ fun BluetoothDevice.removeBond() {
} }
} }
fun BluetoothGattCharacteristic.getPropertiesList(): ArrayList<Long> { fun BluetoothGattCharacteristic.getPropertiesList(): ArrayList<Long> {
val propertiesList = arrayListOf<Long>() val propertiesList = arrayListOf<Long>()
if (properties and BluetoothGattCharacteristic.PROPERTY_BROADCAST > 0) { if (properties and BluetoothGattCharacteristic.PROPERTY_BROADCAST > 0) {
@@ -241,16 +187,54 @@ fun BluetoothGattCharacteristic.getPropertiesList(): ArrayList<Long> {
fun Short.toByteArray(byteOrder: ByteOrder = ByteOrder.LITTLE_ENDIAN): ByteArray = fun Short.toByteArray(byteOrder: ByteOrder = ByteOrder.LITTLE_ENDIAN): ByteArray =
ByteBuffer.allocate(2 /*Short.SIZE_BYTES*/).order(byteOrder).putShort(this).array() ByteBuffer.allocate(2 /*Short.SIZE_BYTES*/).order(byteOrder).putShort(this).array()
// Errors
fun unknownCharacteristicError(char: String) =
FlutterError("IllegalArgument", "Unknown error", null)
fun createFlutterError(
code: UniversalBleErrorCode,
message: String? = null,
details: String? = null,
) = FlutterError(code.raw.toString(), message, details ?: code.toString())
val DeviceDisconnectedError: FlutterError = FlutterError( fun gattStatusToUniversalBleErrorCode(code: Int): UniversalBleErrorCode {
"DeviceDisconnected", return when (code) {
"Device Disconnected", BluetoothGatt.GATT_READ_NOT_PERMITTED -> UniversalBleErrorCode.READ_NOT_PERMITTED
null BluetoothGatt.GATT_WRITE_NOT_PERMITTED -> UniversalBleErrorCode.WRITE_NOT_PERMITTED
) BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION -> UniversalBleErrorCode.INSUFFICIENT_AUTHENTICATION
BluetoothGatt.GATT_INSUFFICIENT_AUTHORIZATION -> UniversalBleErrorCode.INSUFFICIENT_AUTHORIZATION
BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION -> UniversalBleErrorCode.INSUFFICIENT_ENCRYPTION
BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED -> UniversalBleErrorCode.OPERATION_NOT_SUPPORTED
BluetoothGatt.GATT_INVALID_OFFSET -> UniversalBleErrorCode.INVALID_OFFSET
BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH -> UniversalBleErrorCode.INVALID_ATTRIBUTE_LENGTH
BluetoothGatt.GATT_CONNECTION_CONGESTED -> UniversalBleErrorCode.CONNECTION_FAILED
BluetoothGatt.GATT_FAILURE -> UniversalBleErrorCode.FAILED
0x01 -> UniversalBleErrorCode.INVALID_HANDLE
0x04 -> UniversalBleErrorCode.INVALID_PDU
0x09 -> UniversalBleErrorCode.OPERATION_IN_PROGRESS
0x0a -> UniversalBleErrorCode.SERVICE_NOT_FOUND
0x0b -> UniversalBleErrorCode.INVALID_ATTRIBUTE_LENGTH
0x0c -> UniversalBleErrorCode.INSUFFICIENT_KEY_SIZE
0x0e -> UniversalBleErrorCode.FAILED
0x10 -> UniversalBleErrorCode.OPERATION_NOT_SUPPORTED
0x11 -> UniversalBleErrorCode.FAILED
else -> UniversalBleErrorCode.UNKNOWN_ERROR
}
}
fun Int.parseBluetoothStatusCodeError(): UniversalBleErrorCode? {
if (this == BluetoothStatusCodes.SUCCESS) return null
return when (this) {
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED -> UniversalBleErrorCode.BLUETOOTH_NOT_ENABLED
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED -> UniversalBleErrorCode.BLUETOOTH_NOT_ALLOWED
BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED -> UniversalBleErrorCode.NOT_PAIRED
BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED -> UniversalBleErrorCode.WRITE_NOT_PERMITTED
BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY -> UniversalBleErrorCode.WRITE_REQUEST_BUSY
BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION -> UniversalBleErrorCode.CONNECTION_FAILED
BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND -> UniversalBleErrorCode.SERVICE_NOT_FOUND
BluetoothStatusCodes.ERROR_UNKNOWN -> UniversalBleErrorCode.UNKNOWN_ERROR
BluetoothStatusCodes.FEATURE_NOT_CONFIGURED -> UniversalBleErrorCode.NOT_IMPLEMENTED
BluetoothStatusCodes.FEATURE_NOT_SUPPORTED -> UniversalBleErrorCode.NOT_SUPPORTED
else -> null
}
}
fun Int.parseHciErrorCode(): String? { fun Int.parseHciErrorCode(): String? {
return when (this) { return when (this) {
@@ -32,6 +32,7 @@ import io.flutter.plugin.common.PluginRegistry
import java.util.UUID import java.util.UUID
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import androidx.core.content.edit
private const val TAG = "UniversalBlePlugin" private const val TAG = "UniversalBlePlugin"
@@ -102,7 +103,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
if (bluetoothEnableRequestFuture != null) { if (bluetoothEnableRequestFuture != null) {
callback( callback(
Result.failure( Result.failure(
FlutterError("Failed", "Bluetooth enable request in progress", null) createFlutterError(
UniversalBleErrorCode.OPERATION_IN_PROGRESS,
"Bluetooth enable request in progress"
)
) )
) )
return return
@@ -120,7 +124,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
if (bluetoothDisableRequestFuture != null) { if (bluetoothDisableRequestFuture != null) {
callback( callback(
Result.failure( Result.failure(
FlutterError("Failed", "Bluetooth disable request in progress", null) createFlutterError(
UniversalBleErrorCode.OPERATION_IN_PROGRESS,
"Bluetooth disable request in progress"
)
) )
) )
return return
@@ -131,9 +138,9 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} }
override fun startScan(filter: UniversalScanFilter?) { override fun startScan(filter: UniversalScanFilter?) {
if (!isBluetoothAvailable()) throw FlutterError( if (!isBluetoothAvailable()) throw createFlutterError(
"BluetoothNotEnabled", UniversalBleErrorCode.BLUETOOTH_NOT_ENABLED,
"Bluetooth not enabled", "Bluetooth not enabled"
) )
val builder = ScanSettings.Builder() val builder = ScanSettings.Builder()
@@ -143,10 +150,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} }
val settings = builder.build() val settings = builder.build()
val usesCustomFilters = filter?.usesCustomFilters() ?: false; val usesCustomFilters = filter?.usesCustomFilters() ?: false
try { try {
val filterServices = filter?.withServices?.filterNotNull()?.toUUIDList() ?: emptyList() val filterServices = filter?.withServices?.toUUIDList() ?: emptyList()
var scanFilters = emptyList<ScanFilter>() var scanFilters = emptyList<ScanFilter>()
// Set custom scan filter only if required // Set custom scan filter only if required
@@ -156,25 +163,25 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
universalBleFilterUtil.serviceFilterUUIDS = filterServices universalBleFilterUtil.serviceFilterUUIDS = filterServices
} else { } else {
universalBleFilterUtil.scanFilter = null universalBleFilterUtil.scanFilter = null
scanFilters = filter?.toScanFilters(filterServices) ?: emptyList<ScanFilter>() scanFilters = filter?.toScanFilters(filterServices) ?: emptyList()
} }
safeScanner.startScan( safeScanner.startScan(
scanFilters, settings, scanCallback scanFilters, settings, scanCallback
) )
} catch (e: Exception) { } catch (e: Exception) {
throw FlutterError( throw createFlutterError(
"illegalIllegalArgument", UniversalBleErrorCode.FAILED,
"Failed to start Scan", "Failed to start Scan",
e.toString() details = e.toString()
) )
} }
} }
override fun stopScan() { override fun stopScan() {
if (!isBluetoothAvailable()) throw FlutterError( if (!isBluetoothAvailable()) throw createFlutterError(
"BluetoothNotEnabled", UniversalBleErrorCode.BLUETOOTH_NOT_ENABLED,
"Bluetooth not enabled", "Bluetooth not enabled"
) )
// check if already scanning // check if already scanning
safeScanner.stopScan(scanCallback) safeScanner.stopScan(scanCallback)
@@ -192,7 +199,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} }
return return
} else if (currentState == BluetoothGatt.STATE_CONNECTING) { } else if (currentState == BluetoothGatt.STATE_CONNECTING) {
throw FlutterError("Connecting", "Connection already in progress", null) throw createFlutterError(
UniversalBleErrorCode.CONNECTION_IN_PROGRESS,
"Connection already in progress"
)
} }
} }
@@ -240,7 +250,12 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
discoverServicesFutureList.add(DiscoverServicesFuture(deviceId, callback)) discoverServicesFutureList.add(DiscoverServicesFuture(deviceId, callback))
} else { } else {
callback( callback(
Result.failure(FlutterError("Failed", "Failed to discover services", null)) Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to discover services"
)
)
) )
} }
} catch (e: FlutterError) { } catch (e: FlutterError) {
@@ -253,7 +268,12 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
discoverServicesFutureList.filter { it.deviceId == gatt.device.address }.forEach { discoverServicesFutureList.filter { it.deviceId == gatt.device.address }.forEach {
discoverServicesFutureList.remove(it) discoverServicesFutureList.remove(it)
it.result( it.result(
Result.failure(FlutterError("Failed", "Failed to discover services", null)) Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to discover services"
)
)
) )
} }
return return
@@ -290,7 +310,14 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
gatt.getCharacteristic(service, characteristic) gatt.getCharacteristic(service, characteristic)
if (gattCharacteristic == null) { if (gattCharacteristic == null) {
callback(subscriptionFailedError("characteristic not found")) callback(
Result.failure(
createFlutterError(
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
"characteristic not found"
)
)
)
return return
} }
@@ -298,7 +325,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
gattCharacteristic.getDescriptor(ccdCharacteristic) gattCharacteristic.getDescriptor(ccdCharacteristic)
val bleInputPropertyEnum: BleInputProperty = val bleInputPropertyEnum: BleInputProperty =
BleInputProperty.values().first { it.value == bleInputProperty } BleInputProperty.entries.first { it.value == bleInputProperty }
val (value, enable) = when (bleInputPropertyEnum) { val (value, enable) = when (bleInputPropertyEnum) {
BleInputProperty.Notification -> BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE to true BleInputProperty.Notification -> BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE to true
@@ -310,14 +337,30 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
// Some devices do not need CCCD to update // Some devices do not need CCCD to update
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val status = gatt.writeDescriptor(descriptor, value)
if (gatt.writeDescriptor(descriptor, value) != BluetoothStatusCodes.SUCCESS) { if (gatt.writeDescriptor(descriptor, value) != BluetoothStatusCodes.SUCCESS) {
callback(subscriptionFailedError("Failed to update descriptor")) callback(
Result.failure(
createFlutterError(
status.parseBluetoothStatusCodeError()
?: UniversalBleErrorCode.FAILED,
"Failed to update descriptor"
)
)
)
return return
} }
} else { } else {
descriptor.value = value descriptor.value = value
if (!gatt.writeDescriptor(descriptor)) { if (!gatt.writeDescriptor(descriptor)) {
callback(subscriptionFailedError("Failed to update descriptor")) callback(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to update descriptor"
)
)
)
return return
} }
} }
@@ -339,12 +382,27 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
callback(Result.success(Unit)) callback(Result.success(Unit))
} }
} else { } else {
callback(subscriptionFailedError()) callback(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to update subscription state"
)
)
)
} }
} catch (e: FlutterError) { } catch (e: FlutterError) {
callback(Result.failure(e)) callback(Result.failure(e))
} catch (e: Exception) { } catch (e: Exception) {
callback(subscriptionFailedError(e.toString())) callback(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to update subscription state",
e.toString()
)
)
)
} }
} }
@@ -359,13 +417,23 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
val gattCharacteristic = gatt.getCharacteristic(service, characteristic) val gattCharacteristic = gatt.getCharacteristic(service, characteristic)
if (gattCharacteristic == null) { if (gattCharacteristic == null) {
callback( callback(
Result.failure(FlutterError("IllegalArgument", "Unknown characteristic", null)) Result.failure(
createFlutterError(
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
"Unknown characteristic"
)
)
) )
return return
} }
if (!gatt.readCharacteristic(gattCharacteristic)) { if (!gatt.readCharacteristic(gattCharacteristic)) {
callback( callback(
Result.failure(unknownCharacteristicError(characteristic)) Result.failure(
createFlutterError(
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
"$characteristic not found",
)
)
) )
return return
} }
@@ -383,8 +451,8 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} catch (e: Exception) { } catch (e: Exception) {
callback( callback(
Result.failure( Result.failure(
FlutterError( createFlutterError(
"Failed", UniversalBleErrorCode.READ_FAILED,
"Failed to read value", "Failed to read value",
e.toString() e.toString()
) )
@@ -410,10 +478,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} else { } else {
it.result( it.result(
Result.failure( Result.failure(
FlutterError( createFlutterError(
status.toString(), gattStatusToUniversalBleErrorCode(status),
"Failed to read: (${status.parseGattErrorCode()})", "Failed to read",
null, status.toString()
) )
) )
) )
@@ -434,33 +502,38 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
val gatt = deviceId.toBluetoothGatt() val gatt = deviceId.toBluetoothGatt()
val gattCharacteristic = gatt.getCharacteristic(service, characteristic) val gattCharacteristic = gatt.getCharacteristic(service, characteristic)
if (gattCharacteristic == null) { if (gattCharacteristic == null) {
callback(Result.failure(unknownCharacteristicError(characteristic))) callback(
Result.failure(
createFlutterError(
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
"$characteristic not found",
)
)
)
return return
} }
var writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT var writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
if (bleOutputProperty == BleOutputProperty.withResponse.value) { if (bleOutputProperty == BleOutputProperty.WithResponse.value) {
if (gattCharacteristic.properties and BluetoothGattCharacteristic.PROPERTY_WRITE == 0) { if (gattCharacteristic.properties and BluetoothGattCharacteristic.PROPERTY_WRITE == 0) {
callback( callback(
Result.failure( Result.failure(
FlutterError( createFlutterError(
"IllegalArgument", UniversalBleErrorCode.CHARACTERISTIC_DOES_NOT_SUPPORT_WRITE,
"Characteristic does not support write withResponse", "Characteristic does not support write withResponse"
null
) )
) )
) )
return return
} }
writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
} else if (bleOutputProperty == BleOutputProperty.withoutResponse.value) { } else if (bleOutputProperty == BleOutputProperty.WithoutResponse.value) {
if (gattCharacteristic.properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE == 0) { if (gattCharacteristic.properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE == 0) {
callback( callback(
Result.failure( Result.failure(
FlutterError( createFlutterError(
"IllegalArgument", UniversalBleErrorCode.CHARACTERISTIC_DOES_NOT_SUPPORT_WRITE_WITHOUT_RESPONSE,
"Characteristic does not support write withoutResponse", "Characteristic does not support write withoutResponse"
null
) )
) )
) )
@@ -495,10 +568,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
writeResultFutureList.remove(writeFuture) writeResultFutureList.remove(writeFuture)
callback( callback(
Result.failure( Result.failure(
FlutterError( createFlutterError(
"WriteError", gattStatusToUniversalBleErrorCode(result),
"Failed to write: ${result.parseGattErrorCode()}", "Failed to write",
null result.toString()
) )
) )
) )
@@ -524,10 +597,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} else { } else {
it.result( it.result(
Result.failure( Result.failure(
FlutterError( createFlutterError(
status.toString(), gattStatusToUniversalBleErrorCode(status),
"Failed to write: (${status.parseGattErrorCode()})", "Failed to write",
null, status.toString()
) )
) )
) )
@@ -553,7 +626,14 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
if (status == BluetoothGatt.GATT_SUCCESS) { if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(mtu.toLong())) it.result(Result.success(mtu.toLong()))
} else { } else {
it.result(Result.failure(FlutterError("Failed to change MTU", null, null))) it.result(
Result.failure(
createFlutterError(
UniversalBleErrorCode.FAILED,
"Failed to change MTU"
)
)
)
} }
} }
} }
@@ -580,10 +660,9 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
if (pendingFuture != null) { if (pendingFuture != null) {
callback( callback(
Result.failure( Result.failure(
FlutterError( createFlutterError(
"InProgress", UniversalBleErrorCode.OPERATION_IN_PROGRESS,
"Pairing already in progress", "Pairing already in progress"
null
) )
) )
) )
@@ -594,12 +673,19 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
if (remoteDevice.createBond()) { if (remoteDevice.createBond()) {
pairResultFutures[deviceId] = callback pairResultFutures[deviceId] = callback
} else { } else {
callback(Result.failure(FlutterError("Failed", "Failed to pair", null))) callback(
Result.failure(
createFlutterError(
UniversalBleErrorCode.PAIRING_FAILED,
"Failed to pair"
)
)
)
} }
} catch (e: Exception) { } catch (e: Exception) {
callback( callback(
Result.failure( Result.failure(
FlutterError("Failed", e.toString(), null) createFlutterError(UniversalBleErrorCode.FAILED, e.toString())
) )
) )
} }
@@ -664,7 +750,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
try { try {
val timeout = (devices.size * 2).toLong() val timeout = (devices.size * 2).toLong()
latch.await(timeout, TimeUnit.SECONDS) latch.await(timeout, TimeUnit.SECONDS)
} catch (e: InterruptedException) { } catch (_: InterruptedException) {
Thread.currentThread().interrupt() Thread.currentThread().interrupt()
} }
@@ -749,10 +835,13 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
private fun cleanConnection(gatt: BluetoothGatt) { private fun cleanConnection(gatt: BluetoothGatt) {
gatt.removeCache() gatt.removeCache()
gatt.disconnect() gatt.disconnect()
val deviceDisconnectedError: FlutterError = createFlutterError(
UniversalBleErrorCode.DEVICE_DISCONNECTED,
"Device Disconnected",
)
readResultFutureList.removeAll { readResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) { if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError)) it.result(Result.failure(deviceDisconnectedError))
true true
} else { } else {
false false
@@ -760,7 +849,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} }
writeResultFutureList.removeAll { writeResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) { if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError)) it.result(Result.failure(deviceDisconnectedError))
true true
} else { } else {
false false
@@ -768,7 +857,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} }
subscriptionResultFutureList.removeAll { subscriptionResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) { if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError)) it.result(Result.failure(deviceDisconnectedError))
true true
} else { } else {
false false
@@ -776,7 +865,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} }
mtuResultFutureList.removeAll { mtuResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) { if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError)) it.result(Result.failure(deviceDisconnectedError))
true true
} else { } else {
false false
@@ -784,7 +873,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
} }
discoverServicesFutureList.removeAll { discoverServicesFutureList.removeAll {
if (it.deviceId == gatt.device.address) { if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError)) it.result(Result.failure(deviceDisconnectedError))
true true
} else { } else {
false false
@@ -830,7 +919,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
Log.v(TAG, "${device.address} BOND_BONDING") Log.v(TAG, "${device.address} BOND_BONDING")
} }
BluetoothDevice.BOND_BONDED -> { BOND_BONDED -> {
onBondStateUpdate(device.address, true) onBondStateUpdate(device.address, true)
} }
@@ -944,7 +1033,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
if (descriptor?.uuid.toString() == ccdCharacteristic.toString()) { if (descriptor?.uuid.toString() == ccdCharacteristic.toString()) {
val char: String? = descriptor?.characteristic?.uuid?.toString() val char: String? = descriptor?.characteristic?.uuid?.toString()
val service: String? = descriptor?.characteristic?.service?.uuid?.toString() val service: String? = descriptor?.characteristic?.service?.uuid?.toString()
val deviceId: String? = gatt?.device?.address; val deviceId: String? = gatt?.device?.address
if (deviceId != null && char != null && service != null) { if (deviceId != null && char != null && service != null) {
updateSubscriptionState(deviceId, char, service, status) updateSubscriptionState(deviceId, char, service, status)
} }
@@ -963,14 +1052,13 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
it.serviceId == service it.serviceId == service
}.forEach { }.forEach {
subscriptionResultFutureList.remove(it) subscriptionResultFutureList.remove(it)
val error: String? = status.parseGattErrorCode() if (status != BluetoothGatt.GATT_SUCCESS) {
if (error != null) {
it.result( it.result(
Result.failure( Result.failure(
FlutterError( createFlutterError(
status.toString(), gattStatusToUniversalBleErrorCode(status),
"Failed to update subscription state: $error", "Failed to update subscription state",
null, status.toString()
) )
) )
) )
@@ -989,7 +1077,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
"com.navideck.universal_ble.services", "com.navideck.universal_ble.services",
Context.MODE_PRIVATE Context.MODE_PRIVATE
) )
cachedServicesSharedPref.edit().putStringSet(deviceId, services.toSet()).apply() cachedServicesSharedPref.edit { putStringSet(deviceId, services.toSet()) }
cachedServicesMap[deviceId] = services cachedServicesMap[deviceId] = services
} }
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
echo "Building pigeon..."
dart run pigeon --input pigeon/universal_ble.dart
echo "Pigeon built successfully"
echo "Formatting generated files..."
dart format lib/src/universal_ble_pigeon/universal_ble.g.dart
echo "Generated files formatted successfully"
echo "Done"
+194 -32
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v22.6.1), do not edit directly. // Autogenerated from Pigeon (v26.0.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
import Foundation import Foundation
@@ -15,9 +15,9 @@ import Foundation
final class PigeonError: Error { final class PigeonError: Error {
let code: String let code: String
let message: String? let message: String?
let details: Any? let details: Sendable?
init(code: String, message: String?, details: Any?) { init(code: String, message: String?, details: Sendable?) {
self.code = code self.code = code
self.message = message self.message = message
self.details = details self.details = details
@@ -68,8 +68,137 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
return value as! T? return value as! T?
} }
func deepEqualsUniversalBle(_ lhs: Any?, _ rhs: Any?) -> Bool {
let cleanLhs = nilOrValue(lhs) as Any?
let cleanRhs = nilOrValue(rhs) as Any?
switch (cleanLhs, cleanRhs) {
case (nil, nil):
return true
case (nil, _), (_, nil):
return false
case is (Void, Void):
return true
case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable):
return cleanLhsHashable == cleanRhsHashable
case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]):
guard cleanLhsArray.count == cleanRhsArray.count else { return false }
for (index, element) in cleanLhsArray.enumerated() {
if !deepEqualsUniversalBle(element, cleanRhsArray[index]) {
return false
}
}
return true
case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false }
for (key, cleanLhsValue) in cleanLhsDictionary {
guard cleanRhsDictionary.index(forKey: key) != nil else { return false }
if !deepEqualsUniversalBle(cleanLhsValue, cleanRhsDictionary[key]!) {
return false
}
}
return true
default:
// Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue.
return false
}
}
func deepHashUniversalBle(value: Any?, hasher: inout Hasher) {
if let valueList = value as? [AnyHashable] {
for item in valueList { deepHashUniversalBle(value: item, hasher: &hasher) }
return
}
if let valueDict = value as? [AnyHashable: AnyHashable] {
for key in valueDict.keys {
hasher.combine(key)
deepHashUniversalBle(value: valueDict[key]!, hasher: &hasher)
}
return
}
if let hashableValue = value as? AnyHashable {
hasher.combine(hashableValue.hashValue)
}
return hasher.combine(String(describing: value))
}
/// Unified error codes for all platforms
enum UniversalBleErrorCode: Int {
case unknownError = 0
case failed = 1
case notSupported = 2
case notImplemented = 3
case channelError = 4
case bluetoothNotAvailable = 5
case bluetoothNotEnabled = 6
case bluetoothNotAllowed = 7
case bluetoothUnauthorized = 8
case deviceDisconnected = 9
case connectionTimeout = 10
case connectionFailed = 11
case connectionRejected = 12
case connectionLimitExceeded = 13
case connectionAlreadyExists = 14
case connectionTerminated = 15
case connectionInProgress = 16
case illegalArgument = 17
case deviceNotFound = 18
case serviceNotFound = 19
case characteristicNotFound = 20
case invalidServiceUuid = 21
case invalidCharacteristicUuid = 22
case invalidOffset = 23
case invalidAttributeLength = 24
case invalidPdu = 25
case invalidHandle = 26
case readFailed = 27
case readNotPermitted = 28
case writeFailed = 29
case writeNotPermitted = 30
case writeRequestBusy = 31
case invalidAction = 32
case operationNotSupported = 33
case operationTimeout = 34
case operationCancelled = 35
case operationInProgress = 36
case characteristicDoesNotSupportRead = 37
case characteristicDoesNotSupportWrite = 38
case characteristicDoesNotSupportWriteWithoutResponse = 39
case characteristicDoesNotSupportNotify = 40
case characteristicDoesNotSupportIndicate = 41
case notPaired = 42
case notPairable = 43
case alreadyPaired = 44
case pairingFailed = 45
case pairingCancelled = 46
case pairingTimeout = 47
case pairingNotAllowed = 48
case authenticationFailure = 49
case insufficientAuthentication = 50
case insufficientAuthorization = 51
case insufficientEncryption = 52
case insufficientKeySize = 53
case protectionLevelNotMet = 54
case accessDenied = 55
case unpairingFailed = 56
case alreadyUnpaired = 57
case scanFailed = 58
case stoppingScanInProgress = 59
case webBluetoothGloballyDisabled = 60
}
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalBleScanResult { struct UniversalBleScanResult: Hashable {
var deviceId: String var deviceId: String
var name: String? = nil var name: String? = nil
var isPaired: Bool? = nil var isPaired: Bool? = nil
@@ -78,7 +207,6 @@ struct UniversalBleScanResult {
var services: [String]? = nil var services: [String]? = nil
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleScanResult? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleScanResult? {
let deviceId = pigeonVar_list[0] as! String let deviceId = pigeonVar_list[0] as! String
@@ -107,15 +235,19 @@ struct UniversalBleScanResult {
services, services,
] ]
} }
static func == (lhs: UniversalBleScanResult, rhs: UniversalBleScanResult) -> Bool {
return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashUniversalBle(value: toList(), hasher: &hasher)
}
} }
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalBleService { struct UniversalBleService: Hashable {
var uuid: String var uuid: String
var characteristics: [UniversalBleCharacteristic]? = nil var characteristics: [UniversalBleCharacteristic]? = nil
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleService? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleService? {
let uuid = pigeonVar_list[0] as! String let uuid = pigeonVar_list[0] as! String
@@ -132,15 +264,19 @@ struct UniversalBleService {
characteristics, characteristics,
] ]
} }
static func == (lhs: UniversalBleService, rhs: UniversalBleService) -> Bool {
return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashUniversalBle(value: toList(), hasher: &hasher)
}
} }
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalBleCharacteristic { struct UniversalBleCharacteristic: Hashable {
var uuid: String var uuid: String
var properties: [Int64] var properties: [Int64]
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleCharacteristic? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleCharacteristic? {
let uuid = pigeonVar_list[0] as! String let uuid = pigeonVar_list[0] as! String
@@ -157,18 +293,22 @@ struct UniversalBleCharacteristic {
properties, properties,
] ]
} }
static func == (lhs: UniversalBleCharacteristic, rhs: UniversalBleCharacteristic) -> Bool {
return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashUniversalBle(value: toList(), hasher: &hasher)
}
} }
/// Scan Filters /// Scan Filters
/// ///
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalScanFilter { struct UniversalScanFilter: Hashable {
var withServices: [String] var withServices: [String]
var withNamePrefix: [String] var withNamePrefix: [String]
var withManufacturerData: [UniversalManufacturerDataFilter] var withManufacturerData: [UniversalManufacturerDataFilter]
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalScanFilter? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalScanFilter? {
let withServices = pigeonVar_list[0] as! [String] let withServices = pigeonVar_list[0] as! [String]
@@ -188,16 +328,20 @@ struct UniversalScanFilter {
withManufacturerData, withManufacturerData,
] ]
} }
static func == (lhs: UniversalScanFilter, rhs: UniversalScanFilter) -> Bool {
return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashUniversalBle(value: toList(), hasher: &hasher)
}
} }
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalManufacturerDataFilter { struct UniversalManufacturerDataFilter: Hashable {
var companyIdentifier: Int64 var companyIdentifier: Int64
var data: FlutterStandardTypedData? = nil var data: FlutterStandardTypedData? = nil
var mask: FlutterStandardTypedData? = nil var mask: FlutterStandardTypedData? = nil
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerDataFilter? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerDataFilter? {
let companyIdentifier = pigeonVar_list[0] as! Int64 let companyIdentifier = pigeonVar_list[0] as! Int64
@@ -217,15 +361,19 @@ struct UniversalManufacturerDataFilter {
mask, mask,
] ]
} }
static func == (lhs: UniversalManufacturerDataFilter, rhs: UniversalManufacturerDataFilter) -> Bool {
return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashUniversalBle(value: toList(), hasher: &hasher)
}
} }
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalManufacturerData { struct UniversalManufacturerData: Hashable {
var companyIdentifier: Int64 var companyIdentifier: Int64
var data: FlutterStandardTypedData var data: FlutterStandardTypedData
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerData? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerData? {
let companyIdentifier = pigeonVar_list[0] as! Int64 let companyIdentifier = pigeonVar_list[0] as! Int64
@@ -242,22 +390,33 @@ struct UniversalManufacturerData {
data, data,
] ]
} }
static func == (lhs: UniversalManufacturerData, rhs: UniversalManufacturerData) -> Bool {
return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) }
func hash(into hasher: inout Hasher) {
deepHashUniversalBle(value: toList(), hasher: &hasher)
}
} }
private class UniversalBlePigeonCodecReader: FlutterStandardReader { private class UniversalBlePigeonCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? { override func readValue(ofType type: UInt8) -> Any? {
switch type { switch type {
case 129: case 129:
return UniversalBleScanResult.fromList(self.readValue() as! [Any?]) let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
if let enumResultAsInt = enumResultAsInt {
return UniversalBleErrorCode(rawValue: enumResultAsInt)
}
return nil
case 130: case 130:
return UniversalBleService.fromList(self.readValue() as! [Any?]) return UniversalBleScanResult.fromList(self.readValue() as! [Any?])
case 131: case 131:
return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?]) return UniversalBleService.fromList(self.readValue() as! [Any?])
case 132: case 132:
return UniversalScanFilter.fromList(self.readValue() as! [Any?]) return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?])
case 133: case 133:
return UniversalManufacturerDataFilter.fromList(self.readValue() as! [Any?]) return UniversalScanFilter.fromList(self.readValue() as! [Any?])
case 134: case 134:
return UniversalManufacturerDataFilter.fromList(self.readValue() as! [Any?])
case 135:
return UniversalManufacturerData.fromList(self.readValue() as! [Any?]) return UniversalManufacturerData.fromList(self.readValue() as! [Any?])
default: default:
return super.readValue(ofType: type) return super.readValue(ofType: type)
@@ -267,24 +426,27 @@ private class UniversalBlePigeonCodecReader: FlutterStandardReader {
private class UniversalBlePigeonCodecWriter: FlutterStandardWriter { private class UniversalBlePigeonCodecWriter: FlutterStandardWriter {
override func writeValue(_ value: Any) { override func writeValue(_ value: Any) {
if let value = value as? UniversalBleScanResult { if let value = value as? UniversalBleErrorCode {
super.writeByte(129) super.writeByte(129)
super.writeValue(value.toList()) super.writeValue(value.rawValue)
} else if let value = value as? UniversalBleService { } else if let value = value as? UniversalBleScanResult {
super.writeByte(130) super.writeByte(130)
super.writeValue(value.toList()) super.writeValue(value.toList())
} else if let value = value as? UniversalBleCharacteristic { } else if let value = value as? UniversalBleService {
super.writeByte(131) super.writeByte(131)
super.writeValue(value.toList()) super.writeValue(value.toList())
} else if let value = value as? UniversalScanFilter { } else if let value = value as? UniversalBleCharacteristic {
super.writeByte(132) super.writeByte(132)
super.writeValue(value.toList()) super.writeValue(value.toList())
} else if let value = value as? UniversalManufacturerDataFilter { } else if let value = value as? UniversalScanFilter {
super.writeByte(133) super.writeByte(133)
super.writeValue(value.toList()) super.writeValue(value.toList())
} else if let value = value as? UniversalManufacturerData { } else if let value = value as? UniversalManufacturerDataFilter {
super.writeByte(134) super.writeByte(134)
super.writeValue(value.toList()) super.writeValue(value.toList())
} else if let value = value as? UniversalManufacturerData {
super.writeByte(135)
super.writeValue(value.toList())
} else { } else {
super.writeValue(value) super.writeValue(value)
} }
@@ -650,7 +812,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
let details: String? = nilOrValue(listResponse[2]) let details: String? = nilOrValue(listResponse[2])
completion(.failure(PigeonError(code: code, message: message, details: details))) completion(.failure(PigeonError(code: code, message: message, details: details)))
} else { } else {
completion(.success(Void())) completion(.success(()))
} }
} }
} }
@@ -668,7 +830,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
let details: String? = nilOrValue(listResponse[2]) let details: String? = nilOrValue(listResponse[2])
completion(.failure(PigeonError(code: code, message: message, details: details))) completion(.failure(PigeonError(code: code, message: message, details: details)))
} else { } else {
completion(.success(Void())) completion(.success(()))
} }
} }
} }
@@ -686,7 +848,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
let details: String? = nilOrValue(listResponse[2]) let details: String? = nilOrValue(listResponse[2])
completion(.failure(PigeonError(code: code, message: message, details: details))) completion(.failure(PigeonError(code: code, message: message, details: details)))
} else { } else {
completion(.success(Void())) completion(.success(()))
} }
} }
} }
@@ -704,7 +866,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
let details: String? = nilOrValue(listResponse[2]) let details: String? = nilOrValue(listResponse[2])
completion(.failure(PigeonError(code: code, message: message, details: details))) completion(.failure(PigeonError(code: code, message: message, details: details)))
} else { } else {
completion(.success(Void())) completion(.success(()))
} }
} }
} }
@@ -722,7 +884,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
let details: String? = nilOrValue(listResponse[2]) let details: String? = nilOrValue(listResponse[2])
completion(.failure(PigeonError(code: code, message: message, details: details))) completion(.failure(PigeonError(code: code, message: message, details: details)))
} else { } else {
completion(.success(Void())) completion(.success(()))
} }
} }
} }
+59 -2
View File
@@ -103,12 +103,69 @@ extension CBManagerState {
} }
} }
/// Maps string error codes to UniversalBleErrorCode enum
func mapErrorCodeToEnum(_ code: String) -> UniversalBleErrorCode {
switch code.lowercased() {
case "notsupported", "not_supported":
return .notSupported
case "notimplemented", "not_implemented":
return .notImplemented
case "channel-error", "channelerror":
return .channelError
case "failed":
return .failed
case "devicedisconnected", "device_disconnected":
return .deviceDisconnected
case "illegalargument", "illegal_argument":
return .illegalArgument
case "invalidaction", "invalid_action":
return .invalidAction
case "readfailed", "read_failed":
return .readFailed
case "devicenotfound", "device_not_found":
return .deviceNotFound
case "servicenotfound", "service_not_found":
return .serviceNotFound
case "characteristicnotfound", "characteristic_not_found":
return .characteristicNotFound
case "invalidserviceuuid", "invalid_service_uuid":
return .invalidServiceUuid
case "characteristicdoesnotsupportread":
return .characteristicDoesNotSupportRead
case "characteristicdoesnotsupportwrite":
return .characteristicDoesNotSupportWrite
case "characteristicdoesnotsupportwritewithoutresponse":
return .characteristicDoesNotSupportWriteWithoutResponse
case "characteristicdoesnotsupportnotify":
return .characteristicDoesNotSupportNotify
case "characteristicdoesnotsupportindicate":
return .characteristicDoesNotSupportIndicate
default:
return .unknownError
}
}
/// Creates a PigeonError with the error code enum in details
func createFlutterError(
code: UniversalBleErrorCode,
message: String? = nil,
details: String? = nil
) -> PigeonError {
// Pass the enum's rawValue (Int) in code as string, and enum name in details
return PigeonError(
code: code.rawValue.description,
message: message,
details: details ?? code.rawValue
)
}
extension Error { extension Error {
func toPigeonError() -> PigeonError { func toFlutterError() -> PigeonError {
let nsError = self as NSError let nsError = self as NSError
let errorCode: String = .init(nsError.code) let errorCode: String = .init(nsError.code)
let errorDescription: String = nsError.localizedDescription let errorDescription: String = nsError.localizedDescription
return PigeonError(code: errorCode, message: errorDescription, details: nil) let mappedCode = mapErrorCodeToEnum(errorCode)
return createFlutterError(code: mappedCode, message: errorDescription, details: errorCode)
} }
} }
+33 -33
View File
@@ -55,11 +55,11 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
} }
func enableBluetooth(completion: @escaping (Result<Bool, Error>) -> Void) { func enableBluetooth(completion: @escaping (Result<Bool, Error>) -> Void) {
completion(Result.failure(PigeonError(code: "NotSupported", message: nil, details: nil))) completion(Result.failure(createFlutterError(code: .notSupported)))
} }
func disableBluetooth(completion: @escaping (Result<Bool, any Error>) -> Void) { func disableBluetooth(completion: @escaping (Result<Bool, any Error>) -> Void) {
completion(Result.failure(PigeonError(code: "NotSupported", message: nil, details: nil))) completion(Result.failure(createFlutterError(code: .notSupported)))
} }
func startScan(filter: UniversalScanFilter?) throws { func startScan(filter: UniversalScanFilter?) throws {
@@ -122,7 +122,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
characteristicReadFutures.removeAll { future in characteristicReadFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
) )
return true return true
} }
@@ -131,7 +131,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
characteristicWriteFutures.removeAll { future in characteristicWriteFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
) )
return true return true
} }
@@ -140,7 +140,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
characteristicNotifyFutures.removeAll { future in characteristicNotifyFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
) )
return true return true
} }
@@ -149,7 +149,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
discoverServicesFutures.removeAll { future in discoverServicesFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
) )
return true return true
} }
@@ -161,7 +161,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func discoverServices(deviceId: String, completion: @escaping (Result<[UniversalBleService], Error>) -> Void) { func discoverServices(deviceId: String, completion: @escaping (Result<[UniversalBleService], Error>) -> Void) {
guard let peripheral = deviceId.findPeripheral(manager: manager) else { guard let peripheral = deviceId.findPeripheral(manager: manager) else {
completion( completion(
Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)) Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(self)"))
) )
return return
} }
@@ -198,22 +198,22 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func setNotifiable(deviceId: String, service: String, characteristic: String, bleInputProperty: Int64, completion: @escaping (Result<Void, any Error>) -> Void) { func setNotifiable(deviceId: String, service: String, characteristic: String, bleInputProperty: Int64, completion: @escaping (Result<Void, any Error>) -> Void) {
guard let peripheral = deviceId.findPeripheral(manager: manager) else { guard let peripheral = deviceId.findPeripheral(manager: manager) else {
completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(deviceId)")))
return return
} }
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else { guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicNotFound, message: "Unknown characteristic:\(characteristic)")))
return return
} }
if bleInputProperty == BleInputProperty.notification.rawValue && !gattCharacteristic.properties.contains(.notify) { if bleInputProperty == BleInputProperty.notification.rawValue && !gattCharacteristic.properties.contains(.notify) {
completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support notify", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicDoesNotSupportNotify, message: "Characteristic does not support notify")))
return return
} }
if bleInputProperty == BleInputProperty.indication.rawValue && !gattCharacteristic.properties.contains(.indicate) { if bleInputProperty == BleInputProperty.indication.rawValue && !gattCharacteristic.properties.contains(.indicate) {
completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support indicate", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicDoesNotSupportIndicate, message: "Characteristic does not support indicate")))
return return
} }
@@ -224,15 +224,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func readValue(deviceId: String, service: String, characteristic: String, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) { func readValue(deviceId: String, service: String, characteristic: String, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
guard let peripheral = deviceId.findPeripheral(manager: manager) else { guard let peripheral = deviceId.findPeripheral(manager: manager) else {
completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(self)")))
return return
} }
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else { guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicNotFound, message: "Unknown characteristic:\(characteristic)")))
return return
} }
if !gattCharacteristic.properties.contains(.read) { if !gattCharacteristic.properties.contains(.read) {
completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support read", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicDoesNotSupportRead, message: "Characteristic does not support read")))
return return
} }
peripheral.readValue(for: gattCharacteristic) peripheral.readValue(for: gattCharacteristic)
@@ -241,11 +241,11 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func writeValue(deviceId: String, service: String, characteristic: String, value: FlutterStandardTypedData, bleOutputProperty: Int64, completion: @escaping (Result<Void, Error>) -> Void) { func writeValue(deviceId: String, service: String, characteristic: String, value: FlutterStandardTypedData, bleOutputProperty: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
guard let peripheral = deviceId.findPeripheral(manager: manager) else { guard let peripheral = deviceId.findPeripheral(manager: manager) else {
completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(self)")))
return return
} }
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else { guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicNotFound, message: "Unknown characteristic:\(characteristic)")))
return return
} }
@@ -253,12 +253,12 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
if type == CBCharacteristicWriteType.withResponse { if type == CBCharacteristicWriteType.withResponse {
if !gattCharacteristic.properties.contains(.write) { if !gattCharacteristic.properties.contains(.write) {
completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support write withResponse", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicDoesNotSupportWrite, message: "Characteristic does not support write withResponse")))
return return
} }
} else if type == CBCharacteristicWriteType.withoutResponse { } else if type == CBCharacteristicWriteType.withoutResponse {
if !gattCharacteristic.properties.contains(.writeWithoutResponse) { if !gattCharacteristic.properties.contains(.writeWithoutResponse) {
completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support write withoutResponse", details: nil))) completion(Result.failure(createFlutterError(code: .characteristicDoesNotSupportWriteWithoutResponse, message: "Characteristic does not support write withoutResponse")))
return return
} }
} }
@@ -275,7 +275,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func requestMtu(deviceId: String, expectedMtu _: Int64, completion: @escaping (Result<Int64, Error>) -> Void) { func requestMtu(deviceId: String, expectedMtu _: Int64, completion: @escaping (Result<Int64, Error>) -> Void) {
guard let peripheral = deviceId.findPeripheral(manager: manager) else { guard let peripheral = deviceId.findPeripheral(manager: manager) else {
completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(self)")))
return return
} }
let mtu = peripheral.maximumWriteValueLength(for: CBCharacteristicWriteType.withoutResponse) let mtu = peripheral.maximumWriteValueLength(for: CBCharacteristicWriteType.withoutResponse)
@@ -285,15 +285,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
} }
func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) { func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
completion(Result.failure(PigeonError(code: "NotSupported", message: nil, details: nil))) completion(Result.failure(createFlutterError(code: .notSupported)))
} }
func pair(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) { func pair(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
completion(Result.failure(PigeonError(code: "Implemented in Dart", message: nil, details: nil))) completion(Result.failure(createFlutterError(code: .notImplemented)))
} }
func unPair(deviceId _: String) throws { func unPair(deviceId _: String) throws {
throw PigeonError(code: "NotSupported", message: nil, details: nil) throw createFlutterError(code: .notSupported)
} }
func getSystemDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void) { func getSystemDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void) {
@@ -427,8 +427,8 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
characteristicWriteFutures.removeAll { future in characteristicWriteFutures.removeAll { future in
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr { if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
if let pigeonError = error?.toPigeonError() { if let flutterError = error?.toFlutterError() {
future.result(Result.failure(pigeonError)) future.result(Result.failure(flutterError))
} else { } else {
future.result(Result.success({}())) future.result(Result.success({}()))
} }
@@ -441,8 +441,8 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
characteristicNotifyFutures.removeAll { future in characteristicNotifyFutures.removeAll { future in
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr { if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
if let pigeonError = error?.toPigeonError() { if let flutterError = error?.toFlutterError() {
future.result(Result.failure(pigeonError)) future.result(Result.failure(flutterError))
} else { } else {
future.result(Result.success({}())) future.result(Result.success({}()))
} }
@@ -467,13 +467,13 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
// Update futures for readValue // Update futures for readValue
characteristicReadFutures.removeAll { future in characteristicReadFutures.removeAll { future in
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr { if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
if let pigeonError = error?.toPigeonError() { if let flutterError = error?.toFlutterError() {
future.result(Result.failure(pigeonError)) future.result(Result.failure(flutterError))
} else { } else {
if let characteristicValue = characteristic.value { if let characteristicValue = characteristic.value {
future.result(Result.success(FlutterStandardTypedData(bytes: characteristicValue))) future.result(Result.success(FlutterStandardTypedData(bytes: characteristicValue)))
} else { } else {
future.result(Result.failure(PigeonError(code: "ReadFailed", message: "No value", details: nil))) future.result(Result.failure(createFlutterError(code: .readFailed, message: "No value")))
} }
} }
return true return true
@@ -484,15 +484,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
} }
extension CBPeripheral { extension CBPeripheral {
func saveCache(){ func saveCache() {
discoveredPeripherals[self.uuid.uuidString] = self discoveredPeripherals[uuid.uuidString] = self
} }
} }
extension String { extension String {
func getPeripheral(manager: CBCentralManager) throws -> CBPeripheral { func getPeripheral(manager: CBCentralManager) throws -> CBPeripheral {
guard let peripheral = findPeripheral(manager: manager) else { guard let peripheral = findPeripheral(manager: manager) else {
throw PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil) throw createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(self)")
} }
return peripheral return peripheral
} }
@@ -515,7 +515,7 @@ extension [String] {
func toCBUUID() throws -> [CBUUID] { func toCBUUID() throws -> [CBUUID] {
return try compactMap { serviceUUID in return try compactMap { serviceUUID in
guard UUID(uuidString: serviceUUID) != nil else { guard UUID(uuidString: serviceUUID) != nil else {
throw PigeonError(code: "IllegalArgument", message: "Invalid service UUID:\(serviceUUID)", details: nil) throw createFlutterError(code: .invalidServiceUuid, message: "Invalid service UUID:\(serviceUUID)")
} }
return CBUUID(string: serviceUUID) return CBUUID(string: serviceUUID)
} }
+1 -1
View File
@@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>12.0</string> <string>13.0</string>
</dict> </dict>
</plist> </plist>
+1 -1
View File
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '12.0' # platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+3 -3
View File
@@ -31,11 +31,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694
COCOAPODS: 1.15.2 COCOAPODS: 1.16.2
+3 -3
View File
@@ -470,7 +470,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@@ -598,7 +598,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -647,7 +647,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
@@ -54,6 +55,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
+8 -3
View File
@@ -1,3 +1,4 @@
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart';
import 'package:universal_ble/src/utils/cache_handler.dart'; import 'package:universal_ble/src/utils/cache_handler.dart';
import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble/universal_ble.dart';
@@ -105,13 +106,17 @@ extension BleDeviceExtension on BleDevice {
} }
if (discoveredServices.isEmpty) { if (discoveredServices.isEmpty) {
throw ServiceNotFoundException('No services found'); throw UniversalBleException(
code: UniversalBleErrorCode.serviceNotFound,
message: 'No services found',
);
} }
return discoveredServices.firstWhere( return discoveredServices.firstWhere(
(s) => BleUuidParser.compareStrings(s.uuid, service), (s) => BleUuidParser.compareStrings(s.uuid, service),
orElse: () => throw ServiceNotFoundException( orElse: () => throw UniversalBleException(
'Service "$service" not available', code: UniversalBleErrorCode.serviceNotFound,
message: 'Service "$service" not available',
), ),
); );
} }
@@ -1,3 +1,4 @@
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart';
import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble/universal_ble.dart';
/// Extension methods for [BleService] objects. /// Extension methods for [BleService] objects.
@@ -8,12 +9,16 @@ extension BleServiceExtension on BleService {
/// with the given UUID is not available. /// with the given UUID is not available.
BleCharacteristic getCharacteristic(String characteristicId) { BleCharacteristic getCharacteristic(String characteristicId) {
if (characteristics.isEmpty) { if (characteristics.isEmpty) {
throw CharacteristicNotFoundException('No characteristics found'); throw UniversalBleException(
code: UniversalBleErrorCode.characteristicNotFound,
message: 'No characteristics found',
);
} }
return characteristics.firstWhere( return characteristics.firstWhere(
(c) => BleUuidParser.compareStrings(c.uuid, characteristicId), (c) => BleUuidParser.compareStrings(c.uuid, characteristicId),
orElse: () => throw CharacteristicNotFoundException( orElse: () => throw UniversalBleException(
'Characteristic "$characteristicId" not available', code: UniversalBleErrorCode.characteristicNotFound,
message: 'Characteristic "$characteristicId" not available',
), ),
); );
} }
+63 -36
View File
@@ -1,58 +1,85 @@
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart';
import 'package:universal_ble/src/utils/universal_ble_error_parser.dart';
class ConnectionException implements Exception { /// Base exception class for all BLE errors with typed error codes
late String message; class UniversalBleException implements Exception {
final UniversalBleErrorCode code;
final String message;
final dynamic details;
ConnectionException([dynamic error]) { UniversalBleException({
message = _errorParser(error); required this.code,
required this.message,
this.details,
});
@override
String toString() => message;
factory UniversalBleException.fromError(dynamic error) {
String message = error.toString();
dynamic details = error;
if (error is PlatformException) {
message = error.message ?? error.details?.toString() ?? error.code;
details = error.details;
} }
return UniversalBleException(
@override code: UniversalBleErrorParser.getCode(error),
String toString() => message; message: message,
} details: details,
);
class PairingException implements Exception {
late String message;
PairingException([dynamic error]) {
message = _errorParser(error);
} }
@override
String toString() => message;
} }
class WebBluetoothGloballyDisabled implements Exception { /// Exception thrown when connection-related errors occur
String message; class ConnectionException extends UniversalBleException {
WebBluetoothGloballyDisabled(this.message); ConnectionException._({
required super.code,
required super.message,
super.details,
});
@override ConnectionException([dynamic error])
String toString() => message; : this._(
code: UniversalBleErrorParser.getCode(error),
message: _errorParser(error),
details: error,
);
} }
class NotFoundException implements Exception {} /// Exception thrown when pairing-related errors occur
class PairingException extends UniversalBleException {
PairingException._({
required super.code,
required super.message,
super.details,
});
class ServiceNotFoundException implements NotFoundException { /// Legacy constructor for backward compatibility
String message; PairingException([dynamic error])
ServiceNotFoundException(this.message); : this._(
code: UniversalBleErrorParser.getCode(error),
@override message: _errorParser(error),
String toString() => message; details: error,
);
} }
class CharacteristicNotFoundException implements NotFoundException { /// Exception thrown when Web Bluetooth API is globally disabled
String message; class WebBluetoothGloballyDisabled extends UniversalBleException {
CharacteristicNotFoundException(this.message); WebBluetoothGloballyDisabled({
super.code = UniversalBleErrorCode.webBluetoothGloballyDisabled,
@override required super.message,
String toString() => message; super.details,
});
} }
/// Legacy error parser for backward compatibility
String _errorParser(dynamic error) { String _errorParser(dynamic error) {
if (error == null) { if (error == null) {
return "Failed"; return "Failed";
} else if (error is PlatformException) { } else if (error is PlatformException) {
return error.message ?? error.details ?? error.code; return error.message ?? error.details ?? error.code ?? 'Unknown error';
} else if (error is String) { } else if (error is String) {
return error; return error;
} else { } else {
@@ -3,9 +3,12 @@ import 'dart:async';
import 'package:bluez/bluez.dart'; import 'package:bluez/bluez.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:universal_ble/src/models/model_exports.dart'; import 'package:universal_ble/src/models/model_exports.dart';
import 'package:universal_ble/src/utils/universal_ble_error_parser.dart';
import 'package:universal_ble/src/utils/universal_ble_filter_util.dart'; import 'package:universal_ble/src/utils/universal_ble_filter_util.dart';
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart';
import 'package:universal_ble/src/universal_ble_platform_interface.dart'; import 'package:universal_ble/src/universal_ble_platform_interface.dart';
import 'package:universal_ble/src/utils/universal_logger.dart'; import 'package:universal_ble/src/utils/universal_logger.dart';
import 'package:universal_ble/src/universal_ble_exceptions.dart';
class UniversalBleLinux extends UniversalBlePlatform { class UniversalBleLinux extends UniversalBlePlatform {
UniversalBleLinux._(); UniversalBleLinux._();
@@ -180,7 +183,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
if (device.gattServices.isEmpty && !device.servicesResolved) { if (device.gattServices.isEmpty && !device.servicesResolved) {
throw "Failed to resolve services"; throw UniversalBleException(
code: UniversalBleErrorCode.failed,
message: "Failed to resolve services",
);
} }
List<BleService> services = []; List<BleService> services = [];
@@ -217,7 +223,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
orElse: () => null); orElse: () => null);
if (c == null) { if (c == null) {
throw Exception('Unknown characteristic:$characteristic'); throw UniversalBleException(
code: UniversalBleErrorCode.characteristicNotFound,
message: 'Unknown characteristic:$characteristic',
);
} }
return c; return c;
} }
@@ -279,9 +288,8 @@ class UniversalBleLinux extends UniversalBlePlatform {
final data = await c.readValue(); final data = await c.readValue();
return Uint8List.fromList(data); return Uint8List.fromList(data);
} on BlueZFailedException catch (e) { } on BlueZFailedException catch (e) {
throw PlatformException( throw e.toUniversalBleException(
code: e.errorCode ?? "ReadFailed", defaultCode: UniversalBleErrorCode.readFailed,
message: e.message,
); );
} }
} }
@@ -307,9 +315,8 @@ class UniversalBleLinux extends UniversalBlePlatform {
); );
} }
} on BlueZFailedException catch (e) { } on BlueZFailedException catch (e) {
throw PlatformException( throw e.toUniversalBleException(
code: e.errorCode ?? "WriteFailed", defaultCode: UniversalBleErrorCode.writeFailed,
message: e.message,
); );
} }
} }
@@ -317,7 +324,12 @@ class UniversalBleLinux extends UniversalBlePlatform {
@override @override
Future<int> requestMtu(String deviceId, int expectedMtu) async { Future<int> requestMtu(String deviceId, int expectedMtu) async {
final device = _findDeviceById(deviceId); final device = _findDeviceById(deviceId);
if (!device.connected) throw Exception('Device not connected'); if (!device.connected) {
throw UniversalBleException(
code: UniversalBleErrorCode.deviceDisconnected,
message: 'Device not connected',
);
}
for (BlueZGattService service in device.gattServices) { for (BlueZGattService service in device.gattServices) {
for (BlueZGattCharacteristic characteristic in service.characteristics) { for (BlueZGattCharacteristic characteristic in service.characteristics) {
int? mtu = characteristic.mtu; int? mtu = characteristic.mtu;
@@ -325,7 +337,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
if (mtu != null) return mtu - 3; if (mtu != null) return mtu - 3;
} }
} }
throw Exception('MTU not available'); throw UniversalBleException(
code: UniversalBleErrorCode.operationNotSupported,
message: 'MTU not available',
);
} }
@override @override
@@ -393,7 +408,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
(device) => device?.address == deviceId, (device) => device?.address == deviceId,
orElse: () => null); orElse: () => null);
if (device == null) { if (device == null) {
throw Exception('Unknown deviceId:$deviceId'); throw UniversalBleException(
code: UniversalBleErrorCode.deviceNotFound,
message: 'Unknown deviceId:$deviceId',
);
} }
return device; return device;
} }
@@ -459,7 +477,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
} }
if (client.adapters.isEmpty) { if (client.adapters.isEmpty) {
throw Exception('Bluetooth adapter unavailable'); throw UniversalBleException(
code: UniversalBleErrorCode.bluetoothNotAvailable,
message: 'Bluetooth adapter unavailable',
);
} }
} }
@@ -584,6 +605,21 @@ extension on BlueZGattCharacteristicFlag {
} }
extension on BlueZFailedException { extension on BlueZFailedException {
UniversalBleException toUniversalBleException({
required UniversalBleErrorCode defaultCode,
}) {
// Map BlueZ error code to UniversalBleErrorCode
UniversalBleErrorCode code = UniversalBleErrorParser.getCode(errorCode);
if (code == UniversalBleErrorCode.unknownError) {
code = defaultCode;
}
throw UniversalBleException(
code: code,
message: message,
details: errorCode,
);
}
/// Extract error code from message and parse into decimal /// Extract error code from message and parse into decimal
/// example: 'Operation failed with ATT error: 0x90' => 144 /// example: 'Operation failed with ATT error: 0x90' => 144
String? get errorCode { String? get errorCode {
+415 -103
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v22.6.1), do not edit directly. // Autogenerated from Pigeon (v26.0.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
@@ -15,7 +15,8 @@ PlatformException _createConnectionError(String channelName) {
); );
} }
List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) { List<Object?> wrapResponse(
{Object? result, PlatformException? error, bool empty = false}) {
if (empty) { if (empty) {
return <Object?>[]; return <Object?>[];
} }
@@ -25,6 +26,86 @@ List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty
return <Object?>[error.code, error.message, error.details]; return <Object?>[error.code, error.message, error.details];
} }
bool _deepEquals(Object? a, Object? b) {
if (a is List && b is List) {
return a.length == b.length &&
a.indexed
.every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
}
if (a is Map && b is Map) {
return a.length == b.length &&
a.entries.every((MapEntry<Object?, Object?> entry) =>
(b as Map<Object?, Object?>).containsKey(entry.key) &&
_deepEquals(entry.value, b[entry.key]));
}
return a == b;
}
/// Unified error codes for all platforms
enum UniversalBleErrorCode {
unknownError,
failed,
notSupported,
notImplemented,
channelError,
bluetoothNotAvailable,
bluetoothNotEnabled,
bluetoothNotAllowed,
bluetoothUnauthorized,
deviceDisconnected,
connectionTimeout,
connectionFailed,
connectionRejected,
connectionLimitExceeded,
connectionAlreadyExists,
connectionTerminated,
connectionInProgress,
illegalArgument,
deviceNotFound,
serviceNotFound,
characteristicNotFound,
invalidServiceUuid,
invalidCharacteristicUuid,
invalidOffset,
invalidAttributeLength,
invalidPdu,
invalidHandle,
readFailed,
readNotPermitted,
writeFailed,
writeNotPermitted,
writeRequestBusy,
invalidAction,
operationNotSupported,
operationTimeout,
operationCancelled,
operationInProgress,
characteristicDoesNotSupportRead,
characteristicDoesNotSupportWrite,
characteristicDoesNotSupportWriteWithoutResponse,
characteristicDoesNotSupportNotify,
characteristicDoesNotSupportIndicate,
notPaired,
notPairable,
alreadyPaired,
pairingFailed,
pairingCancelled,
pairingTimeout,
pairingNotAllowed,
authenticationFailure,
insufficientAuthentication,
insufficientAuthorization,
insufficientEncryption,
insufficientKeySize,
protectionLevelNotMet,
accessDenied,
unpairingFailed,
alreadyUnpaired,
scanFailed,
stoppingScanInProgress,
webBluetoothGloballyDisabled,
}
class UniversalBleScanResult { class UniversalBleScanResult {
UniversalBleScanResult({ UniversalBleScanResult({
required this.deviceId, required this.deviceId,
@@ -47,7 +128,7 @@ class UniversalBleScanResult {
List<String>? services; List<String>? services;
Object encode() { List<Object?> _toList() {
return <Object?>[ return <Object?>[
deviceId, deviceId,
name, name,
@@ -58,6 +139,10 @@ class UniversalBleScanResult {
]; ];
} }
Object encode() {
return _toList();
}
static UniversalBleScanResult decode(Object result) { static UniversalBleScanResult decode(Object result) {
result as List<Object?>; result as List<Object?>;
return UniversalBleScanResult( return UniversalBleScanResult(
@@ -65,10 +150,27 @@ class UniversalBleScanResult {
name: result[1] as String?, name: result[1] as String?,
isPaired: result[2] as bool?, isPaired: result[2] as bool?,
rssi: result[3] as int?, rssi: result[3] as int?,
manufacturerDataList: (result[4] as List<Object?>?)?.cast<UniversalManufacturerData>(), manufacturerDataList:
(result[4] as List<Object?>?)?.cast<UniversalManufacturerData>(),
services: (result[5] as List<Object?>?)?.cast<String>(), services: (result[5] as List<Object?>?)?.cast<String>(),
); );
} }
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
bool operator ==(Object other) {
if (other is! UniversalBleScanResult || other.runtimeType != runtimeType) {
return false;
}
if (identical(this, other)) {
return true;
}
return _deepEquals(encode(), other.encode());
}
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
int get hashCode => Object.hashAll(_toList());
} }
class UniversalBleService { class UniversalBleService {
@@ -81,20 +183,41 @@ class UniversalBleService {
List<UniversalBleCharacteristic>? characteristics; List<UniversalBleCharacteristic>? characteristics;
Object encode() { List<Object?> _toList() {
return <Object?>[ return <Object?>[
uuid, uuid,
characteristics, characteristics,
]; ];
} }
Object encode() {
return _toList();
}
static UniversalBleService decode(Object result) { static UniversalBleService decode(Object result) {
result as List<Object?>; result as List<Object?>;
return UniversalBleService( return UniversalBleService(
uuid: result[0]! as String, uuid: result[0]! as String,
characteristics: (result[1] as List<Object?>?)?.cast<UniversalBleCharacteristic>(), characteristics:
(result[1] as List<Object?>?)?.cast<UniversalBleCharacteristic>(),
); );
} }
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
bool operator ==(Object other) {
if (other is! UniversalBleService || other.runtimeType != runtimeType) {
return false;
}
if (identical(this, other)) {
return true;
}
return _deepEquals(encode(), other.encode());
}
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
int get hashCode => Object.hashAll(_toList());
} }
class UniversalBleCharacteristic { class UniversalBleCharacteristic {
@@ -107,13 +230,17 @@ class UniversalBleCharacteristic {
List<int> properties; List<int> properties;
Object encode() { List<Object?> _toList() {
return <Object?>[ return <Object?>[
uuid, uuid,
properties, properties,
]; ];
} }
Object encode() {
return _toList();
}
static UniversalBleCharacteristic decode(Object result) { static UniversalBleCharacteristic decode(Object result) {
result as List<Object?>; result as List<Object?>;
return UniversalBleCharacteristic( return UniversalBleCharacteristic(
@@ -121,6 +248,23 @@ class UniversalBleCharacteristic {
properties: (result[1] as List<Object?>?)!.cast<int>(), properties: (result[1] as List<Object?>?)!.cast<int>(),
); );
} }
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
bool operator ==(Object other) {
if (other is! UniversalBleCharacteristic ||
other.runtimeType != runtimeType) {
return false;
}
if (identical(this, other)) {
return true;
}
return _deepEquals(encode(), other.encode());
}
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
int get hashCode => Object.hashAll(_toList());
} }
/// Scan Filters /// Scan Filters
@@ -137,7 +281,7 @@ class UniversalScanFilter {
List<UniversalManufacturerDataFilter> withManufacturerData; List<UniversalManufacturerDataFilter> withManufacturerData;
Object encode() { List<Object?> _toList() {
return <Object?>[ return <Object?>[
withServices, withServices,
withNamePrefix, withNamePrefix,
@@ -145,14 +289,35 @@ class UniversalScanFilter {
]; ];
} }
Object encode() {
return _toList();
}
static UniversalScanFilter decode(Object result) { static UniversalScanFilter decode(Object result) {
result as List<Object?>; result as List<Object?>;
return UniversalScanFilter( return UniversalScanFilter(
withServices: (result[0] as List<Object?>?)!.cast<String>(), withServices: (result[0] as List<Object?>?)!.cast<String>(),
withNamePrefix: (result[1] as List<Object?>?)!.cast<String>(), withNamePrefix: (result[1] as List<Object?>?)!.cast<String>(),
withManufacturerData: (result[2] as List<Object?>?)!.cast<UniversalManufacturerDataFilter>(), withManufacturerData: (result[2] as List<Object?>?)!
.cast<UniversalManufacturerDataFilter>(),
); );
} }
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
bool operator ==(Object other) {
if (other is! UniversalScanFilter || other.runtimeType != runtimeType) {
return false;
}
if (identical(this, other)) {
return true;
}
return _deepEquals(encode(), other.encode());
}
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
int get hashCode => Object.hashAll(_toList());
} }
class UniversalManufacturerDataFilter { class UniversalManufacturerDataFilter {
@@ -168,7 +333,7 @@ class UniversalManufacturerDataFilter {
Uint8List? mask; Uint8List? mask;
Object encode() { List<Object?> _toList() {
return <Object?>[ return <Object?>[
companyIdentifier, companyIdentifier,
data, data,
@@ -176,6 +341,10 @@ class UniversalManufacturerDataFilter {
]; ];
} }
Object encode() {
return _toList();
}
static UniversalManufacturerDataFilter decode(Object result) { static UniversalManufacturerDataFilter decode(Object result) {
result as List<Object?>; result as List<Object?>;
return UniversalManufacturerDataFilter( return UniversalManufacturerDataFilter(
@@ -184,6 +353,23 @@ class UniversalManufacturerDataFilter {
mask: result[2] as Uint8List?, mask: result[2] as Uint8List?,
); );
} }
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
bool operator ==(Object other) {
if (other is! UniversalManufacturerDataFilter ||
other.runtimeType != runtimeType) {
return false;
}
if (identical(this, other)) {
return true;
}
return _deepEquals(encode(), other.encode());
}
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
int get hashCode => Object.hashAll(_toList());
} }
class UniversalManufacturerData { class UniversalManufacturerData {
@@ -196,13 +382,17 @@ class UniversalManufacturerData {
Uint8List data; Uint8List data;
Object encode() { List<Object?> _toList() {
return <Object?>[ return <Object?>[
companyIdentifier, companyIdentifier,
data, data,
]; ];
} }
Object encode() {
return _toList();
}
static UniversalManufacturerData decode(Object result) { static UniversalManufacturerData decode(Object result) {
result as List<Object?>; result as List<Object?>;
return UniversalManufacturerData( return UniversalManufacturerData(
@@ -210,8 +400,24 @@ class UniversalManufacturerData {
data: result[1]! as Uint8List, data: result[1]! as Uint8List,
); );
} }
}
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
bool operator ==(Object other) {
if (other is! UniversalManufacturerData ||
other.runtimeType != runtimeType) {
return false;
}
if (identical(this, other)) {
return true;
}
return _deepEquals(encode(), other.encode());
}
@override
// ignore: avoid_equals_and_hash_code_on_mutable_classes
int get hashCode => Object.hashAll(_toList());
}
class _PigeonCodec extends StandardMessageCodec { class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec(); const _PigeonCodec();
@@ -220,24 +426,27 @@ class _PigeonCodec extends StandardMessageCodec {
if (value is int) { if (value is int) {
buffer.putUint8(4); buffer.putUint8(4);
buffer.putInt64(value); buffer.putInt64(value);
} else if (value is UniversalBleScanResult) { } else if (value is UniversalBleErrorCode) {
buffer.putUint8(129); buffer.putUint8(129);
writeValue(buffer, value.encode()); writeValue(buffer, value.index);
} else if (value is UniversalBleService) { } else if (value is UniversalBleScanResult) {
buffer.putUint8(130); buffer.putUint8(130);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else if (value is UniversalBleCharacteristic) { } else if (value is UniversalBleService) {
buffer.putUint8(131); buffer.putUint8(131);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else if (value is UniversalScanFilter) { } else if (value is UniversalBleCharacteristic) {
buffer.putUint8(132); buffer.putUint8(132);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else if (value is UniversalManufacturerDataFilter) { } else if (value is UniversalScanFilter) {
buffer.putUint8(133); buffer.putUint8(133);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else if (value is UniversalManufacturerData) { } else if (value is UniversalManufacturerDataFilter) {
buffer.putUint8(134); buffer.putUint8(134);
writeValue(buffer, value.encode()); writeValue(buffer, value.encode());
} else if (value is UniversalManufacturerData) {
buffer.putUint8(135);
writeValue(buffer, value.encode());
} else { } else {
super.writeValue(buffer, value); super.writeValue(buffer, value);
} }
@@ -247,16 +456,19 @@ class _PigeonCodec extends StandardMessageCodec {
Object? readValueOfType(int type, ReadBuffer buffer) { Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) { switch (type) {
case 129: case 129:
return UniversalBleScanResult.decode(readValue(buffer)!); final int? value = readValue(buffer) as int?;
return value == null ? null : UniversalBleErrorCode.values[value];
case 130: case 130:
return UniversalBleService.decode(readValue(buffer)!); return UniversalBleScanResult.decode(readValue(buffer)!);
case 131: case 131:
return UniversalBleCharacteristic.decode(readValue(buffer)!); return UniversalBleService.decode(readValue(buffer)!);
case 132: case 132:
return UniversalScanFilter.decode(readValue(buffer)!); return UniversalBleCharacteristic.decode(readValue(buffer)!);
case 133: case 133:
return UniversalManufacturerDataFilter.decode(readValue(buffer)!); return UniversalScanFilter.decode(readValue(buffer)!);
case 134: case 134:
return UniversalManufacturerDataFilter.decode(readValue(buffer)!);
case 135:
return UniversalManufacturerData.decode(readValue(buffer)!); return UniversalManufacturerData.decode(readValue(buffer)!);
default: default:
return super.readValueOfType(type, buffer); return super.readValueOfType(type, buffer);
@@ -269,9 +481,11 @@ class UniversalBlePlatformChannel {
/// Constructor for [UniversalBlePlatformChannel]. The [binaryMessenger] named argument is /// Constructor for [UniversalBlePlatformChannel]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default /// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform. /// BinaryMessenger will be used which routes to the host platform.
UniversalBlePlatformChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) UniversalBlePlatformChannel(
{BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
: pigeonVar_binaryMessenger = binaryMessenger, : pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; pigeonVar_messageChannelSuffix =
messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
final BinaryMessenger? pigeonVar_binaryMessenger; final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec(); static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
@@ -279,14 +493,17 @@ class UniversalBlePlatformChannel {
final String pigeonVar_messageChannelSuffix; final String pigeonVar_messageChannelSuffix;
Future<int> getBluetoothAvailabilityState() async { Future<int> getBluetoothAvailabilityState() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -306,14 +523,17 @@ class UniversalBlePlatformChannel {
} }
Future<bool> enableBluetooth() async { Future<bool> enableBluetooth() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -333,14 +553,17 @@ class UniversalBlePlatformChannel {
} }
Future<bool> disableBluetooth() async { Future<bool> disableBluetooth() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -360,14 +583,18 @@ class UniversalBlePlatformChannel {
} }
Future<void> startScan(UniversalScanFilter? filter) async { Future<void> startScan(UniversalScanFilter? filter) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[filter]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[filter]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -382,14 +609,17 @@ class UniversalBlePlatformChannel {
} }
Future<void> stopScan() async { Future<void> stopScan() async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -404,14 +634,18 @@ class UniversalBlePlatformChannel {
} }
Future<void> connect(String deviceId) async { Future<void> connect(String deviceId) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -426,14 +660,18 @@ class UniversalBlePlatformChannel {
} }
Future<void> disconnect(String deviceId) async { Future<void> disconnect(String deviceId) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -447,15 +685,20 @@ class UniversalBlePlatformChannel {
} }
} }
Future<void> setNotifiable(String deviceId, String service, String characteristic, int bleInputProperty) async { Future<void> setNotifiable(String deviceId, String service,
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix'; String characteristic, int bleInputProperty) async {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final String pigeonVar_channelName =
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel
.send(<Object?>[deviceId, service, characteristic, bleInputProperty]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId, service, characteristic, bleInputProperty]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -470,14 +713,18 @@ class UniversalBlePlatformChannel {
} }
Future<List<UniversalBleService>> discoverServices(String deviceId) async { Future<List<UniversalBleService>> discoverServices(String deviceId) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -492,19 +739,25 @@ class UniversalBlePlatformChannel {
message: 'Host platform returned null value for non-null return value.', message: 'Host platform returned null value for non-null return value.',
); );
} else { } else {
return (pigeonVar_replyList[0] as List<Object?>?)!.cast<UniversalBleService>(); return (pigeonVar_replyList[0] as List<Object?>?)!
.cast<UniversalBleService>();
} }
} }
Future<Uint8List> readValue(String deviceId, String service, String characteristic) async { Future<Uint8List> readValue(
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix'; String deviceId, String service, String characteristic) async {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final String pigeonVar_channelName =
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId, service, characteristic]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId, service, characteristic]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -524,14 +777,18 @@ class UniversalBlePlatformChannel {
} }
Future<int> requestMtu(String deviceId, int expectedMtu) async { Future<int> requestMtu(String deviceId, int expectedMtu) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId, expectedMtu]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId, expectedMtu]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -550,15 +807,20 @@ class UniversalBlePlatformChannel {
} }
} }
Future<void> writeValue(String deviceId, String service, String characteristic, Uint8List value, int bleOutputProperty) async { Future<void> writeValue(String deviceId, String service,
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix'; String characteristic, Uint8List value, int bleOutputProperty) async {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final String pigeonVar_channelName =
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
<Object?>[deviceId, service, characteristic, value, bleOutputProperty]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId, service, characteristic, value, bleOutputProperty]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -573,14 +835,18 @@ class UniversalBlePlatformChannel {
} }
Future<bool> isPaired(String deviceId) async { Future<bool> isPaired(String deviceId) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -600,14 +866,18 @@ class UniversalBlePlatformChannel {
} }
Future<bool> pair(String deviceId) async { Future<bool> pair(String deviceId) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -627,14 +897,18 @@ class UniversalBlePlatformChannel {
} }
Future<void> unPair(String deviceId) async { Future<void> unPair(String deviceId) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -648,15 +922,20 @@ class UniversalBlePlatformChannel {
} }
} }
Future<List<UniversalBleScanResult>> getSystemDevices(List<String> withServices) async { Future<List<UniversalBleScanResult>> getSystemDevices(
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix'; List<String> withServices) async {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final String pigeonVar_channelName =
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[withServices]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[withServices]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -671,19 +950,24 @@ class UniversalBlePlatformChannel {
message: 'Host platform returned null value for non-null return value.', message: 'Host platform returned null value for non-null return value.',
); );
} else { } else {
return (pigeonVar_replyList[0] as List<Object?>?)!.cast<UniversalBleScanResult>(); return (pigeonVar_replyList[0] as List<Object?>?)!
.cast<UniversalBleScanResult>();
} }
} }
Future<int> getConnectionState(String deviceId) async { Future<int> getConnectionState(String deviceId) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix'; final String pigeonVar_channelName =
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName, pigeonVar_channelName,
pigeonChannelCodec, pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger, binaryMessenger: pigeonVar_binaryMessenger,
); );
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[deviceId]);
final List<Object?>? pigeonVar_replyList = final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?; await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) { if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName); throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) { } else if (pigeonVar_replyList.length > 1) {
@@ -713,15 +997,24 @@ abstract class UniversalBleCallbackChannel {
void onScanResult(UniversalBleScanResult result); void onScanResult(UniversalBleScanResult result);
void onValueChanged(String deviceId, String characteristicId, Uint8List value); void onValueChanged(
String deviceId, String characteristicId, Uint8List value);
void onConnectionChanged(String deviceId, bool connected, String? error); void onConnectionChanged(String deviceId, bool connected, String? error);
static void setUp(UniversalBleCallbackChannel? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { static void setUp(
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; UniversalBleCallbackChannel? api, {
BinaryMessenger? binaryMessenger,
String messageChannelSuffix = '',
}) {
messageChannelSuffix =
messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
{ {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final BasicMessageChannel<
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', pigeonChannelCodec, Object?> pigeonVar_channel = BasicMessageChannel<
Object?>(
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger); binaryMessenger: binaryMessenger);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
@@ -739,14 +1032,18 @@ abstract class UniversalBleCallbackChannel {
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()));
} }
}); });
} }
} }
{ {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final BasicMessageChannel<
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', pigeonChannelCodec, Object?> pigeonVar_channel = BasicMessageChannel<
Object?>(
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger); binaryMessenger: binaryMessenger);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
@@ -768,14 +1065,18 @@ abstract class UniversalBleCallbackChannel {
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()));
} }
}); });
} }
} }
{ {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final BasicMessageChannel<
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', pigeonChannelCodec, Object?> pigeonVar_channel = BasicMessageChannel<
Object?>(
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger); binaryMessenger: binaryMessenger);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
@@ -784,7 +1085,8 @@ abstract class UniversalBleCallbackChannel {
assert(message != null, assert(message != null,
'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null.'); 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null.');
final List<Object?> args = (message as List<Object?>?)!; final List<Object?> args = (message as List<Object?>?)!;
final UniversalBleScanResult? arg_result = (args[0] as UniversalBleScanResult?); final UniversalBleScanResult? arg_result =
(args[0] as UniversalBleScanResult?);
assert(arg_result != null, assert(arg_result != null,
'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null, expected non-null UniversalBleScanResult.'); 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null, expected non-null UniversalBleScanResult.');
try { try {
@@ -793,14 +1095,18 @@ abstract class UniversalBleCallbackChannel {
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()));
} }
}); });
} }
} }
{ {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final BasicMessageChannel<
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', pigeonChannelCodec, Object?> pigeonVar_channel = BasicMessageChannel<
Object?>(
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger); binaryMessenger: binaryMessenger);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
@@ -819,19 +1125,24 @@ abstract class UniversalBleCallbackChannel {
assert(arg_value != null, assert(arg_value != null,
'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null, expected non-null Uint8List.'); 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null, expected non-null Uint8List.');
try { try {
api.onValueChanged(arg_deviceId!, arg_characteristicId!, arg_value!); api.onValueChanged(
arg_deviceId!, arg_characteristicId!, arg_value!);
return wrapResponse(empty: true); return wrapResponse(empty: true);
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()));
} }
}); });
} }
} }
{ {
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>( final BasicMessageChannel<
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', pigeonChannelCodec, Object?> pigeonVar_channel = BasicMessageChannel<
Object?>(
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger); binaryMessenger: binaryMessenger);
if (api == null) { if (api == null) {
pigeonVar_channel.setMessageHandler(null); pigeonVar_channel.setMessageHandler(null);
@@ -853,7 +1164,8 @@ abstract class UniversalBleCallbackChannel {
} on PlatformException catch (e) { } on PlatformException catch (e) {
return wrapResponse(error: e); return wrapResponse(error: e);
} catch (e) { } catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()));
} }
}); });
} }
@@ -1,5 +1,4 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart'; import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart';
import 'package:universal_ble/src/utils/universal_ble_filter_util.dart'; import 'package:universal_ble/src/utils/universal_ble_filter_util.dart';
import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble/universal_ble.dart';
@@ -18,7 +17,9 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
@override @override
Future<AvailabilityState> getBluetoothAvailabilityState() async { Future<AvailabilityState> getBluetoothAvailabilityState() async {
int state = await _channel.getBluetoothAvailabilityState(); int state = await _executeWithErrorHandling(
() => _channel.getBluetoothAvailabilityState(),
);
return AvailabilityState.parse(state); return AvailabilityState.parse(state);
} }
@@ -27,7 +28,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
if (!BleCapabilities.supportsBluetoothEnableApi) { if (!BleCapabilities.supportsBluetoothEnableApi) {
throw UnsupportedError("Not supported"); throw UnsupportedError("Not supported");
} }
return _channel.enableBluetooth(); return _executeWithErrorHandling(() => _channel.enableBluetooth());
} }
@override @override
@@ -35,7 +36,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
if (!BleCapabilities.supportsBluetoothEnableApi) { if (!BleCapabilities.supportsBluetoothEnableApi) {
throw UnsupportedError("Not supported"); throw UnsupportedError("Not supported");
} }
return _channel.disableBluetooth(); return _executeWithErrorHandling(() => _channel.disableBluetooth());
} }
@override @override
@@ -45,31 +46,37 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
}) async { }) async {
await _ensureInitialized(); await _ensureInitialized();
_bleFilter.scanFilter = scanFilter; _bleFilter.scanFilter = scanFilter;
await _channel.startScan( await _executeWithErrorHandling(
() => _channel.startScan(
scanFilter.toUniversalScanFilter(), scanFilter.toUniversalScanFilter(),
),
); );
} }
@override @override
Future<void> stopScan() => _channel.stopScan(); Future<void> stopScan() =>
_executeWithErrorHandling(() => _channel.stopScan());
@override @override
Future<BleConnectionState> getConnectionState(String deviceId) async { Future<BleConnectionState> getConnectionState(String deviceId) async {
int state = await _channel.getConnectionState(deviceId); int state = await _executeWithErrorHandling(
() => _channel.getConnectionState(deviceId));
return BleConnectionState.parse(state); return BleConnectionState.parse(state);
} }
@override @override
Future<void> connect(String deviceId, {Duration? connectionTimeout}) => Future<void> connect(String deviceId, {Duration? connectionTimeout}) =>
_channel.connect(deviceId); _executeWithErrorHandling(() => _channel.connect(deviceId));
@override @override
Future<void> disconnect(String deviceId) => _channel.disconnect(deviceId); Future<void> disconnect(String deviceId) =>
_executeWithErrorHandling(() => _channel.disconnect(deviceId));
@override @override
Future<List<BleService>> discoverServices(String deviceId) async { Future<List<BleService>> discoverServices(String deviceId) async {
List<UniversalBleService?> universalBleServices = List<UniversalBleService?> universalBleServices =
await _channel.discoverServices(deviceId); await _executeWithErrorHandling(
() => _channel.discoverServices(deviceId));
return List<BleService>.from(universalBleServices return List<BleService>.from(universalBleServices
.where((e) => e != null) .where((e) => e != null)
.map((e) => e!.toBleService(deviceId)) .map((e) => e!.toBleService(deviceId))
@@ -79,12 +86,12 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
@override @override
Future<void> setNotifiable(String deviceId, String service, Future<void> setNotifiable(String deviceId, String service,
String characteristic, BleInputProperty bleInputProperty) { String characteristic, BleInputProperty bleInputProperty) {
return _channel.setNotifiable( return _executeWithErrorHandling(() => _channel.setNotifiable(
deviceId, deviceId,
service, service,
characteristic, characteristic,
bleInputProperty.index, bleInputProperty.index,
); ));
} }
@override @override
@@ -94,7 +101,8 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
String characteristic, { String characteristic, {
final Duration? timeout, final Duration? timeout,
}) { }) {
return _channel.readValue(deviceId, service, characteristic); return _executeWithErrorHandling(
() => _channel.readValue(deviceId, service, characteristic));
} }
@override @override
@@ -104,33 +112,38 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
String characteristic, String characteristic,
Uint8List value, Uint8List value,
BleOutputProperty bleOutputProperty) { BleOutputProperty bleOutputProperty) {
return _channel.writeValue( return _executeWithErrorHandling(() => _channel.writeValue(
deviceId, deviceId,
service, service,
characteristic, characteristic,
value, value,
bleOutputProperty.index, bleOutputProperty.index,
); ));
} }
@override @override
Future<int> requestMtu(String deviceId, int expectedMtu) => Future<int> requestMtu(String deviceId, int expectedMtu) =>
_channel.requestMtu(deviceId, expectedMtu); _executeWithErrorHandling(
() => _channel.requestMtu(deviceId, expectedMtu));
@override @override
Future<bool> isPaired(String deviceId) => _channel.isPaired(deviceId); Future<bool> isPaired(String deviceId) =>
_executeWithErrorHandling(() => _channel.isPaired(deviceId));
@override @override
Future<bool> pair(String deviceId) => _channel.pair(deviceId); Future<bool> pair(String deviceId) =>
_executeWithErrorHandling(() => _channel.pair(deviceId));
@override @override
Future<void> unpair(String deviceId) => _channel.unPair(deviceId); Future<void> unpair(String deviceId) =>
_executeWithErrorHandling(() => _channel.unPair(deviceId));
@override @override
Future<List<BleDevice>> getSystemDevices( Future<List<BleDevice>> getSystemDevices(
List<String>? withServices, List<String>? withServices,
) async { ) async {
var devices = await _channel.getSystemDevices(withServices ?? []); var devices = await _executeWithErrorHandling(
() => _channel.getSystemDevices(withServices ?? []));
return List<BleDevice>.from( return List<BleDevice>.from(
devices.map((e) => e.toBleDevice(isSystemDevice: true)).toList(), devices.map((e) => e.toBleDevice(isSystemDevice: true)).toList(),
); );
@@ -152,6 +165,16 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
)); ));
} }
/// Executes a platform call with error handling
/// Converts any errors to UniversalBleException
Future<T> _executeWithErrorHandling<T>(Future<T> Function() future) async {
try {
return await future();
} catch (error) {
throw UniversalBleException.fromError(error);
}
}
Future<void> _ensureInitialized() async { Future<void> _ensureInitialized() async {
// Check bluetooth availability on Apple // Check bluetooth availability on Apple
// so that it will ask permission only when required, and throw error on failed // so that it will ask permission only when required, and throw error on failed
@@ -160,13 +183,13 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
AvailabilityState state = await getBluetoothAvailabilityState(); AvailabilityState state = await getBluetoothAvailabilityState();
switch (state) { switch (state) {
case AvailabilityState.unauthorized: case AvailabilityState.unauthorized:
throw PlatformException( throw UniversalBleException(
code: "Unauthorized", code: UniversalBleErrorCode.bluetoothUnauthorized,
message: "Not authorized to access Bluetooth", message: "Not authorized to access Bluetooth",
); );
case AvailabilityState.unsupported: case AvailabilityState.unsupported:
throw PlatformException( throw UniversalBleException(
code: "Unsupported", code: UniversalBleErrorCode.notSupported,
message: "Bluetooth is not supported", message: "Bluetooth is not supported",
); );
default: default:
@@ -4,6 +4,7 @@ import 'dart:collection';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_web_bluetooth/flutter_web_bluetooth.dart'; import 'package:flutter_web_bluetooth/flutter_web_bluetooth.dart';
import 'package:universal_ble/src/utils/universal_logger.dart'; import 'package:universal_ble/src/utils/universal_logger.dart';
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart';
import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble/universal_ble.dart';
class UniversalBleWeb extends UniversalBlePlatform { class UniversalBleWeb extends UniversalBlePlatform {
@@ -35,7 +36,12 @@ class UniversalBleWeb extends UniversalBlePlatform {
Duration? connectionTimeout = const Duration(seconds: 10), Duration? connectionTimeout = const Duration(seconds: 10),
}) async { }) async {
var device = _getDeviceById(deviceId); var device = _getDeviceById(deviceId);
if (device == null) throw "$deviceId Not Found"; if (device == null) {
throw UniversalBleException(
code: UniversalBleErrorCode.deviceNotFound,
message: "$deviceId Not Found",
);
}
await device.connect(timeout: connectionTimeout); await device.connect(timeout: connectionTimeout);
// Subscribe to Connection Stream // Subscribe to Connection Stream
@@ -92,7 +98,7 @@ class UniversalBleWeb extends UniversalBlePlatform {
} catch (e) { } catch (e) {
String error = e.toString().replaceAll("DeviceNotFoundError:", "").trim(); String error = e.toString().replaceAll("DeviceNotFoundError:", "").trim();
if (error.toLowerCase().contains("api globally disabled")) { if (error.toLowerCase().contains("api globally disabled")) {
throw WebBluetoothGloballyDisabled(error); throw WebBluetoothGloballyDisabled(message: error);
} }
rethrow; rethrow;
} }
@@ -154,7 +160,9 @@ class UniversalBleWeb extends UniversalBlePlatform {
); );
if (bleCharacteristic == null) { if (bleCharacteristic == null) {
throw Exception( throw UniversalBleException(
code: UniversalBleErrorCode.characteristicNotFound,
message:
'Characteristic $characteristic for service $service not found', 'Characteristic $characteristic for service $service not found',
); );
} }
@@ -195,7 +203,9 @@ class UniversalBleWeb extends UniversalBlePlatform {
); );
if (bleCharacteristic == null) { if (bleCharacteristic == null) {
throw Exception( throw UniversalBleException(
code: UniversalBleErrorCode.characteristicNotFound,
message:
'Characteristic $characteristic for service $service not found', 'Characteristic $characteristic for service $service not found',
); );
} }
@@ -221,8 +231,11 @@ class UniversalBleWeb extends UniversalBlePlatform {
characteristicId: characteristic, characteristicId: characteristic,
); );
if (bleCharacteristic == null) { if (bleCharacteristic == null) {
throw Exception( throw UniversalBleException(
'Characteristic $characteristic for service $service not found'); code: UniversalBleErrorCode.characteristicNotFound,
message:
'Characteristic $characteristic for service $service not found',
);
} }
var data = timeout != null var data = timeout != null
? bleCharacteristic.readValue(timeout: timeout) ? bleCharacteristic.readValue(timeout: timeout)
@@ -233,29 +246,44 @@ class UniversalBleWeb extends UniversalBlePlatform {
/// `Unimplemented` /// `Unimplemented`
@override @override
Future<int> requestMtu(String deviceId, int expectedMtu) { Future<int> requestMtu(String deviceId, int expectedMtu) {
throw UnimplementedError(); throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "requestMtu is not implemented on Web platform",
);
} }
@override @override
Future<bool> isPaired(String deviceId) { Future<bool> isPaired(String deviceId) {
throw UnimplementedError(); throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "isPaired is not implemented on Web platform",
);
} }
@override @override
Future<bool> pair(String deviceId) { Future<bool> pair(String deviceId) {
throw UnimplementedError(); throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "pair is not implemented on Web platform",
);
} }
@override @override
Future<void> unpair(String deviceId) { Future<void> unpair(String deviceId) {
throw UnimplementedError(); throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "unpair is not implemented on Web platform",
);
} }
@override @override
Future<List<BleDevice>> getSystemDevices( Future<List<BleDevice>> getSystemDevices(
List<String>? withServices, List<String>? withServices,
) { ) {
throw UnimplementedError(); throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "getSystemDevices is not implemented on Web platform",
);
} }
/// Helpers /// Helpers
@@ -335,12 +363,18 @@ class UniversalBleWeb extends UniversalBlePlatform {
@override @override
Future<bool> enableBluetooth() { Future<bool> enableBluetooth() {
throw UnimplementedError(); throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "enableBluetooth is not implemented on Web platform",
);
} }
@override @override
Future<bool> disableBluetooth() { Future<bool> disableBluetooth() {
throw UnimplementedError(); throw UniversalBleException(
code: UniversalBleErrorCode.notImplemented,
message: "disableBluetooth is not implemented on Web platform",
);
} }
RequestOptionsBuilder _getRequestOptionBuilder( RequestOptionsBuilder _getRequestOptionBuilder(
@@ -0,0 +1,417 @@
import 'package:flutter/services.dart';
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart';
/// Utility class to parse error codes from dynamic errors
class UniversalBleErrorParser {
static UniversalBleErrorCode getCode(dynamic error) {
if (error is UniversalBleErrorCode) return error;
if (error is PlatformException) {
int? errorCodeInt = int.tryParse((error).code);
if (errorCodeInt != null) {
return UniversalBleErrorCode.values[errorCodeInt];
}
}
if (error is num) {
return _parseNumericErrorCode((error).toInt());
}
if (error is String) {
int? errorCodeInt = int.tryParse(error);
if (errorCodeInt != null) {
return _parseNumericErrorCode(errorCodeInt);
} else {
return _parseStringErrorCode(error) ??
UniversalBleErrorCode.unknownError;
}
}
return UniversalBleErrorCode.unknownError;
}
static UniversalBleErrorCode? _parseStringErrorCode(String code) {
switch (code.toLowerCase()) {
case 'notsupported':
case 'not_supported':
return UniversalBleErrorCode.notSupported;
case 'notimplemented':
case 'not_implemented':
return UniversalBleErrorCode.notImplemented;
case 'channel-error':
case 'channelerror':
return UniversalBleErrorCode.channelError;
case 'failed':
return UniversalBleErrorCode.failed;
case 'bluetoothnotavailable':
case 'bluetooth_not_available':
return UniversalBleErrorCode.bluetoothNotAvailable;
case 'bluetoothnotenabled':
case 'bluetooth_not_enabled':
return UniversalBleErrorCode.bluetoothNotEnabled;
case 'bluetoothnotallowed':
case 'bluetooth_not_allowed':
return UniversalBleErrorCode.bluetoothNotAllowed;
case 'bluetoothunauthorized':
case 'bluetooth_unauthorized':
return UniversalBleErrorCode.bluetoothUnauthorized;
case 'devicedisconnected':
case 'device_disconnected':
return UniversalBleErrorCode.deviceDisconnected;
case 'connectiontimeout':
case 'connection_timeout':
return UniversalBleErrorCode.connectionTimeout;
case 'connectionfailed':
case 'connection_failed':
return UniversalBleErrorCode.connectionFailed;
case 'connectionrejected':
case 'connection_rejected':
return UniversalBleErrorCode.connectionRejected;
case 'connecting':
case 'connectioninprogress':
case 'connection_in_progress':
return UniversalBleErrorCode.connectionInProgress;
case 'connectionterminated':
case 'connection_terminated':
return UniversalBleErrorCode.connectionTerminated;
case 'illegalargument':
case 'illegal_argument':
return UniversalBleErrorCode.illegalArgument;
case 'devicenotfound':
case 'device_not_found':
return UniversalBleErrorCode.deviceNotFound;
case 'servicenotfound':
case 'service_not_found':
return UniversalBleErrorCode.serviceNotFound;
case 'characteristicnotfound':
case 'characteristic_not_found':
return UniversalBleErrorCode.characteristicNotFound;
case 'invalidserviceuuid':
case 'invalid_service_uuid':
return UniversalBleErrorCode.invalidServiceUuid;
case 'invalidcharacteristicuuid':
case 'invalid_characteristic_uuid':
return UniversalBleErrorCode.invalidCharacteristicUuid;
case 'readfailed':
case 'read_failed':
return UniversalBleErrorCode.readFailed;
case 'writefailed':
case 'write_failed':
case 'writeerror':
case 'write_error':
return UniversalBleErrorCode.writeFailed;
case 'invalidaction':
case 'invalid_action':
return UniversalBleErrorCode.invalidAction;
case 'operationnotsupported':
case 'operation_not_supported':
return UniversalBleErrorCode.operationNotSupported;
case 'operationtimeout':
case 'operation_timeout':
return UniversalBleErrorCode.operationTimeout;
case 'operationcancelled':
case 'operation_cancelled':
return UniversalBleErrorCode.operationCancelled;
case 'inprogress':
case 'alreadyinprogress':
case 'already_in_progress':
return UniversalBleErrorCode.operationInProgress;
case 'notpaired':
case 'not_paired':
return UniversalBleErrorCode.notPaired;
case 'notpairable':
case 'not_pairable':
return UniversalBleErrorCode.notPairable;
case 'alreadypaired':
case 'already_paired':
return UniversalBleErrorCode.alreadyPaired;
case 'pairingfailed':
case 'pairing_failed':
return UniversalBleErrorCode.pairingFailed;
case 'pairingcancelled':
case 'pairing_cancelled':
return UniversalBleErrorCode.pairingCancelled;
case 'pairingtimeout':
case 'pairing_timeout':
return UniversalBleErrorCode.pairingTimeout;
case 'pairingnotallowed':
case 'pairing_not_allowed':
return UniversalBleErrorCode.pairingNotAllowed;
case 'authenticationfailure':
case 'authentication_failure':
return UniversalBleErrorCode.authenticationFailure;
case 'authenticationtimeout':
case 'authentication_timeout':
case 'authenticationnotallowed':
case 'authentication_not_allowed':
return UniversalBleErrorCode.authenticationFailure;
case 'hardwarefailure':
case 'hardware_failure':
case 'toomanyconnections':
case 'too_many_connections':
case 'notreadytopair':
case 'not_ready_to_pair':
case 'nonsupportedprofiles':
case 'no_supported_profiles':
case 'invalidceremonydata':
case 'invalid_ceremony_data':
case 'requiredhandlernotregistered':
case 'required_handler_not_registered':
case 'rejectedbyhandler':
case 'rejected_by_handler':
case 'remotedevicehasassociation':
case 'remote_device_has_association':
return UniversalBleErrorCode.pairingFailed;
case 'protectionlevelcouldnotbemet':
case 'protection_level_could_not_be_met':
return UniversalBleErrorCode.protectionLevelNotMet;
case 'unpairingfailed':
case 'unpairing_failed':
return UniversalBleErrorCode.unpairingFailed;
case 'alreadyunpaired':
case 'already_unpaired':
return UniversalBleErrorCode.alreadyUnpaired;
case 'accessdenied':
case 'access_denied':
return UniversalBleErrorCode.accessDenied;
case 'scan_failed_already_started':
case 'scanfailedalreadystarted':
case 'scan_failed_application_registration_failed':
case 'scanfailedapplicationregistrationfailed':
case 'scan_failed_feature_unsupported':
case 'scanfailedfeatureunsupported':
case 'scan_failed_internal_error':
case 'scanfailedinternalerror':
case 'scan_failed_out_of_hardware_resources':
case 'scanfailedoutofhardwareresources':
case 'scan_failed_scanning_too_frequently':
case 'scanfailedscanningtoofrequently':
return UniversalBleErrorCode.scanFailed;
case 'stoppingscaninprogress':
case 'stopping_scan_in_progress':
return UniversalBleErrorCode.stoppingScanInProgress;
case 'gatt_failure':
case 'gattfailure':
case 'unreachable':
case 'protocolerror':
case 'protocol_error':
case 'gattunreachable':
case 'gatt_protocol_error':
case 'gatt_unlikely':
case 'gattunlikely':
case 'gatt_insufficient_resources':
case 'gattinsufficientresources':
return UniversalBleErrorCode.failed;
case 'gatt_read_not_permitted':
case 'gattreadnotpermitted':
return UniversalBleErrorCode.readNotPermitted;
case 'gatt_write_not_permitted':
case 'gattwritenotpermitted':
return UniversalBleErrorCode.writeNotPermitted;
case 'gatt_insufficient_authentication':
case 'gattinsufficientauthentication':
return UniversalBleErrorCode.insufficientAuthentication;
case 'gatt_insufficient_authorization':
case 'gattinsufficientauthorization':
return UniversalBleErrorCode.insufficientAuthorization;
case 'gatt_insufficient_encryption':
case 'gattinsufficientencryption':
return UniversalBleErrorCode.insufficientEncryption;
case 'gatt_insufficient_key_size':
case 'gattinsufficientkeysize':
return UniversalBleErrorCode.insufficientKeySize;
case 'gatt_request_not_supported':
case 'gattrequestnotsupported':
return UniversalBleErrorCode.operationNotSupported;
case 'gatt_invalid_offset':
case 'gattinvalidoffset':
return UniversalBleErrorCode.invalidOffset;
case 'gatt_invalid_attribute_length':
case 'gattinvalidattributelength':
return UniversalBleErrorCode.invalidAttributeLength;
case 'gatt_connection_congested':
case 'gattconnectioncongested':
return UniversalBleErrorCode.connectionFailed;
case 'gatt_invalid_handle':
case 'gattinvalidhandle':
return UniversalBleErrorCode.invalidHandle;
case 'gatt_invalid_pdu':
case 'gattinvalidpdu':
return UniversalBleErrorCode.invalidPdu;
case 'gatt_prepare_queue_full':
case 'gattpreparequeuefull':
return UniversalBleErrorCode.operationInProgress;
case 'gatt_attr_not_found':
case 'gattattrnotfound':
return UniversalBleErrorCode.serviceNotFound;
case 'gatt_attr_not_long':
case 'gattattrnotlong':
return UniversalBleErrorCode.invalidAttributeLength;
case 'gatt_unsupported_group':
case 'gattunsupportedgroup':
return UniversalBleErrorCode.operationNotSupported;
case 'feature_not_configured':
case 'featurenotconfigured':
case 'feature_not_supported':
case 'featurenotsupported':
case 'feature_supported':
case 'featuresupported':
return UniversalBleErrorCode.notSupported;
case 'error_profile_service_not_bound':
case 'errorprofileservicenotbound':
return UniversalBleErrorCode.failed;
case 'error_missing_bluetooth_connect_permission':
case 'errormissingbluetoothconnectpermission':
return UniversalBleErrorCode.bluetoothNotAllowed;
case 'error_device_not_bonded':
case 'errordevicenotbonded':
return UniversalBleErrorCode.notPaired;
case 'error_gatt_write_not_allowed':
case 'errorgattwritenotallowed':
return UniversalBleErrorCode.writeNotPermitted;
case 'error_gatt_write_request_busy':
case 'errorgattwriterequestbusy':
return UniversalBleErrorCode.writeRequestBusy;
case 'error_unknown':
case 'errorunknown':
return UniversalBleErrorCode.unknownError;
case 'webbluetoothgloballydisabled':
case 'web_bluetooth_globally_disabled':
return UniversalBleErrorCode.webBluetoothGloballyDisabled;
default:
return null;
}
}
static UniversalBleErrorCode _parseNumericErrorCode(int code) {
switch (code) {
case 0x00:
return UniversalBleErrorCode.unknownError;
case 0x01:
return UniversalBleErrorCode.invalidHandle;
case 0x02:
return UniversalBleErrorCode.readNotPermitted;
case 0x03:
return UniversalBleErrorCode.writeNotPermitted;
case 0x04:
return UniversalBleErrorCode.invalidPdu;
case 0x05:
return UniversalBleErrorCode.insufficientAuthentication;
// Consolidated: gattRequestNotSupported -> operationNotSupported
case 0x06:
return UniversalBleErrorCode.operationNotSupported;
case 0x07:
return UniversalBleErrorCode.invalidOffset;
case 0x08:
return UniversalBleErrorCode.insufficientAuthorization;
// Consolidated: gattPrepareQueueFull -> operationInProgress
case 0x09:
return UniversalBleErrorCode.operationInProgress;
// Consolidated: gattAttrNotFound -> serviceNotFound
case 0x0A:
return UniversalBleErrorCode.serviceNotFound;
// Consolidated: gattAttrNotLong -> invalidAttributeLength
case 0x0B:
return UniversalBleErrorCode.invalidAttributeLength;
case 0x0C:
return UniversalBleErrorCode.insufficientKeySize;
case 0x0D:
return UniversalBleErrorCode.invalidAttributeLength;
// Consolidated: gattUnlikely -> failed
case 0x0E:
return UniversalBleErrorCode.failed;
case 0x0F:
return UniversalBleErrorCode.insufficientEncryption;
// Consolidated: gattUnsupportedGroup -> operationNotSupported
case 0x10:
return UniversalBleErrorCode.operationNotSupported;
// Consolidated: gattInsufficientResources -> failed
case 0x11:
return UniversalBleErrorCode.failed;
// Consolidated: gattConnectionCongested -> connectionFailed
case 0x85:
return UniversalBleErrorCode.connectionFailed;
// Consolidated: gattFailure -> failed
case 0x101:
return UniversalBleErrorCode.failed;
}
// HCI error codes - consolidated to higher-level errors
switch (code) {
// Connection errors
case 0x08: // Connection Timeout
case 0x10: // Connection Accept Timeout Exceeded
return UniversalBleErrorCode.connectionTimeout;
case 0x09: // Connection Limit Exceeded
case 0x0A: // Synchronous Connection Limit To A Device Exceeded
return UniversalBleErrorCode.connectionLimitExceeded;
case 0x0B: // Connection Already Exists
return UniversalBleErrorCode.connectionAlreadyExists;
case 0x0D: // Connection Rejected due to Limited Resources
case 0x0F: // Connection Rejected due to Unacceptable BD_ADDR
case 0x39: // Connection Rejected due to No Suitable Channel Found
return UniversalBleErrorCode.connectionRejected;
case 0x0E: // Connection Rejected Due To Security Reasons
return UniversalBleErrorCode.connectionRejected;
case 0x13: // Remote User Terminated Connection
case 0x14: // Remote Device Terminated Connection due to Low Resources
case 0x15: // Remote Device Terminated Connection due to Power Off
case 0x16: // Connection Terminated By Local Host
case 0x3D: // Connection Terminated due to MIC Failure
return UniversalBleErrorCode.connectionTerminated;
case 0x3E: // Connection Failed to be Established
case 0x3F: // MAC Connection Failed
return UniversalBleErrorCode.connectionFailed;
// Pairing/Authentication errors
case 0x05: // Authentication Failure
return UniversalBleErrorCode.authenticationFailure;
case 0x18: // Pairing Not Allowed
return UniversalBleErrorCode.pairingNotAllowed;
case 0x03: // Hardware Failure
case 0x29: // Pairing With Unit Key Not Supported
case 0x37: // Secure Simple Pairing Not Supported By Host
case 0x38: // Host Busy - Pairing
return UniversalBleErrorCode.pairingFailed;
case 0x2F: // Insufficient Security
return UniversalBleErrorCode.insufficientEncryption;
// Operation errors
case 0x0C: // Command Disallowed
case 0x11: // Unsupported Feature or Parameter Value
case 0x12: // Invalid HCI Command Parameters
case 0x1A: // Unsupported Remote Feature
case 0x1E: // Invalid LMP Parameters
case 0x20: // Unsupported LMP Parameter Value
return UniversalBleErrorCode.operationNotSupported;
case 0x22: // LMP Response Timeout
return UniversalBleErrorCode.operationTimeout;
// General errors
case 0x01: // Unknown HCI Command
case 0x02: // Unknown Connection Identifier
return UniversalBleErrorCode.unknownError;
case 0x04: // Page Timeout
return UniversalBleErrorCode.connectionTimeout;
case 0x06: // PIN or Key Missing
return UniversalBleErrorCode.authenticationFailure;
case 0x07: // Memory Capacity Exceeded
return UniversalBleErrorCode.failed;
case 0x17: // Repeated Attempts
return UniversalBleErrorCode.failed;
case 0x25: // Encryption Mode Not Acceptable
return UniversalBleErrorCode.insufficientEncryption;
case 0x26: // Link Key cannot be Changed
case 0x27: // Requested QoS Not Supported
case 0x2C: // QoS Unacceptable Parameter
case 0x2D: // QoS Rejected
case 0x2E: // Channel Classification Not Supported
case 0x30: // Parameter Out Of Mandatory Range
case 0x32: // Role Switch Pending
case 0x35: // Role Switch Failed
case 0x36: // Extended Inquiry Response Too Large
case 0x3A: // Controller Busy
case 0x3B: // Unacceptable Connection Parameters
case 0x3C: // Advertising Timeout
return UniversalBleErrorCode.failed;
}
// Default to unknown error for unmapped codes
return UniversalBleErrorCode.unknownError;
}
}
+84
View File
@@ -169,3 +169,87 @@ class UniversalManufacturerData {
required this.data, required this.data,
}); });
} }
/// Unified error codes for all platforms
enum UniversalBleErrorCode {
// General errors
unknownError,
failed,
notSupported,
notImplemented,
channelError,
// Bluetooth availability errors
bluetoothNotAvailable,
bluetoothNotEnabled,
bluetoothNotAllowed,
bluetoothUnauthorized,
// Connection errors
deviceDisconnected,
connectionTimeout,
connectionFailed,
connectionRejected,
connectionLimitExceeded,
connectionAlreadyExists,
connectionTerminated,
connectionInProgress,
// Device/Service/Characteristic errors
illegalArgument,
deviceNotFound,
serviceNotFound,
characteristicNotFound,
invalidServiceUuid,
invalidCharacteristicUuid,
invalidOffset,
invalidAttributeLength,
invalidPdu,
invalidHandle,
// Operation errors
readFailed,
readNotPermitted,
writeFailed,
writeNotPermitted,
writeRequestBusy,
invalidAction,
operationNotSupported,
operationTimeout,
operationCancelled,
operationInProgress,
// Characteristic property errors
characteristicDoesNotSupportRead,
characteristicDoesNotSupportWrite,
characteristicDoesNotSupportWriteWithoutResponse,
characteristicDoesNotSupportNotify,
characteristicDoesNotSupportIndicate,
// Pairing errors
notPaired,
notPairable,
alreadyPaired,
pairingFailed,
pairingCancelled,
pairingTimeout,
pairingNotAllowed,
authenticationFailure,
insufficientAuthentication,
insufficientAuthorization,
insufficientEncryption,
insufficientKeySize,
protectionLevelNotMet,
accessDenied,
// Unpairing errors
unpairingFailed,
alreadyUnpaired,
// Scan errors
scanFailed,
stoppingScanInProgress,
// Web-specific errors
webBluetoothGloballyDisabled,
}
+2 -2
View File
@@ -1,6 +1,6 @@
name: universal_ble name: universal_ble
description: A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE) plugin for Flutter description: A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE) plugin for Flutter
version: 0.21.1 version: 1.0.0
homepage: https://navideck.com homepage: https://navideck.com
repository: https://github.com/Navideck/universal_ble repository: https://github.com/Navideck/universal_ble
issue_tracker: https://github.com/Navideck/universal_ble/issues issue_tracker: https://github.com/Navideck/universal_ble/issues
@@ -38,7 +38,7 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^6.0.0 flutter_lints: ^6.0.0
pigeon: ^22.4.0 pigeon: ^26.0.5
flutter: flutter:
plugin: plugin:
+6 -2
View File
@@ -1,6 +1,10 @@
#pragma once #pragma once
#include <string> #include <string>
#include <optional>
#include "helper/universal_enum.h"
#include "helper/universal_ble_base.h"
#include "generated/universal_ble.g.h"
namespace universal_ble namespace universal_ble
{ {
@@ -46,9 +50,9 @@ namespace universal_ble
return std::nullopt; return std::nullopt;
} }
inline std::optional<std::string> parse_pairing_fail_error(const DevicePairingResult& result) inline std::optional<std::string> device_pairing_result_to_string(const DevicePairingResultStatus result)
{ {
switch (result.Status()) switch (result)
{ {
case DevicePairingResultStatus::Paired: return std::nullopt; case DevicePairingResultStatus::Paired: return std::nullopt;
case DevicePairingResultStatus::AlreadyPaired: return "AlreadyPaired"; case DevicePairingResultStatus::AlreadyPaired: return "AlreadyPaired";
+22 -12
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v22.6.1), do not edit directly. // Autogenerated from Pigeon (v26.0.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
#undef _HAS_EXCEPTIONS #undef _HAS_EXCEPTIONS
@@ -425,21 +425,26 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType(
flutter::ByteStreamReader* stream) const { flutter::ByteStreamReader* stream) const {
switch (type) { switch (type) {
case 129: { case 129: {
return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); const auto& encodable_enum_arg = ReadValue(stream);
const int64_t enum_arg_value = encodable_enum_arg.IsNull() ? 0 : encodable_enum_arg.LongValue();
return encodable_enum_arg.IsNull() ? EncodableValue() : CustomEncodableValue(static_cast<UniversalBleErrorCode>(enum_arg_value));
} }
case 130: { case 130: {
return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
} }
case 131: { case 131: {
return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
} }
case 132: { case 132: {
return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
} }
case 133: { case 133: {
return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
} }
case 134: { case 134: {
return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
}
case 135: {
return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
} }
default: default:
@@ -451,33 +456,38 @@ void PigeonInternalCodecSerializer::WriteValue(
const EncodableValue& value, const EncodableValue& value,
flutter::ByteStreamWriter* stream) const { flutter::ByteStreamWriter* stream) const {
if (const CustomEncodableValue* custom_value = std::get_if<CustomEncodableValue>(&value)) { if (const CustomEncodableValue* custom_value = std::get_if<CustomEncodableValue>(&value)) {
if (custom_value->type() == typeid(UniversalBleScanResult)) { if (custom_value->type() == typeid(UniversalBleErrorCode)) {
stream->WriteByte(129); stream->WriteByte(129);
WriteValue(EncodableValue(static_cast<int>(std::any_cast<UniversalBleErrorCode>(*custom_value))), stream);
return;
}
if (custom_value->type() == typeid(UniversalBleScanResult)) {
stream->WriteByte(130);
WriteValue(EncodableValue(std::any_cast<UniversalBleScanResult>(*custom_value).ToEncodableList()), stream); WriteValue(EncodableValue(std::any_cast<UniversalBleScanResult>(*custom_value).ToEncodableList()), stream);
return; return;
} }
if (custom_value->type() == typeid(UniversalBleService)) { if (custom_value->type() == typeid(UniversalBleService)) {
stream->WriteByte(130); stream->WriteByte(131);
WriteValue(EncodableValue(std::any_cast<UniversalBleService>(*custom_value).ToEncodableList()), stream); WriteValue(EncodableValue(std::any_cast<UniversalBleService>(*custom_value).ToEncodableList()), stream);
return; return;
} }
if (custom_value->type() == typeid(UniversalBleCharacteristic)) { if (custom_value->type() == typeid(UniversalBleCharacteristic)) {
stream->WriteByte(131); stream->WriteByte(132);
WriteValue(EncodableValue(std::any_cast<UniversalBleCharacteristic>(*custom_value).ToEncodableList()), stream); WriteValue(EncodableValue(std::any_cast<UniversalBleCharacteristic>(*custom_value).ToEncodableList()), stream);
return; return;
} }
if (custom_value->type() == typeid(UniversalScanFilter)) { if (custom_value->type() == typeid(UniversalScanFilter)) {
stream->WriteByte(132); stream->WriteByte(133);
WriteValue(EncodableValue(std::any_cast<UniversalScanFilter>(*custom_value).ToEncodableList()), stream); WriteValue(EncodableValue(std::any_cast<UniversalScanFilter>(*custom_value).ToEncodableList()), stream);
return; return;
} }
if (custom_value->type() == typeid(UniversalManufacturerDataFilter)) { if (custom_value->type() == typeid(UniversalManufacturerDataFilter)) {
stream->WriteByte(133); stream->WriteByte(134);
WriteValue(EncodableValue(std::any_cast<UniversalManufacturerDataFilter>(*custom_value).ToEncodableList()), stream); WriteValue(EncodableValue(std::any_cast<UniversalManufacturerDataFilter>(*custom_value).ToEncodableList()), stream);
return; return;
} }
if (custom_value->type() == typeid(UniversalManufacturerData)) { if (custom_value->type() == typeid(UniversalManufacturerData)) {
stream->WriteByte(134); stream->WriteByte(135);
WriteValue(EncodableValue(std::any_cast<UniversalManufacturerData>(*custom_value).ToEncodableList()), stream); WriteValue(EncodableValue(std::any_cast<UniversalManufacturerData>(*custom_value).ToEncodableList()), stream);
return; return;
} }
+66 -18
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v22.6.1), do not edit directly. // Autogenerated from Pigeon (v26.0.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
#ifndef PIGEON_UNIVERSAL_BLE_G_H_ #ifndef PIGEON_UNIVERSAL_BLE_G_H_
@@ -57,6 +57,71 @@ template<class T> class ErrorOr {
}; };
// Unified error codes for all platforms
enum class UniversalBleErrorCode {
kUnknownError = 0,
kFailed = 1,
kNotSupported = 2,
kNotImplemented = 3,
kChannelError = 4,
kBluetoothNotAvailable = 5,
kBluetoothNotEnabled = 6,
kBluetoothNotAllowed = 7,
kBluetoothUnauthorized = 8,
kDeviceDisconnected = 9,
kConnectionTimeout = 10,
kConnectionFailed = 11,
kConnectionRejected = 12,
kConnectionLimitExceeded = 13,
kConnectionAlreadyExists = 14,
kConnectionTerminated = 15,
kConnectionInProgress = 16,
kIllegalArgument = 17,
kDeviceNotFound = 18,
kServiceNotFound = 19,
kCharacteristicNotFound = 20,
kInvalidServiceUuid = 21,
kInvalidCharacteristicUuid = 22,
kInvalidOffset = 23,
kInvalidAttributeLength = 24,
kInvalidPdu = 25,
kInvalidHandle = 26,
kReadFailed = 27,
kReadNotPermitted = 28,
kWriteFailed = 29,
kWriteNotPermitted = 30,
kWriteRequestBusy = 31,
kInvalidAction = 32,
kOperationNotSupported = 33,
kOperationTimeout = 34,
kOperationCancelled = 35,
kOperationInProgress = 36,
kCharacteristicDoesNotSupportRead = 37,
kCharacteristicDoesNotSupportWrite = 38,
kCharacteristicDoesNotSupportWriteWithoutResponse = 39,
kCharacteristicDoesNotSupportNotify = 40,
kCharacteristicDoesNotSupportIndicate = 41,
kNotPaired = 42,
kNotPairable = 43,
kAlreadyPaired = 44,
kPairingFailed = 45,
kPairingCancelled = 46,
kPairingTimeout = 47,
kPairingNotAllowed = 48,
kAuthenticationFailure = 49,
kInsufficientAuthentication = 50,
kInsufficientAuthorization = 51,
kInsufficientEncryption = 52,
kInsufficientKeySize = 53,
kProtectionLevelNotMet = 54,
kAccessDenied = 55,
kUnpairingFailed = 56,
kAlreadyUnpaired = 57,
kScanFailed = 58,
kStoppingScanInProgress = 59,
kWebBluetoothGloballyDisabled = 60
};
// Generated class from Pigeon that represents data sent in messages. // Generated class from Pigeon that represents data sent in messages.
class UniversalBleScanResult { class UniversalBleScanResult {
@@ -96,7 +161,6 @@ class UniversalBleScanResult {
void set_services(const flutter::EncodableList* value_arg); void set_services(const flutter::EncodableList* value_arg);
void set_services(const flutter::EncodableList& value_arg); void set_services(const flutter::EncodableList& value_arg);
private: private:
static UniversalBleScanResult FromEncodableList(const flutter::EncodableList& list); static UniversalBleScanResult FromEncodableList(const flutter::EncodableList& list);
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
@@ -109,7 +173,6 @@ class UniversalBleScanResult {
std::optional<int64_t> rssi_; std::optional<int64_t> rssi_;
std::optional<flutter::EncodableList> manufacturer_data_list_; std::optional<flutter::EncodableList> manufacturer_data_list_;
std::optional<flutter::EncodableList> services_; std::optional<flutter::EncodableList> services_;
}; };
@@ -131,7 +194,6 @@ class UniversalBleService {
void set_characteristics(const flutter::EncodableList* value_arg); void set_characteristics(const flutter::EncodableList* value_arg);
void set_characteristics(const flutter::EncodableList& value_arg); void set_characteristics(const flutter::EncodableList& value_arg);
private: private:
static UniversalBleService FromEncodableList(const flutter::EncodableList& list); static UniversalBleService FromEncodableList(const flutter::EncodableList& list);
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
@@ -140,7 +202,6 @@ class UniversalBleService {
friend class PigeonInternalCodecSerializer; friend class PigeonInternalCodecSerializer;
std::string uuid_; std::string uuid_;
std::optional<flutter::EncodableList> characteristics_; std::optional<flutter::EncodableList> characteristics_;
}; };
@@ -158,7 +219,6 @@ class UniversalBleCharacteristic {
const flutter::EncodableList& properties() const; const flutter::EncodableList& properties() const;
void set_properties(const flutter::EncodableList& value_arg); void set_properties(const flutter::EncodableList& value_arg);
private: private:
static UniversalBleCharacteristic FromEncodableList(const flutter::EncodableList& list); static UniversalBleCharacteristic FromEncodableList(const flutter::EncodableList& list);
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
@@ -167,7 +227,6 @@ class UniversalBleCharacteristic {
friend class PigeonInternalCodecSerializer; friend class PigeonInternalCodecSerializer;
std::string uuid_; std::string uuid_;
flutter::EncodableList properties_; flutter::EncodableList properties_;
}; };
@@ -191,7 +250,6 @@ class UniversalScanFilter {
const flutter::EncodableList& with_manufacturer_data() const; const flutter::EncodableList& with_manufacturer_data() const;
void set_with_manufacturer_data(const flutter::EncodableList& value_arg); void set_with_manufacturer_data(const flutter::EncodableList& value_arg);
private: private:
static UniversalScanFilter FromEncodableList(const flutter::EncodableList& list); static UniversalScanFilter FromEncodableList(const flutter::EncodableList& list);
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
@@ -201,7 +259,6 @@ class UniversalScanFilter {
flutter::EncodableList with_services_; flutter::EncodableList with_services_;
flutter::EncodableList with_name_prefix_; flutter::EncodableList with_name_prefix_;
flutter::EncodableList with_manufacturer_data_; flutter::EncodableList with_manufacturer_data_;
}; };
@@ -228,7 +285,6 @@ class UniversalManufacturerDataFilter {
void set_mask(const std::vector<uint8_t>* value_arg); void set_mask(const std::vector<uint8_t>* value_arg);
void set_mask(const std::vector<uint8_t>& value_arg); void set_mask(const std::vector<uint8_t>& value_arg);
private: private:
static UniversalManufacturerDataFilter FromEncodableList(const flutter::EncodableList& list); static UniversalManufacturerDataFilter FromEncodableList(const flutter::EncodableList& list);
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
@@ -238,7 +294,6 @@ class UniversalManufacturerDataFilter {
int64_t company_identifier_; int64_t company_identifier_;
std::optional<std::vector<uint8_t>> data_; std::optional<std::vector<uint8_t>> data_;
std::optional<std::vector<uint8_t>> mask_; std::optional<std::vector<uint8_t>> mask_;
}; };
@@ -256,7 +311,6 @@ class UniversalManufacturerData {
const std::vector<uint8_t>& data() const; const std::vector<uint8_t>& data() const;
void set_data(const std::vector<uint8_t>& value_arg); void set_data(const std::vector<uint8_t>& value_arg);
private: private:
static UniversalManufacturerData FromEncodableList(const flutter::EncodableList& list); static UniversalManufacturerData FromEncodableList(const flutter::EncodableList& list);
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
@@ -265,7 +319,6 @@ class UniversalManufacturerData {
friend class PigeonInternalCodecSerializer; friend class PigeonInternalCodecSerializer;
int64_t company_identifier_; int64_t company_identifier_;
std::vector<uint8_t> data_; std::vector<uint8_t> data_;
}; };
@@ -280,12 +333,10 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer {
void WriteValue( void WriteValue(
const flutter::EncodableValue& value, const flutter::EncodableValue& value,
flutter::ByteStreamWriter* stream) const override; flutter::ByteStreamWriter* stream) const override;
protected: protected:
flutter::EncodableValue ReadValueOfType( flutter::EncodableValue ReadValueOfType(
uint8_t type, uint8_t type,
flutter::ByteStreamReader* stream) const override; flutter::ByteStreamReader* stream) const override;
}; };
// Flutter -> Native // Flutter -> Native
@@ -352,10 +403,8 @@ class UniversalBlePlatformChannel {
const std::string& message_channel_suffix); const std::string& message_channel_suffix);
static flutter::EncodableValue WrapError(std::string_view error_message); static flutter::EncodableValue WrapError(std::string_view error_message);
static flutter::EncodableValue WrapError(const FlutterError& error); static flutter::EncodableValue WrapError(const FlutterError& error);
protected: protected:
UniversalBlePlatformChannel() = default; UniversalBlePlatformChannel() = default;
}; };
// Native -> Flutter // Native -> Flutter
// //
@@ -393,7 +442,6 @@ class UniversalBleCallbackChannel {
const std::string* error, const std::string* error,
std::function<void(void)>&& on_success, std::function<void(void)>&& on_success,
std::function<void(const FlutterError&)>&& on_error); std::function<void(const FlutterError&)>&& on_error);
private: private:
flutter::BinaryMessenger* binary_messenger_; flutter::BinaryMessenger* binary_messenger_;
std::string message_channel_suffix_; std::string message_channel_suffix_;
+142 -1
View File
@@ -1,8 +1,11 @@
#include "Utils.h" #include "utils.h"
#include "../generated/universal_ble.g.h"
#include "../enum_parser.h"
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <algorithm>
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
#include <sdkddkver.h> #include <sdkddkver.h>
@@ -158,4 +161,142 @@ namespace universal_ble
return rove.dwMajorVersion == 10 && rove.dwBuildNumber >= 22000; return rove.dwMajorVersion == 10 && rove.dwBuildNumber >= 22000;
} }
FlutterError create_flutter_error(
UniversalBleErrorCode code,
const std::string& message,
const std::string& details
)
{
// Pass the enum's underlying integer value as string in code, and enum name or details in details
std::string code_str = std::to_string(static_cast<int>(code));
std::string details_str = details.empty() ? std::to_string(static_cast<int>(code)) : details;
return FlutterError(code_str, message, details_str);
}
FlutterError create_flutter_error_from_gatt_communication_status(
GattCommunicationStatus status,
const std::string& message
)
{
if (status == GattCommunicationStatus::Success) {
// Success case - shouldn't normally create an error, but if called, return unknown
return create_flutter_error(UniversalBleErrorCode::kUnknownError, message);
}
UniversalBleErrorCode error_code;
switch (status)
{
case GattCommunicationStatus::Unreachable:
case GattCommunicationStatus::ProtocolError:
case GattCommunicationStatus::AccessDenied:
default:
error_code = UniversalBleErrorCode::kFailed;
break;
}
auto error_message = gatt_communication_status_to_error(status);
std::string final_message = message.empty() && error_message.has_value()
? error_message.value()
: message;
return create_flutter_error(error_code, final_message);
}
FlutterError create_flutter_error_from_pairing_status(
DevicePairingResultStatus status,
const std::string& message
)
{
if (status == DevicePairingResultStatus::Paired) {
// Success case - shouldn't normally create an error, but if called, return unknown
return create_flutter_error(UniversalBleErrorCode::kUnknownError, message);
}
UniversalBleErrorCode error_code;
switch (status)
{
case DevicePairingResultStatus::AlreadyPaired:
error_code = UniversalBleErrorCode::kAlreadyPaired;
break;
case DevicePairingResultStatus::ConnectionRejected:
error_code = UniversalBleErrorCode::kConnectionRejected;
break;
case DevicePairingResultStatus::NotPaired:
error_code = UniversalBleErrorCode::kNotPaired;
break;
case DevicePairingResultStatus::NotReadyToPair:
case DevicePairingResultStatus::TooManyConnections:
case DevicePairingResultStatus::HardwareFailure:
case DevicePairingResultStatus::NoSupportedProfiles:
case DevicePairingResultStatus::InvalidCeremonyData:
case DevicePairingResultStatus::RequiredHandlerNotRegistered:
case DevicePairingResultStatus::RejectedByHandler:
case DevicePairingResultStatus::RemoteDeviceHasAssociation:
error_code = UniversalBleErrorCode::kPairingFailed;
break;
case DevicePairingResultStatus::AuthenticationTimeout:
case DevicePairingResultStatus::AuthenticationNotAllowed:
case DevicePairingResultStatus::AuthenticationFailure:
error_code = UniversalBleErrorCode::kAuthenticationFailure;
break;
case DevicePairingResultStatus::ProtectionLevelCouldNotBeMet:
error_code = UniversalBleErrorCode::kProtectionLevelNotMet;
break;
case DevicePairingResultStatus::AccessDenied:
error_code = UniversalBleErrorCode::kAccessDenied;
break;
case DevicePairingResultStatus::PairingCanceled:
error_code = UniversalBleErrorCode::kPairingCancelled;
break;
case DevicePairingResultStatus::OperationAlreadyInProgress:
error_code = UniversalBleErrorCode::kOperationInProgress;
break;
default:
error_code = UniversalBleErrorCode::kPairingFailed;
break;
}
auto error_message = device_pairing_result_to_string(status);
std::string final_message = message.empty() && error_message.has_value()
? error_message.value()
: message;
return create_flutter_error(error_code, final_message);
}
FlutterError create_flutter_error_from_unpairing_status(
DeviceUnpairingResultStatus status,
const std::string& message
)
{
if (status == DeviceUnpairingResultStatus::Unpaired) {
// Success case - shouldn't normally create an error, but if called, return unknown
return create_flutter_error(UniversalBleErrorCode::kUnknownError, message);
}
UniversalBleErrorCode error_code;
switch (status)
{
case DeviceUnpairingResultStatus::Failed:
error_code = UniversalBleErrorCode::kUnpairingFailed;
break;
case DeviceUnpairingResultStatus::AlreadyUnpaired:
error_code = UniversalBleErrorCode::kAlreadyUnpaired;
break;
case DeviceUnpairingResultStatus::AccessDenied:
error_code = UniversalBleErrorCode::kAccessDenied;
break;
case DeviceUnpairingResultStatus::OperationAlreadyInProgress:
error_code = UniversalBleErrorCode::kOperationInProgress;
break;
default:
error_code = UniversalBleErrorCode::kUnpairingFailed;
break;
}
auto error_message = device_unpairing_result_to_string(status);
std::string final_message = message.empty() && error_message.has_value()
? error_message.value()
: message;
return create_flutter_error(error_code, final_message);
}
} // namespace universal_ble } // namespace universal_ble
+38 -2
View File
@@ -6,8 +6,10 @@
#include "winrt/Windows.Foundation.h" #include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Storage.Streams.h" #include "winrt/Windows.Storage.Streams.h"
#include "winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h"
#include "winrt/base.h" #include "winrt/base.h"
#include "universal_ble_base.h" #include "universal_ble_base.h"
#include "../generated/universal_ble.g.h"
constexpr uint32_t TEN_SECONDS_IN_MSECS = 10000; constexpr uint32_t TEN_SECONDS_IN_MSECS = 10000;
@@ -28,6 +30,40 @@ namespace universal_ble
bool is_little_endian(); bool is_little_endian();
bool is_windows11_or_greater(); bool is_windows11_or_greater();
/// Creates a FlutterError with the error code enum in details
FlutterError create_flutter_error(
UniversalBleErrorCode code,
const std::string& message = "",
const std::string& details = ""
);
// Error creation functions
/// Creates a FlutterError from GATT communication status
FlutterError create_flutter_error_from_gatt_communication_status(
GattCommunicationStatus status,
const std::string& message = ""
);
/// Creates a FlutterError from device pairing result status
FlutterError create_flutter_error_from_pairing_status(
DevicePairingResultStatus status,
const std::string& message = ""
);
/// Creates a FlutterError from device unpairing result status
FlutterError create_flutter_error_from_unpairing_status(
DeviceUnpairingResultStatus status,
const std::string& message = ""
);
// Create Flutter unknown error
inline FlutterError create_flutter_unknown_error(
const std::string& message = "Unknown error"
) {
return create_flutter_error(UniversalBleErrorCode::kUnknownError, message);
}
/// To call async functions synchronously /// To call async functions synchronously
template <typename AsyncT> template <typename AsyncT>
static auto async_get(AsyncT const &async) static auto async_get(AsyncT const &async)
@@ -42,11 +78,11 @@ namespace universal_ble
} }
catch (const hresult_error &err) catch (const hresult_error &err)
{ {
throw FlutterError("Failed", to_string(err.message())); throw create_flutter_error(UniversalBleErrorCode::kFailed, to_string(err.message()));
} }
catch (...) catch (...)
{ {
throw FlutterError("Failed", "Unknown error"); throw create_flutter_unknown_error();
} }
} }
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -61,11 +61,11 @@ namespace universal_ble
{ {
if (gatt_map.count(service_uuid) == 0) if (gatt_map.count(service_uuid) == 0)
{ {
throw FlutterError("IllegalArgument", "Service not found"); throw create_flutter_error(UniversalBleErrorCode::kServiceNotFound, "Service not found");
} }
if (gatt_map[service_uuid].characteristics.count(characteristic_uuid) == 0) if (gatt_map[service_uuid].characteristics.count(characteristic_uuid) == 0)
{ {
throw FlutterError("IllegalArgument", "Characteristic not found"); throw create_flutter_error(UniversalBleErrorCode::kCharacteristicNotFound, "Characteristic not found");
} }
return gatt_map[service_uuid].characteristics.at(characteristic_uuid); return gatt_map[service_uuid].characteristics.at(characteristic_uuid);
} }