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:
@@ -1,3 +1,6 @@
|
||||
## 1.0.0
|
||||
* Unified error codes for all platforms
|
||||
|
||||
## 0.21.1
|
||||
* Fix device name resolution on Windows
|
||||
* Add `exclusionFilters` to filter out devices from scan results
|
||||
|
||||
@@ -17,6 +17,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE
|
||||
- [Requesting MTU](#requesting-mtu)
|
||||
- [Command Queue](#command-queue)
|
||||
- [Timeout](#timeout)
|
||||
- [Error Handling](#error-handling)
|
||||
- [UUID Format Agnostic](#uuid-format-agnostic)
|
||||
|
||||
## 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.
|
||||
|
||||
## 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
|
||||
|
||||
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
|
||||
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
|
||||
|
||||
@@ -7,16 +7,22 @@ package com.navideck.universal_ble
|
||||
import android.util.Log
|
||||
import io.flutter.plugin.common.BasicMessageChannel
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MessageCodec
|
||||
import io.flutter.plugin.common.StandardMethodCodec
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
import java.io.ByteArrayOutputStream
|
||||
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)
|
||||
}
|
||||
|
||||
private fun wrapError(exception: Throwable): List<Any?> {
|
||||
fun wrapError(exception: Throwable): List<Any?> {
|
||||
return if (exception is FlutterError) {
|
||||
listOf(
|
||||
exception.code,
|
||||
@@ -31,9 +37,37 @@ private fun wrapError(exception: Throwable): List<Any?> {
|
||||
)
|
||||
}
|
||||
}
|
||||
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.
|
||||
@@ -47,6 +81,77 @@ class FlutterError (
|
||||
val details: Any? = null
|
||||
) : 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. */
|
||||
data class UniversalBleScanResult (
|
||||
val deviceId: String,
|
||||
@@ -78,6 +183,16 @@ data class UniversalBleScanResult (
|
||||
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. */
|
||||
@@ -99,6 +214,16 @@ data class UniversalBleService (
|
||||
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. */
|
||||
@@ -120,6 +245,16 @@ data class UniversalBleCharacteristic (
|
||||
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,
|
||||
)
|
||||
}
|
||||
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. */
|
||||
@@ -172,6 +317,16 @@ data class UniversalManufacturerDataFilter (
|
||||
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. */
|
||||
@@ -193,36 +348,51 @@ data class UniversalManufacturerData (
|
||||
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() {
|
||||
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
|
||||
return when (type) {
|
||||
129.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
UniversalBleScanResult.fromList(it)
|
||||
return (readValue(buffer) as Long?)?.let {
|
||||
UniversalBleErrorCode.ofRaw(it.toInt())
|
||||
}
|
||||
}
|
||||
130.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
UniversalBleService.fromList(it)
|
||||
UniversalBleScanResult.fromList(it)
|
||||
}
|
||||
}
|
||||
131.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
UniversalBleCharacteristic.fromList(it)
|
||||
UniversalBleService.fromList(it)
|
||||
}
|
||||
}
|
||||
132.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
UniversalScanFilter.fromList(it)
|
||||
UniversalBleCharacteristic.fromList(it)
|
||||
}
|
||||
}
|
||||
133.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
UniversalManufacturerDataFilter.fromList(it)
|
||||
UniversalScanFilter.fromList(it)
|
||||
}
|
||||
}
|
||||
134.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
UniversalManufacturerDataFilter.fromList(it)
|
||||
}
|
||||
}
|
||||
135.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
UniversalManufacturerData.fromList(it)
|
||||
}
|
||||
@@ -232,30 +402,34 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() {
|
||||
}
|
||||
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
|
||||
when (value) {
|
||||
is UniversalBleScanResult -> {
|
||||
is UniversalBleErrorCode -> {
|
||||
stream.write(129)
|
||||
writeValue(stream, value.toList())
|
||||
writeValue(stream, value.raw.toLong())
|
||||
}
|
||||
is UniversalBleService -> {
|
||||
is UniversalBleScanResult -> {
|
||||
stream.write(130)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is UniversalBleCharacteristic -> {
|
||||
is UniversalBleService -> {
|
||||
stream.write(131)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is UniversalScanFilter -> {
|
||||
is UniversalBleCharacteristic -> {
|
||||
stream.write(132)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is UniversalManufacturerDataFilter -> {
|
||||
is UniversalScanFilter -> {
|
||||
stream.write(133)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is UniversalManufacturerData -> {
|
||||
is UniversalManufacturerDataFilter -> {
|
||||
stream.write(134)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is UniversalManufacturerData -> {
|
||||
stream.write(135)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
else -> super.writeValue(stream, value)
|
||||
}
|
||||
}
|
||||
@@ -302,10 +476,10 @@ interface UniversalBlePlatformChannel {
|
||||
api.getBluetoothAvailabilityState{ result: Result<Long> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,10 +494,10 @@ interface UniversalBlePlatformChannel {
|
||||
api.enableBluetooth{ result: Result<Boolean> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,10 +512,10 @@ interface UniversalBlePlatformChannel {
|
||||
api.disableBluetooth{ result: Result<Boolean> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,7 +533,7 @@ interface UniversalBlePlatformChannel {
|
||||
api.startScan(filterArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
UniversalBlePigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
@@ -375,7 +549,7 @@ interface UniversalBlePlatformChannel {
|
||||
api.stopScan()
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
UniversalBlePigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
@@ -393,7 +567,7 @@ interface UniversalBlePlatformChannel {
|
||||
api.connect(deviceIdArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
UniversalBlePigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
@@ -411,7 +585,7 @@ interface UniversalBlePlatformChannel {
|
||||
api.disconnect(deviceIdArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
UniversalBlePigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
@@ -431,9 +605,9 @@ interface UniversalBlePlatformChannel {
|
||||
api.setNotifiable(deviceIdArg, serviceArg, characteristicArg, bleInputPropertyArg) { result: Result<Unit> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
reply.reply(wrapResult(null))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapResult(null))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -450,10 +624,10 @@ interface UniversalBlePlatformChannel {
|
||||
api.discoverServices(deviceIdArg) { result: Result<List<UniversalBleService>> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
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> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
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> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
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> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
reply.reply(wrapResult(null))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapResult(null))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -536,10 +710,10 @@ interface UniversalBlePlatformChannel {
|
||||
api.isPaired(deviceIdArg) { result: Result<Boolean> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
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> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -577,7 +751,7 @@ interface UniversalBlePlatformChannel {
|
||||
api.unPair(deviceIdArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
UniversalBlePigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
@@ -594,10 +768,10 @@ interface UniversalBlePlatformChannel {
|
||||
api.getSystemDevices(withServicesArg) { result: Result<List<UniversalBleScanResult>> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
reply.reply(UniversalBlePigeonUtils.wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -614,7 +788,7 @@ interface UniversalBlePlatformChannel {
|
||||
val wrapped: List<Any?> = try {
|
||||
listOf(api.getConnectionState(deviceIdArg))
|
||||
} catch (exception: Throwable) {
|
||||
wrapError(exception)
|
||||
UniversalBlePigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
@@ -650,7 +824,7 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} 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))
|
||||
}
|
||||
} 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))
|
||||
}
|
||||
} 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))
|
||||
}
|
||||
} 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))
|
||||
}
|
||||
} 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.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.os.ParcelUuid
|
||||
import android.util.Log
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.util.UUID
|
||||
import kotlin.experimental.and
|
||||
|
||||
@@ -46,7 +43,7 @@ class UniversalBleFilterUtil {
|
||||
}
|
||||
|
||||
private fun isNameMatchingFilters(scanFilter: UniversalScanFilter, name: String?): Boolean {
|
||||
val namePrefixFilter = scanFilter.withNamePrefix.filterNotNull()
|
||||
val namePrefixFilter = scanFilter.withNamePrefix
|
||||
if (namePrefixFilter.isEmpty()) {
|
||||
return true
|
||||
}
|
||||
@@ -74,7 +71,7 @@ class UniversalBleFilterUtil {
|
||||
scanFilter: UniversalScanFilter,
|
||||
manufacturerDataList: List<UniversalManufacturerData>,
|
||||
): Boolean {
|
||||
val filters = scanFilter.withManufacturerData.filterNotNull()
|
||||
val filters = scanFilter.withManufacturerData
|
||||
if (filters.isEmpty()) return true
|
||||
if (manufacturerDataList.isEmpty()) return false
|
||||
return manufacturerDataList.any { msd ->
|
||||
@@ -122,8 +119,8 @@ fun UniversalScanFilter.toScanFilters(serviceUuids: List<UUID>): List<ScanFilter
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
throw FlutterError(
|
||||
"illegalIllegalArgument",
|
||||
throw createFlutterError(
|
||||
UniversalBleErrorCode.INVALID_SERVICE_UUID,
|
||||
"Invalid serviceId: $service",
|
||||
e.toString()
|
||||
)
|
||||
@@ -133,7 +130,7 @@ fun UniversalScanFilter.toScanFilters(serviceUuids: List<UUID>): List<ScanFilter
|
||||
// Add ManufacturerData Filter
|
||||
for (manufacturerData in this.withManufacturerData) {
|
||||
try {
|
||||
manufacturerData?.companyIdentifier?.let {
|
||||
manufacturerData.companyIdentifier.let {
|
||||
val data: ByteArray = manufacturerData.data ?: ByteArray(0)
|
||||
val mask: ByteArray? = manufacturerData.mask
|
||||
if (mask == null) {
|
||||
@@ -152,9 +149,9 @@ fun UniversalScanFilter.toScanFilters(serviceUuids: List<UUID>): List<ScanFilter
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
throw FlutterError(
|
||||
"illegalIllegalArgument",
|
||||
"Invalid manufacturerData: ${manufacturerData?.companyIdentifier} ${manufacturerData?.data} ${manufacturerData?.mask}",
|
||||
throw createFlutterError(
|
||||
UniversalBleErrorCode.FAILED,
|
||||
"Invalid manufacturerData: ${manufacturerData.companyIdentifier} ${manufacturerData.data} ${manufacturerData.mask}",
|
||||
e.toString()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.util.SparseArray
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.util.UUID
|
||||
import androidx.core.util.size
|
||||
|
||||
private const val TAG = "UniversalBlePlugin"
|
||||
|
||||
@@ -46,8 +47,8 @@ enum class BleInputProperty(val value: Long) {
|
||||
}
|
||||
|
||||
enum class BleOutputProperty(val value: Long) {
|
||||
withResponse(0),
|
||||
withoutResponse(1);
|
||||
WithResponse(0),
|
||||
WithoutResponse(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +81,10 @@ fun List<String>.toUUIDList(): List<UUID> {
|
||||
|
||||
fun String.toBluetoothGatt(): BluetoothGatt {
|
||||
return this.findGatt()
|
||||
?: throw FlutterError("IllegalArgument", "Unknown deviceId: $this", null)
|
||||
?: throw createFlutterError(
|
||||
UniversalBleErrorCode.DEVICE_NOT_FOUND,
|
||||
"Unknown deviceId: $this",
|
||||
)
|
||||
}
|
||||
|
||||
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>
|
||||
get() {
|
||||
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>> {
|
||||
return (0 until size()).map { index ->
|
||||
return (0 until size).map { index ->
|
||||
keyAt(index) to valueAt(index)
|
||||
}
|
||||
}
|
||||
@@ -189,16 +146,6 @@ fun BluetoothGatt.getCharacteristic(
|
||||
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() {
|
||||
try {
|
||||
javaClass.getMethod("removeBond").invoke(this)
|
||||
@@ -207,7 +154,6 @@ fun BluetoothDevice.removeBond() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun BluetoothGattCharacteristic.getPropertiesList(): ArrayList<Long> {
|
||||
val propertiesList = arrayListOf<Long>()
|
||||
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 =
|
||||
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(
|
||||
"DeviceDisconnected",
|
||||
"Device Disconnected",
|
||||
null
|
||||
)
|
||||
fun gattStatusToUniversalBleErrorCode(code: Int): UniversalBleErrorCode {
|
||||
return when (code) {
|
||||
BluetoothGatt.GATT_READ_NOT_PERMITTED -> UniversalBleErrorCode.READ_NOT_PERMITTED
|
||||
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? {
|
||||
return when (this) {
|
||||
|
||||
@@ -32,6 +32,7 @@ import io.flutter.plugin.common.PluginRegistry
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import androidx.core.content.edit
|
||||
|
||||
|
||||
private const val TAG = "UniversalBlePlugin"
|
||||
@@ -102,7 +103,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
if (bluetoothEnableRequestFuture != null) {
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError("Failed", "Bluetooth enable request in progress", null)
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.OPERATION_IN_PROGRESS,
|
||||
"Bluetooth enable request in progress"
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
@@ -120,7 +124,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
if (bluetoothDisableRequestFuture != null) {
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError("Failed", "Bluetooth disable request in progress", null)
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.OPERATION_IN_PROGRESS,
|
||||
"Bluetooth disable request in progress"
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
@@ -131,9 +138,9 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
|
||||
override fun startScan(filter: UniversalScanFilter?) {
|
||||
if (!isBluetoothAvailable()) throw FlutterError(
|
||||
"BluetoothNotEnabled",
|
||||
"Bluetooth not enabled",
|
||||
if (!isBluetoothAvailable()) throw createFlutterError(
|
||||
UniversalBleErrorCode.BLUETOOTH_NOT_ENABLED,
|
||||
"Bluetooth not enabled"
|
||||
)
|
||||
|
||||
val builder = ScanSettings.Builder()
|
||||
@@ -143,10 +150,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
val settings = builder.build()
|
||||
|
||||
val usesCustomFilters = filter?.usesCustomFilters() ?: false;
|
||||
val usesCustomFilters = filter?.usesCustomFilters() ?: false
|
||||
|
||||
try {
|
||||
val filterServices = filter?.withServices?.filterNotNull()?.toUUIDList() ?: emptyList()
|
||||
val filterServices = filter?.withServices?.toUUIDList() ?: emptyList()
|
||||
var scanFilters = emptyList<ScanFilter>()
|
||||
|
||||
// Set custom scan filter only if required
|
||||
@@ -156,25 +163,25 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
universalBleFilterUtil.serviceFilterUUIDS = filterServices
|
||||
} else {
|
||||
universalBleFilterUtil.scanFilter = null
|
||||
scanFilters = filter?.toScanFilters(filterServices) ?: emptyList<ScanFilter>()
|
||||
scanFilters = filter?.toScanFilters(filterServices) ?: emptyList()
|
||||
}
|
||||
|
||||
safeScanner.startScan(
|
||||
scanFilters, settings, scanCallback
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
throw FlutterError(
|
||||
"illegalIllegalArgument",
|
||||
throw createFlutterError(
|
||||
UniversalBleErrorCode.FAILED,
|
||||
"Failed to start Scan",
|
||||
e.toString()
|
||||
details = e.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopScan() {
|
||||
if (!isBluetoothAvailable()) throw FlutterError(
|
||||
"BluetoothNotEnabled",
|
||||
"Bluetooth not enabled",
|
||||
if (!isBluetoothAvailable()) throw createFlutterError(
|
||||
UniversalBleErrorCode.BLUETOOTH_NOT_ENABLED,
|
||||
"Bluetooth not enabled"
|
||||
)
|
||||
// check if already scanning
|
||||
safeScanner.stopScan(scanCallback)
|
||||
@@ -192,7 +199,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
return
|
||||
} 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))
|
||||
} else {
|
||||
callback(
|
||||
Result.failure(FlutterError("Failed", "Failed to discover services", null))
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.FAILED,
|
||||
"Failed to discover services"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (e: FlutterError) {
|
||||
@@ -253,7 +268,12 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
discoverServicesFutureList.filter { it.deviceId == gatt.device.address }.forEach {
|
||||
discoverServicesFutureList.remove(it)
|
||||
it.result(
|
||||
Result.failure(FlutterError("Failed", "Failed to discover services", null))
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.FAILED,
|
||||
"Failed to discover services"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
return
|
||||
@@ -290,7 +310,14 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
gatt.getCharacteristic(service, characteristic)
|
||||
|
||||
if (gattCharacteristic == null) {
|
||||
callback(subscriptionFailedError("characteristic not found"))
|
||||
callback(
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
|
||||
"characteristic not found"
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -298,7 +325,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
gattCharacteristic.getDescriptor(ccdCharacteristic)
|
||||
|
||||
val bleInputPropertyEnum: BleInputProperty =
|
||||
BleInputProperty.values().first { it.value == bleInputProperty }
|
||||
BleInputProperty.entries.first { it.value == bleInputProperty }
|
||||
|
||||
val (value, enable) = when (bleInputPropertyEnum) {
|
||||
BleInputProperty.Notification -> BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE to true
|
||||
@@ -310,14 +337,30 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
// Some devices do not need CCCD to update
|
||||
@Suppress("DEPRECATION")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val status = gatt.writeDescriptor(descriptor, value)
|
||||
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
|
||||
}
|
||||
} else {
|
||||
descriptor.value = value
|
||||
if (!gatt.writeDescriptor(descriptor)) {
|
||||
callback(subscriptionFailedError("Failed to update descriptor"))
|
||||
callback(
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.FAILED,
|
||||
"Failed to update descriptor"
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -339,12 +382,27 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(subscriptionFailedError())
|
||||
callback(
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.FAILED,
|
||||
"Failed to update subscription state"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (e: FlutterError) {
|
||||
callback(Result.failure(e))
|
||||
} 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)
|
||||
if (gattCharacteristic == null) {
|
||||
callback(
|
||||
Result.failure(FlutterError("IllegalArgument", "Unknown characteristic", null))
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
|
||||
"Unknown characteristic"
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
if (!gatt.readCharacteristic(gattCharacteristic)) {
|
||||
callback(
|
||||
Result.failure(unknownCharacteristicError(characteristic))
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
|
||||
"$characteristic not found",
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -383,8 +451,8 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
} catch (e: Exception) {
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
"Failed",
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.READ_FAILED,
|
||||
"Failed to read value",
|
||||
e.toString()
|
||||
)
|
||||
@@ -410,10 +478,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
} else {
|
||||
it.result(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
status.toString(),
|
||||
"Failed to read: (${status.parseGattErrorCode()})",
|
||||
null,
|
||||
createFlutterError(
|
||||
gattStatusToUniversalBleErrorCode(status),
|
||||
"Failed to read",
|
||||
status.toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -434,33 +502,38 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
val gatt = deviceId.toBluetoothGatt()
|
||||
val gattCharacteristic = gatt.getCharacteristic(service, characteristic)
|
||||
if (gattCharacteristic == null) {
|
||||
callback(Result.failure(unknownCharacteristicError(characteristic)))
|
||||
callback(
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.CHARACTERISTIC_NOT_FOUND,
|
||||
"$characteristic not found",
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
var writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
|
||||
if (bleOutputProperty == BleOutputProperty.withResponse.value) {
|
||||
if (bleOutputProperty == BleOutputProperty.WithResponse.value) {
|
||||
if (gattCharacteristic.properties and BluetoothGattCharacteristic.PROPERTY_WRITE == 0) {
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
"IllegalArgument",
|
||||
"Characteristic does not support write withResponse",
|
||||
null
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.CHARACTERISTIC_DOES_NOT_SUPPORT_WRITE,
|
||||
"Characteristic does not support write withResponse"
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
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) {
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
"IllegalArgument",
|
||||
"Characteristic does not support write withoutResponse",
|
||||
null
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.CHARACTERISTIC_DOES_NOT_SUPPORT_WRITE_WITHOUT_RESPONSE,
|
||||
"Characteristic does not support write withoutResponse"
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -495,10 +568,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
writeResultFutureList.remove(writeFuture)
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
"WriteError",
|
||||
"Failed to write: ${result.parseGattErrorCode()}",
|
||||
null
|
||||
createFlutterError(
|
||||
gattStatusToUniversalBleErrorCode(result),
|
||||
"Failed to write",
|
||||
result.toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -524,10 +597,10 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
} else {
|
||||
it.result(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
status.toString(),
|
||||
"Failed to write: (${status.parseGattErrorCode()})",
|
||||
null,
|
||||
createFlutterError(
|
||||
gattStatusToUniversalBleErrorCode(status),
|
||||
"Failed to write",
|
||||
status.toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -553,7 +626,14 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
it.result(Result.success(mtu.toLong()))
|
||||
} 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) {
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
"InProgress",
|
||||
"Pairing already in progress",
|
||||
null
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.OPERATION_IN_PROGRESS,
|
||||
"Pairing already in progress"
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -594,12 +673,19 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
if (remoteDevice.createBond()) {
|
||||
pairResultFutures[deviceId] = callback
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("Failed", "Failed to pair", null)))
|
||||
callback(
|
||||
Result.failure(
|
||||
createFlutterError(
|
||||
UniversalBleErrorCode.PAIRING_FAILED,
|
||||
"Failed to pair"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
callback(
|
||||
Result.failure(
|
||||
FlutterError("Failed", e.toString(), null)
|
||||
createFlutterError(UniversalBleErrorCode.FAILED, e.toString())
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -664,7 +750,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
try {
|
||||
val timeout = (devices.size * 2).toLong()
|
||||
latch.await(timeout, TimeUnit.SECONDS)
|
||||
} catch (e: InterruptedException) {
|
||||
} catch (_: InterruptedException) {
|
||||
Thread.currentThread().interrupt()
|
||||
}
|
||||
|
||||
@@ -749,10 +835,13 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
private fun cleanConnection(gatt: BluetoothGatt) {
|
||||
gatt.removeCache()
|
||||
gatt.disconnect()
|
||||
|
||||
val deviceDisconnectedError: FlutterError = createFlutterError(
|
||||
UniversalBleErrorCode.DEVICE_DISCONNECTED,
|
||||
"Device Disconnected",
|
||||
)
|
||||
readResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
it.result(Result.failure(DeviceDisconnectedError))
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -760,7 +849,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
writeResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
it.result(Result.failure(DeviceDisconnectedError))
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -768,7 +857,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
subscriptionResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
it.result(Result.failure(DeviceDisconnectedError))
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -776,7 +865,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
mtuResultFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
it.result(Result.failure(DeviceDisconnectedError))
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -784,7 +873,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
}
|
||||
discoverServicesFutureList.removeAll {
|
||||
if (it.deviceId == gatt.device.address) {
|
||||
it.result(Result.failure(DeviceDisconnectedError))
|
||||
it.result(Result.failure(deviceDisconnectedError))
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -830,7 +919,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
Log.v(TAG, "${device.address} BOND_BONDING")
|
||||
}
|
||||
|
||||
BluetoothDevice.BOND_BONDED -> {
|
||||
BOND_BONDED -> {
|
||||
onBondStateUpdate(device.address, true)
|
||||
}
|
||||
|
||||
@@ -944,7 +1033,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
if (descriptor?.uuid.toString() == ccdCharacteristic.toString()) {
|
||||
val char: String? = descriptor?.characteristic?.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) {
|
||||
updateSubscriptionState(deviceId, char, service, status)
|
||||
}
|
||||
@@ -963,14 +1052,13 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
it.serviceId == service
|
||||
}.forEach {
|
||||
subscriptionResultFutureList.remove(it)
|
||||
val error: String? = status.parseGattErrorCode()
|
||||
if (error != null) {
|
||||
if (status != BluetoothGatt.GATT_SUCCESS) {
|
||||
it.result(
|
||||
Result.failure(
|
||||
FlutterError(
|
||||
status.toString(),
|
||||
"Failed to update subscription state: $error",
|
||||
null,
|
||||
createFlutterError(
|
||||
gattStatusToUniversalBleErrorCode(status),
|
||||
"Failed to update subscription state",
|
||||
status.toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -989,7 +1077,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
||||
"com.navideck.universal_ble.services",
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
cachedServicesSharedPref.edit().putStringSet(deviceId, services.toSet()).apply()
|
||||
cachedServicesSharedPref.edit { putStringSet(deviceId, services.toSet()) }
|
||||
cachedServicesMap[deviceId] = services
|
||||
}
|
||||
|
||||
|
||||
Executable
+11
@@ -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"
|
||||
@@ -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
|
||||
|
||||
import Foundation
|
||||
@@ -15,9 +15,9 @@ import Foundation
|
||||
final class PigeonError: Error {
|
||||
let code: 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.message = message
|
||||
self.details = details
|
||||
@@ -68,8 +68,137 @@ private func nilOrValue<T>(_ value: Any?) -> 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.
|
||||
struct UniversalBleScanResult {
|
||||
struct UniversalBleScanResult: Hashable {
|
||||
var deviceId: String
|
||||
var name: String? = nil
|
||||
var isPaired: Bool? = nil
|
||||
@@ -78,7 +207,6 @@ struct UniversalBleScanResult {
|
||||
var services: [String]? = nil
|
||||
|
||||
|
||||
|
||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleScanResult? {
|
||||
let deviceId = pigeonVar_list[0] as! String
|
||||
@@ -107,15 +235,19 @@ struct UniversalBleScanResult {
|
||||
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.
|
||||
struct UniversalBleService {
|
||||
struct UniversalBleService: Hashable {
|
||||
var uuid: String
|
||||
var characteristics: [UniversalBleCharacteristic]? = nil
|
||||
|
||||
|
||||
|
||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleService? {
|
||||
let uuid = pigeonVar_list[0] as! String
|
||||
@@ -132,15 +264,19 @@ struct UniversalBleService {
|
||||
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.
|
||||
struct UniversalBleCharacteristic {
|
||||
struct UniversalBleCharacteristic: Hashable {
|
||||
var uuid: String
|
||||
var properties: [Int64]
|
||||
|
||||
|
||||
|
||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleCharacteristic? {
|
||||
let uuid = pigeonVar_list[0] as! String
|
||||
@@ -157,18 +293,22 @@ struct UniversalBleCharacteristic {
|
||||
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
|
||||
///
|
||||
/// Generated class from Pigeon that represents data sent in messages.
|
||||
struct UniversalScanFilter {
|
||||
struct UniversalScanFilter: Hashable {
|
||||
var withServices: [String]
|
||||
var withNamePrefix: [String]
|
||||
var withManufacturerData: [UniversalManufacturerDataFilter]
|
||||
|
||||
|
||||
|
||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalScanFilter? {
|
||||
let withServices = pigeonVar_list[0] as! [String]
|
||||
@@ -188,16 +328,20 @@ struct UniversalScanFilter {
|
||||
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.
|
||||
struct UniversalManufacturerDataFilter {
|
||||
struct UniversalManufacturerDataFilter: Hashable {
|
||||
var companyIdentifier: Int64
|
||||
var data: FlutterStandardTypedData? = nil
|
||||
var mask: FlutterStandardTypedData? = nil
|
||||
|
||||
|
||||
|
||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerDataFilter? {
|
||||
let companyIdentifier = pigeonVar_list[0] as! Int64
|
||||
@@ -217,15 +361,19 @@ struct UniversalManufacturerDataFilter {
|
||||
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.
|
||||
struct UniversalManufacturerData {
|
||||
struct UniversalManufacturerData: Hashable {
|
||||
var companyIdentifier: Int64
|
||||
var data: FlutterStandardTypedData
|
||||
|
||||
|
||||
|
||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||
static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerData? {
|
||||
let companyIdentifier = pigeonVar_list[0] as! Int64
|
||||
@@ -242,22 +390,33 @@ struct UniversalManufacturerData {
|
||||
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 {
|
||||
override func readValue(ofType type: UInt8) -> Any? {
|
||||
switch type {
|
||||
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:
|
||||
return UniversalBleService.fromList(self.readValue() as! [Any?])
|
||||
return UniversalBleScanResult.fromList(self.readValue() as! [Any?])
|
||||
case 131:
|
||||
return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?])
|
||||
return UniversalBleService.fromList(self.readValue() as! [Any?])
|
||||
case 132:
|
||||
return UniversalScanFilter.fromList(self.readValue() as! [Any?])
|
||||
return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?])
|
||||
case 133:
|
||||
return UniversalManufacturerDataFilter.fromList(self.readValue() as! [Any?])
|
||||
return UniversalScanFilter.fromList(self.readValue() as! [Any?])
|
||||
case 134:
|
||||
return UniversalManufacturerDataFilter.fromList(self.readValue() as! [Any?])
|
||||
case 135:
|
||||
return UniversalManufacturerData.fromList(self.readValue() as! [Any?])
|
||||
default:
|
||||
return super.readValue(ofType: type)
|
||||
@@ -267,24 +426,27 @@ private class UniversalBlePigeonCodecReader: FlutterStandardReader {
|
||||
|
||||
private class UniversalBlePigeonCodecWriter: FlutterStandardWriter {
|
||||
override func writeValue(_ value: Any) {
|
||||
if let value = value as? UniversalBleScanResult {
|
||||
if let value = value as? UniversalBleErrorCode {
|
||||
super.writeByte(129)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalBleService {
|
||||
super.writeValue(value.rawValue)
|
||||
} else if let value = value as? UniversalBleScanResult {
|
||||
super.writeByte(130)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalBleCharacteristic {
|
||||
} else if let value = value as? UniversalBleService {
|
||||
super.writeByte(131)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalScanFilter {
|
||||
} else if let value = value as? UniversalBleCharacteristic {
|
||||
super.writeByte(132)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalManufacturerDataFilter {
|
||||
} else if let value = value as? UniversalScanFilter {
|
||||
super.writeByte(133)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalManufacturerData {
|
||||
} else if let value = value as? UniversalManufacturerDataFilter {
|
||||
super.writeByte(134)
|
||||
super.writeValue(value.toList())
|
||||
} else if let value = value as? UniversalManufacturerData {
|
||||
super.writeByte(135)
|
||||
super.writeValue(value.toList())
|
||||
} else {
|
||||
super.writeValue(value)
|
||||
}
|
||||
@@ -650,7 +812,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
|
||||
let details: String? = nilOrValue(listResponse[2])
|
||||
completion(.failure(PigeonError(code: code, message: message, details: details)))
|
||||
} else {
|
||||
completion(.success(Void()))
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -668,7 +830,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
|
||||
let details: String? = nilOrValue(listResponse[2])
|
||||
completion(.failure(PigeonError(code: code, message: message, details: details)))
|
||||
} else {
|
||||
completion(.success(Void()))
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -686,7 +848,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
|
||||
let details: String? = nilOrValue(listResponse[2])
|
||||
completion(.failure(PigeonError(code: code, message: message, details: details)))
|
||||
} else {
|
||||
completion(.success(Void()))
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -704,7 +866,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
|
||||
let details: String? = nilOrValue(listResponse[2])
|
||||
completion(.failure(PigeonError(code: code, message: message, details: details)))
|
||||
} else {
|
||||
completion(.success(Void()))
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -722,7 +884,7 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
|
||||
let details: String? = nilOrValue(listResponse[2])
|
||||
completion(.failure(PigeonError(code: code, message: message, details: details)))
|
||||
} else {
|
||||
completion(.success(Void()))
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
func toPigeonError() -> PigeonError {
|
||||
func toFlutterError() -> PigeonError {
|
||||
let nsError = self as NSError
|
||||
let errorCode: String = .init(nsError.code)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,11 +55,11 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
}
|
||||
|
||||
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) {
|
||||
completion(Result.failure(PigeonError(code: "NotSupported", message: nil, details: nil)))
|
||||
completion(Result.failure(createFlutterError(code: .notSupported)))
|
||||
}
|
||||
|
||||
func startScan(filter: UniversalScanFilter?) throws {
|
||||
@@ -122,7 +122,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
characteristicReadFutures.removeAll { future in
|
||||
if future.deviceId == deviceId {
|
||||
future.result(
|
||||
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
|
||||
Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
|
||||
)
|
||||
return true
|
||||
}
|
||||
@@ -131,7 +131,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
characteristicWriteFutures.removeAll { future in
|
||||
if future.deviceId == deviceId {
|
||||
future.result(
|
||||
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
|
||||
Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
|
||||
)
|
||||
return true
|
||||
}
|
||||
@@ -140,7 +140,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
characteristicNotifyFutures.removeAll { future in
|
||||
if future.deviceId == deviceId {
|
||||
future.result(
|
||||
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
|
||||
Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
|
||||
)
|
||||
return true
|
||||
}
|
||||
@@ -149,7 +149,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
discoverServicesFutures.removeAll { future in
|
||||
if future.deviceId == deviceId {
|
||||
future.result(
|
||||
Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
|
||||
Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
|
||||
)
|
||||
return true
|
||||
}
|
||||
@@ -161,7 +161,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
func discoverServices(deviceId: String, completion: @escaping (Result<[UniversalBleService], Error>) -> Void) {
|
||||
guard let peripheral = deviceId.findPeripheral(manager: manager) else {
|
||||
completion(
|
||||
Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))
|
||||
Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(self)"))
|
||||
)
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -224,15 +224,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
|
||||
func readValue(deviceId: String, service: String, characteristic: String, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
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) {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -253,12 +253,12 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
|
||||
if type == CBCharacteristicWriteType.withResponse {
|
||||
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
|
||||
}
|
||||
} else if type == CBCharacteristicWriteType.withoutResponse {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -275,7 +275,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
|
||||
func requestMtu(deviceId: String, expectedMtu _: Int64, completion: @escaping (Result<Int64, Error>) -> Void) {
|
||||
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
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
completion(Result.failure(PigeonError(code: "Implemented in Dart", message: nil, details: nil)))
|
||||
completion(Result.failure(createFlutterError(code: .notImplemented)))
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -427,8 +427,8 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
characteristicWriteFutures.removeAll { future in
|
||||
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
|
||||
if let pigeonError = error?.toPigeonError() {
|
||||
future.result(Result.failure(pigeonError))
|
||||
if let flutterError = error?.toFlutterError() {
|
||||
future.result(Result.failure(flutterError))
|
||||
} else {
|
||||
future.result(Result.success({}()))
|
||||
}
|
||||
@@ -441,8 +441,8 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
|
||||
characteristicNotifyFutures.removeAll { future in
|
||||
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
|
||||
if let pigeonError = error?.toPigeonError() {
|
||||
future.result(Result.failure(pigeonError))
|
||||
if let flutterError = error?.toFlutterError() {
|
||||
future.result(Result.failure(flutterError))
|
||||
} else {
|
||||
future.result(Result.success({}()))
|
||||
}
|
||||
@@ -467,13 +467,13 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
// Update futures for readValue
|
||||
characteristicReadFutures.removeAll { future in
|
||||
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
|
||||
if let pigeonError = error?.toPigeonError() {
|
||||
future.result(Result.failure(pigeonError))
|
||||
if let flutterError = error?.toFlutterError() {
|
||||
future.result(Result.failure(flutterError))
|
||||
} else {
|
||||
if let characteristicValue = characteristic.value {
|
||||
future.result(Result.success(FlutterStandardTypedData(bytes: characteristicValue)))
|
||||
} 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
|
||||
@@ -485,14 +485,14 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
||||
|
||||
extension CBPeripheral {
|
||||
func saveCache() {
|
||||
discoveredPeripherals[self.uuid.uuidString] = self
|
||||
discoveredPeripherals[uuid.uuidString] = self
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func getPeripheral(manager: CBCentralManager) throws -> CBPeripheral {
|
||||
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
|
||||
}
|
||||
@@ -515,7 +515,7 @@ extension [String] {
|
||||
func toCBUUID() throws -> [CBUUID] {
|
||||
return try compactMap { serviceUUID in
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>12.0</string>
|
||||
<string>13.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# 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.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
@@ -31,11 +31,11 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
|
||||
|
||||
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
|
||||
PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
@@ -470,7 +470,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -598,7 +598,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -647,7 +647,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
@@ -54,6 +55,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -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/universal_ble.dart';
|
||||
|
||||
@@ -105,13 +106,17 @@ extension BleDeviceExtension on BleDevice {
|
||||
}
|
||||
|
||||
if (discoveredServices.isEmpty) {
|
||||
throw ServiceNotFoundException('No services found');
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.serviceNotFound,
|
||||
message: 'No services found',
|
||||
);
|
||||
}
|
||||
|
||||
return discoveredServices.firstWhere(
|
||||
(s) => BleUuidParser.compareStrings(s.uuid, service),
|
||||
orElse: () => throw ServiceNotFoundException(
|
||||
'Service "$service" not available',
|
||||
orElse: () => throw UniversalBleException(
|
||||
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';
|
||||
|
||||
/// Extension methods for [BleService] objects.
|
||||
@@ -8,12 +9,16 @@ extension BleServiceExtension on BleService {
|
||||
/// with the given UUID is not available.
|
||||
BleCharacteristic getCharacteristic(String characteristicId) {
|
||||
if (characteristics.isEmpty) {
|
||||
throw CharacteristicNotFoundException('No characteristics found');
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.characteristicNotFound,
|
||||
message: 'No characteristics found',
|
||||
);
|
||||
}
|
||||
return characteristics.firstWhere(
|
||||
(c) => BleUuidParser.compareStrings(c.uuid, characteristicId),
|
||||
orElse: () => throw CharacteristicNotFoundException(
|
||||
'Characteristic "$characteristicId" not available',
|
||||
orElse: () => throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.characteristicNotFound,
|
||||
message: 'Characteristic "$characteristicId" not available',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,58 +1,85 @@
|
||||
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 {
|
||||
late String message;
|
||||
/// Base exception class for all BLE errors with typed error codes
|
||||
class UniversalBleException implements Exception {
|
||||
final UniversalBleErrorCode code;
|
||||
final String message;
|
||||
final dynamic details;
|
||||
|
||||
ConnectionException([dynamic error]) {
|
||||
message = _errorParser(error);
|
||||
}
|
||||
UniversalBleException({
|
||||
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(
|
||||
code: UniversalBleErrorParser.getCode(error),
|
||||
message: message,
|
||||
details: details,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PairingException implements Exception {
|
||||
late String message;
|
||||
/// Exception thrown when connection-related errors occur
|
||||
class ConnectionException extends UniversalBleException {
|
||||
ConnectionException._({
|
||||
required super.code,
|
||||
required super.message,
|
||||
super.details,
|
||||
});
|
||||
|
||||
PairingException([dynamic error]) {
|
||||
message = _errorParser(error);
|
||||
ConnectionException([dynamic error])
|
||||
: this._(
|
||||
code: UniversalBleErrorParser.getCode(error),
|
||||
message: _errorParser(error),
|
||||
details: error,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
/// Exception thrown when pairing-related errors occur
|
||||
class PairingException extends UniversalBleException {
|
||||
PairingException._({
|
||||
required super.code,
|
||||
required super.message,
|
||||
super.details,
|
||||
});
|
||||
|
||||
/// Legacy constructor for backward compatibility
|
||||
PairingException([dynamic error])
|
||||
: this._(
|
||||
code: UniversalBleErrorParser.getCode(error),
|
||||
message: _errorParser(error),
|
||||
details: error,
|
||||
);
|
||||
}
|
||||
|
||||
class WebBluetoothGloballyDisabled implements Exception {
|
||||
String message;
|
||||
WebBluetoothGloballyDisabled(this.message);
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
class NotFoundException implements Exception {}
|
||||
|
||||
class ServiceNotFoundException implements NotFoundException {
|
||||
String message;
|
||||
ServiceNotFoundException(this.message);
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
class CharacteristicNotFoundException implements NotFoundException {
|
||||
String message;
|
||||
CharacteristicNotFoundException(this.message);
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
/// Exception thrown when Web Bluetooth API is globally disabled
|
||||
class WebBluetoothGloballyDisabled extends UniversalBleException {
|
||||
WebBluetoothGloballyDisabled({
|
||||
super.code = UniversalBleErrorCode.webBluetoothGloballyDisabled,
|
||||
required super.message,
|
||||
super.details,
|
||||
});
|
||||
}
|
||||
|
||||
/// Legacy error parser for backward compatibility
|
||||
String _errorParser(dynamic error) {
|
||||
if (error == null) {
|
||||
return "Failed";
|
||||
} 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) {
|
||||
return error;
|
||||
} else {
|
||||
|
||||
@@ -3,9 +3,12 @@ import 'dart:async';
|
||||
import 'package:bluez/bluez.dart';
|
||||
import 'package:flutter/services.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/universal_ble_pigeon/universal_ble.g.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/universal_ble_exceptions.dart';
|
||||
|
||||
class UniversalBleLinux extends UniversalBlePlatform {
|
||||
UniversalBleLinux._();
|
||||
@@ -180,7 +183,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
|
||||
if (device.gattServices.isEmpty && !device.servicesResolved) {
|
||||
throw "Failed to resolve services";
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.failed,
|
||||
message: "Failed to resolve services",
|
||||
);
|
||||
}
|
||||
|
||||
List<BleService> services = [];
|
||||
@@ -217,7 +223,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
orElse: () => null);
|
||||
|
||||
if (c == null) {
|
||||
throw Exception('Unknown characteristic:$characteristic');
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.characteristicNotFound,
|
||||
message: 'Unknown characteristic:$characteristic',
|
||||
);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -279,9 +288,8 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
final data = await c.readValue();
|
||||
return Uint8List.fromList(data);
|
||||
} on BlueZFailedException catch (e) {
|
||||
throw PlatformException(
|
||||
code: e.errorCode ?? "ReadFailed",
|
||||
message: e.message,
|
||||
throw e.toUniversalBleException(
|
||||
defaultCode: UniversalBleErrorCode.readFailed,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -307,9 +315,8 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
);
|
||||
}
|
||||
} on BlueZFailedException catch (e) {
|
||||
throw PlatformException(
|
||||
code: e.errorCode ?? "WriteFailed",
|
||||
message: e.message,
|
||||
throw e.toUniversalBleException(
|
||||
defaultCode: UniversalBleErrorCode.writeFailed,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -317,7 +324,12 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
@override
|
||||
Future<int> requestMtu(String deviceId, int expectedMtu) async {
|
||||
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 (BlueZGattCharacteristic characteristic in service.characteristics) {
|
||||
int? mtu = characteristic.mtu;
|
||||
@@ -325,7 +337,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
if (mtu != null) return mtu - 3;
|
||||
}
|
||||
}
|
||||
throw Exception('MTU not available');
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.operationNotSupported,
|
||||
message: 'MTU not available',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -393,7 +408,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
(device) => device?.address == deviceId,
|
||||
orElse: () => null);
|
||||
if (device == null) {
|
||||
throw Exception('Unknown deviceId:$deviceId');
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.deviceNotFound,
|
||||
message: 'Unknown deviceId:$deviceId',
|
||||
);
|
||||
}
|
||||
return device;
|
||||
}
|
||||
@@ -459,7 +477,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
/// example: 'Operation failed with ATT error: 0x90' => 144
|
||||
String? get errorCode {
|
||||
|
||||
@@ -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
|
||||
// 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) {
|
||||
return <Object?>[];
|
||||
}
|
||||
@@ -25,6 +26,86 @@ List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty
|
||||
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 {
|
||||
UniversalBleScanResult({
|
||||
required this.deviceId,
|
||||
@@ -47,7 +128,7 @@ class UniversalBleScanResult {
|
||||
|
||||
List<String>? services;
|
||||
|
||||
Object encode() {
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[
|
||||
deviceId,
|
||||
name,
|
||||
@@ -58,6 +139,10 @@ class UniversalBleScanResult {
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
|
||||
static UniversalBleScanResult decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return UniversalBleScanResult(
|
||||
@@ -65,10 +150,27 @@ class UniversalBleScanResult {
|
||||
name: result[1] as String?,
|
||||
isPaired: result[2] as bool?,
|
||||
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>(),
|
||||
);
|
||||
}
|
||||
|
||||
@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 {
|
||||
@@ -81,20 +183,41 @@ class UniversalBleService {
|
||||
|
||||
List<UniversalBleCharacteristic>? characteristics;
|
||||
|
||||
Object encode() {
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[
|
||||
uuid,
|
||||
characteristics,
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
|
||||
static UniversalBleService decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return UniversalBleService(
|
||||
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 {
|
||||
@@ -107,13 +230,17 @@ class UniversalBleCharacteristic {
|
||||
|
||||
List<int> properties;
|
||||
|
||||
Object encode() {
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[
|
||||
uuid,
|
||||
properties,
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
|
||||
static UniversalBleCharacteristic decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return UniversalBleCharacteristic(
|
||||
@@ -121,6 +248,23 @@ class UniversalBleCharacteristic {
|
||||
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
|
||||
@@ -137,7 +281,7 @@ class UniversalScanFilter {
|
||||
|
||||
List<UniversalManufacturerDataFilter> withManufacturerData;
|
||||
|
||||
Object encode() {
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[
|
||||
withServices,
|
||||
withNamePrefix,
|
||||
@@ -145,14 +289,35 @@ class UniversalScanFilter {
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
|
||||
static UniversalScanFilter decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return UniversalScanFilter(
|
||||
withServices: (result[0] 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 {
|
||||
@@ -168,7 +333,7 @@ class UniversalManufacturerDataFilter {
|
||||
|
||||
Uint8List? mask;
|
||||
|
||||
Object encode() {
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[
|
||||
companyIdentifier,
|
||||
data,
|
||||
@@ -176,6 +341,10 @@ class UniversalManufacturerDataFilter {
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
|
||||
static UniversalManufacturerDataFilter decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return UniversalManufacturerDataFilter(
|
||||
@@ -184,6 +353,23 @@ class UniversalManufacturerDataFilter {
|
||||
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 {
|
||||
@@ -196,13 +382,17 @@ class UniversalManufacturerData {
|
||||
|
||||
Uint8List data;
|
||||
|
||||
Object encode() {
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[
|
||||
companyIdentifier,
|
||||
data,
|
||||
];
|
||||
}
|
||||
|
||||
Object encode() {
|
||||
return _toList();
|
||||
}
|
||||
|
||||
static UniversalManufacturerData decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return UniversalManufacturerData(
|
||||
@@ -210,8 +400,24 @@ class UniversalManufacturerData {
|
||||
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 {
|
||||
const _PigeonCodec();
|
||||
@@ -220,24 +426,27 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
if (value is int) {
|
||||
buffer.putUint8(4);
|
||||
buffer.putInt64(value);
|
||||
} else if (value is UniversalBleScanResult) {
|
||||
} else if (value is UniversalBleErrorCode) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is UniversalBleService) {
|
||||
writeValue(buffer, value.index);
|
||||
} else if (value is UniversalBleScanResult) {
|
||||
buffer.putUint8(130);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is UniversalBleCharacteristic) {
|
||||
} else if (value is UniversalBleService) {
|
||||
buffer.putUint8(131);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is UniversalScanFilter) {
|
||||
} else if (value is UniversalBleCharacteristic) {
|
||||
buffer.putUint8(132);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is UniversalManufacturerDataFilter) {
|
||||
} else if (value is UniversalScanFilter) {
|
||||
buffer.putUint8(133);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is UniversalManufacturerData) {
|
||||
} else if (value is UniversalManufacturerDataFilter) {
|
||||
buffer.putUint8(134);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is UniversalManufacturerData) {
|
||||
buffer.putUint8(135);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
super.writeValue(buffer, value);
|
||||
}
|
||||
@@ -247,16 +456,19 @@ class _PigeonCodec extends StandardMessageCodec {
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 129:
|
||||
return UniversalBleScanResult.decode(readValue(buffer)!);
|
||||
final int? value = readValue(buffer) as int?;
|
||||
return value == null ? null : UniversalBleErrorCode.values[value];
|
||||
case 130:
|
||||
return UniversalBleService.decode(readValue(buffer)!);
|
||||
return UniversalBleScanResult.decode(readValue(buffer)!);
|
||||
case 131:
|
||||
return UniversalBleCharacteristic.decode(readValue(buffer)!);
|
||||
return UniversalBleService.decode(readValue(buffer)!);
|
||||
case 132:
|
||||
return UniversalScanFilter.decode(readValue(buffer)!);
|
||||
return UniversalBleCharacteristic.decode(readValue(buffer)!);
|
||||
case 133:
|
||||
return UniversalManufacturerDataFilter.decode(readValue(buffer)!);
|
||||
return UniversalScanFilter.decode(readValue(buffer)!);
|
||||
case 134:
|
||||
return UniversalManufacturerDataFilter.decode(readValue(buffer)!);
|
||||
case 135:
|
||||
return UniversalManufacturerData.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
@@ -269,9 +481,11 @@ class UniversalBlePlatformChannel {
|
||||
/// Constructor for [UniversalBlePlatformChannel]. The [binaryMessenger] named argument is
|
||||
/// available for dependency injection. If it is left null, the default
|
||||
/// BinaryMessenger will be used which routes to the host platform.
|
||||
UniversalBlePlatformChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
|
||||
UniversalBlePlatformChannel(
|
||||
{BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
|
||||
: pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
pigeonVar_messageChannelSuffix =
|
||||
messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
final BinaryMessenger? pigeonVar_binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
||||
@@ -279,14 +493,17 @@ class UniversalBlePlatformChannel {
|
||||
final String pigeonVar_messageChannelSuffix;
|
||||
|
||||
Future<int> getBluetoothAvailabilityState() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(null) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -306,14 +523,17 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<bool> enableBluetooth() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(null) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -333,14 +553,17 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<bool> disableBluetooth() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(null) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -360,14 +583,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<void> startScan(UniversalScanFilter? filter) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[filter]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[filter]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -382,14 +609,17 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<void> stopScan() async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(null) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -404,14 +634,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<void> connect(String deviceId) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -426,14 +660,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<void> disconnect(String deviceId) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -447,15 +685,20 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setNotifiable(String deviceId, String service, String characteristic, int bleInputProperty) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
Future<void> setNotifiable(String deviceId, String service,
|
||||
String characteristic, int bleInputProperty) async {
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel
|
||||
.send(<Object?>[deviceId, service, characteristic, bleInputProperty]);
|
||||
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) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -470,14 +713,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<List<UniversalBleService>> discoverServices(String deviceId) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -492,19 +739,25 @@ class UniversalBlePlatformChannel {
|
||||
message: 'Host platform returned null value for non-null return value.',
|
||||
);
|
||||
} 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 {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
Future<Uint8List> readValue(
|
||||
String deviceId, String service, String characteristic) async {
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId, service, characteristic]);
|
||||
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) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -524,14 +777,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<int> requestMtu(String deviceId, int expectedMtu) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId, expectedMtu]);
|
||||
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) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} 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 {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
Future<void> writeValue(String deviceId, String service,
|
||||
String characteristic, Uint8List value, int bleOutputProperty) async {
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
|
||||
<Object?>[deviceId, service, characteristic, value, bleOutputProperty]);
|
||||
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) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -573,14 +835,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<bool> isPaired(String deviceId) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -600,14 +866,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<bool> pair(String deviceId) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -627,14 +897,18 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
|
||||
Future<void> unPair(String deviceId) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -648,15 +922,20 @@ class UniversalBlePlatformChannel {
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<UniversalBleScanResult>> getSystemDevices(List<String> withServices) async {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
Future<List<UniversalBleScanResult>> getSystemDevices(
|
||||
List<String> withServices) async {
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[withServices]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[withServices]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -671,19 +950,24 @@ class UniversalBlePlatformChannel {
|
||||
message: 'Host platform returned null value for non-null return value.',
|
||||
);
|
||||
} 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 {
|
||||
final String pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel =
|
||||
BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture =
|
||||
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||
final List<Object?>? pigeonVar_replyList =
|
||||
await pigeonVar_channel.send(<Object?>[deviceId]) as List<Object?>?;
|
||||
await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
@@ -713,15 +997,24 @@ abstract class UniversalBleCallbackChannel {
|
||||
|
||||
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);
|
||||
|
||||
static void setUp(UniversalBleCallbackChannel? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
static void setUp(
|
||||
UniversalBleCallbackChannel? api, {
|
||||
BinaryMessenger? binaryMessenger,
|
||||
String messageChannelSuffix = '',
|
||||
}) {
|
||||
messageChannelSuffix =
|
||||
messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
{
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', pigeonChannelCodec,
|
||||
final BasicMessageChannel<
|
||||
Object?> pigeonVar_channel = BasicMessageChannel<
|
||||
Object?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
@@ -739,14 +1032,18 @@ abstract class UniversalBleCallbackChannel {
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: 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?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', pigeonChannelCodec,
|
||||
final BasicMessageChannel<
|
||||
Object?> pigeonVar_channel = BasicMessageChannel<
|
||||
Object?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
@@ -768,14 +1065,18 @@ abstract class UniversalBleCallbackChannel {
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: 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?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', pigeonChannelCodec,
|
||||
final BasicMessageChannel<
|
||||
Object?> pigeonVar_channel = BasicMessageChannel<
|
||||
Object?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
@@ -784,7 +1085,8 @@ abstract class UniversalBleCallbackChannel {
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null.');
|
||||
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,
|
||||
'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null, expected non-null UniversalBleScanResult.');
|
||||
try {
|
||||
@@ -793,14 +1095,18 @@ abstract class UniversalBleCallbackChannel {
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: 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?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', pigeonChannelCodec,
|
||||
final BasicMessageChannel<
|
||||
Object?> pigeonVar_channel = BasicMessageChannel<
|
||||
Object?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
@@ -819,19 +1125,24 @@ abstract class UniversalBleCallbackChannel {
|
||||
assert(arg_value != null,
|
||||
'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null, expected non-null Uint8List.');
|
||||
try {
|
||||
api.onValueChanged(arg_deviceId!, arg_characteristicId!, arg_value!);
|
||||
api.onValueChanged(
|
||||
arg_deviceId!, arg_characteristicId!, arg_value!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: 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?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', pigeonChannelCodec,
|
||||
final BasicMessageChannel<
|
||||
Object?> pigeonVar_channel = BasicMessageChannel<
|
||||
Object?>(
|
||||
'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix',
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
@@ -853,7 +1164,8 @@ abstract class UniversalBleCallbackChannel {
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: 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/services.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/universal_ble.dart';
|
||||
@@ -18,7 +17,9 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
||||
|
||||
@override
|
||||
Future<AvailabilityState> getBluetoothAvailabilityState() async {
|
||||
int state = await _channel.getBluetoothAvailabilityState();
|
||||
int state = await _executeWithErrorHandling(
|
||||
() => _channel.getBluetoothAvailabilityState(),
|
||||
);
|
||||
return AvailabilityState.parse(state);
|
||||
}
|
||||
|
||||
@@ -27,7 +28,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
||||
if (!BleCapabilities.supportsBluetoothEnableApi) {
|
||||
throw UnsupportedError("Not supported");
|
||||
}
|
||||
return _channel.enableBluetooth();
|
||||
return _executeWithErrorHandling(() => _channel.enableBluetooth());
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -35,7 +36,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
||||
if (!BleCapabilities.supportsBluetoothEnableApi) {
|
||||
throw UnsupportedError("Not supported");
|
||||
}
|
||||
return _channel.disableBluetooth();
|
||||
return _executeWithErrorHandling(() => _channel.disableBluetooth());
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -45,31 +46,37 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
||||
}) async {
|
||||
await _ensureInitialized();
|
||||
_bleFilter.scanFilter = scanFilter;
|
||||
await _channel.startScan(
|
||||
await _executeWithErrorHandling(
|
||||
() => _channel.startScan(
|
||||
scanFilter.toUniversalScanFilter(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stopScan() => _channel.stopScan();
|
||||
Future<void> stopScan() =>
|
||||
_executeWithErrorHandling(() => _channel.stopScan());
|
||||
|
||||
@override
|
||||
Future<BleConnectionState> getConnectionState(String deviceId) async {
|
||||
int state = await _channel.getConnectionState(deviceId);
|
||||
int state = await _executeWithErrorHandling(
|
||||
() => _channel.getConnectionState(deviceId));
|
||||
return BleConnectionState.parse(state);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect(String deviceId, {Duration? connectionTimeout}) =>
|
||||
_channel.connect(deviceId);
|
||||
_executeWithErrorHandling(() => _channel.connect(deviceId));
|
||||
|
||||
@override
|
||||
Future<void> disconnect(String deviceId) => _channel.disconnect(deviceId);
|
||||
Future<void> disconnect(String deviceId) =>
|
||||
_executeWithErrorHandling(() => _channel.disconnect(deviceId));
|
||||
|
||||
@override
|
||||
Future<List<BleService>> discoverServices(String deviceId) async {
|
||||
List<UniversalBleService?> universalBleServices =
|
||||
await _channel.discoverServices(deviceId);
|
||||
await _executeWithErrorHandling(
|
||||
() => _channel.discoverServices(deviceId));
|
||||
return List<BleService>.from(universalBleServices
|
||||
.where((e) => e != null)
|
||||
.map((e) => e!.toBleService(deviceId))
|
||||
@@ -79,12 +86,12 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
||||
@override
|
||||
Future<void> setNotifiable(String deviceId, String service,
|
||||
String characteristic, BleInputProperty bleInputProperty) {
|
||||
return _channel.setNotifiable(
|
||||
return _executeWithErrorHandling(() => _channel.setNotifiable(
|
||||
deviceId,
|
||||
service,
|
||||
characteristic,
|
||||
bleInputProperty.index,
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -94,7 +101,8 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
||||
String characteristic, {
|
||||
final Duration? timeout,
|
||||
}) {
|
||||
return _channel.readValue(deviceId, service, characteristic);
|
||||
return _executeWithErrorHandling(
|
||||
() => _channel.readValue(deviceId, service, characteristic));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -104,33 +112,38 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
||||
String characteristic,
|
||||
Uint8List value,
|
||||
BleOutputProperty bleOutputProperty) {
|
||||
return _channel.writeValue(
|
||||
return _executeWithErrorHandling(() => _channel.writeValue(
|
||||
deviceId,
|
||||
service,
|
||||
characteristic,
|
||||
value,
|
||||
bleOutputProperty.index,
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> requestMtu(String deviceId, int expectedMtu) =>
|
||||
_channel.requestMtu(deviceId, expectedMtu);
|
||||
_executeWithErrorHandling(
|
||||
() => _channel.requestMtu(deviceId, expectedMtu));
|
||||
|
||||
@override
|
||||
Future<bool> isPaired(String deviceId) => _channel.isPaired(deviceId);
|
||||
Future<bool> isPaired(String deviceId) =>
|
||||
_executeWithErrorHandling(() => _channel.isPaired(deviceId));
|
||||
|
||||
@override
|
||||
Future<bool> pair(String deviceId) => _channel.pair(deviceId);
|
||||
Future<bool> pair(String deviceId) =>
|
||||
_executeWithErrorHandling(() => _channel.pair(deviceId));
|
||||
|
||||
@override
|
||||
Future<void> unpair(String deviceId) => _channel.unPair(deviceId);
|
||||
Future<void> unpair(String deviceId) =>
|
||||
_executeWithErrorHandling(() => _channel.unPair(deviceId));
|
||||
|
||||
@override
|
||||
Future<List<BleDevice>> getSystemDevices(
|
||||
List<String>? withServices,
|
||||
) async {
|
||||
var devices = await _channel.getSystemDevices(withServices ?? []);
|
||||
var devices = await _executeWithErrorHandling(
|
||||
() => _channel.getSystemDevices(withServices ?? []));
|
||||
return List<BleDevice>.from(
|
||||
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 {
|
||||
// Check bluetooth availability on Apple
|
||||
// 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();
|
||||
switch (state) {
|
||||
case AvailabilityState.unauthorized:
|
||||
throw PlatformException(
|
||||
code: "Unauthorized",
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.bluetoothUnauthorized,
|
||||
message: "Not authorized to access Bluetooth",
|
||||
);
|
||||
case AvailabilityState.unsupported:
|
||||
throw PlatformException(
|
||||
code: "Unsupported",
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notSupported,
|
||||
message: "Bluetooth is not supported",
|
||||
);
|
||||
default:
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:collection';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_web_bluetooth/flutter_web_bluetooth.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';
|
||||
|
||||
class UniversalBleWeb extends UniversalBlePlatform {
|
||||
@@ -35,7 +36,12 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
Duration? connectionTimeout = const Duration(seconds: 10),
|
||||
}) async {
|
||||
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);
|
||||
|
||||
// Subscribe to Connection Stream
|
||||
@@ -92,7 +98,7 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
} catch (e) {
|
||||
String error = e.toString().replaceAll("DeviceNotFoundError:", "").trim();
|
||||
if (error.toLowerCase().contains("api globally disabled")) {
|
||||
throw WebBluetoothGloballyDisabled(error);
|
||||
throw WebBluetoothGloballyDisabled(message: error);
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
@@ -154,7 +160,9 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
);
|
||||
|
||||
if (bleCharacteristic == null) {
|
||||
throw Exception(
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.characteristicNotFound,
|
||||
message:
|
||||
'Characteristic $characteristic for service $service not found',
|
||||
);
|
||||
}
|
||||
@@ -195,7 +203,9 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
);
|
||||
|
||||
if (bleCharacteristic == null) {
|
||||
throw Exception(
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.characteristicNotFound,
|
||||
message:
|
||||
'Characteristic $characteristic for service $service not found',
|
||||
);
|
||||
}
|
||||
@@ -221,8 +231,11 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
characteristicId: characteristic,
|
||||
);
|
||||
if (bleCharacteristic == null) {
|
||||
throw Exception(
|
||||
'Characteristic $characteristic for service $service not found');
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.characteristicNotFound,
|
||||
message:
|
||||
'Characteristic $characteristic for service $service not found',
|
||||
);
|
||||
}
|
||||
var data = timeout != null
|
||||
? bleCharacteristic.readValue(timeout: timeout)
|
||||
@@ -233,29 +246,44 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
/// `Unimplemented`
|
||||
@override
|
||||
Future<int> requestMtu(String deviceId, int expectedMtu) {
|
||||
throw UnimplementedError();
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notImplemented,
|
||||
message: "requestMtu is not implemented on Web platform",
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isPaired(String deviceId) {
|
||||
throw UnimplementedError();
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notImplemented,
|
||||
message: "isPaired is not implemented on Web platform",
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> pair(String deviceId) {
|
||||
throw UnimplementedError();
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notImplemented,
|
||||
message: "pair is not implemented on Web platform",
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> unpair(String deviceId) {
|
||||
throw UnimplementedError();
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notImplemented,
|
||||
message: "unpair is not implemented on Web platform",
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<BleDevice>> getSystemDevices(
|
||||
List<String>? withServices,
|
||||
) {
|
||||
throw UnimplementedError();
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notImplemented,
|
||||
message: "getSystemDevices is not implemented on Web platform",
|
||||
);
|
||||
}
|
||||
|
||||
/// Helpers
|
||||
@@ -335,12 +363,18 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
|
||||
@override
|
||||
Future<bool> enableBluetooth() {
|
||||
throw UnimplementedError();
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notImplemented,
|
||||
message: "enableBluetooth is not implemented on Web platform",
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> disableBluetooth() {
|
||||
throw UnimplementedError();
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.notImplemented,
|
||||
message: "disableBluetooth is not implemented on Web platform",
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -169,3 +169,87 @@ class UniversalManufacturerData {
|
||||
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
@@ -1,6 +1,6 @@
|
||||
name: universal_ble
|
||||
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
|
||||
repository: https://github.com/Navideck/universal_ble
|
||||
issue_tracker: https://github.com/Navideck/universal_ble/issues
|
||||
@@ -38,7 +38,7 @@ dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^6.0.0
|
||||
pigeon: ^22.4.0
|
||||
pigeon: ^26.0.5
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "helper/universal_enum.h"
|
||||
#include "helper/universal_ble_base.h"
|
||||
#include "generated/universal_ble.g.h"
|
||||
|
||||
namespace universal_ble
|
||||
{
|
||||
@@ -46,9 +50,9 @@ namespace universal_ble
|
||||
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::AlreadyPaired: return "AlreadyPaired";
|
||||
|
||||
@@ -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
|
||||
|
||||
#undef _HAS_EXCEPTIONS
|
||||
@@ -425,21 +425,26 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType(
|
||||
flutter::ByteStreamReader* stream) const {
|
||||
switch (type) {
|
||||
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: {
|
||||
return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
}
|
||||
case 131: {
|
||||
return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
}
|
||||
case 132: {
|
||||
return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
}
|
||||
case 133: {
|
||||
return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
}
|
||||
case 134: {
|
||||
return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
}
|
||||
case 135: {
|
||||
return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
|
||||
}
|
||||
default:
|
||||
@@ -451,33 +456,38 @@ void PigeonInternalCodecSerializer::WriteValue(
|
||||
const EncodableValue& value,
|
||||
flutter::ByteStreamWriter* stream) const {
|
||||
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);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
if (custom_value->type() == typeid(UniversalBleService)) {
|
||||
stream->WriteByte(130);
|
||||
stream->WriteByte(131);
|
||||
WriteValue(EncodableValue(std::any_cast<UniversalBleService>(*custom_value).ToEncodableList()), stream);
|
||||
return;
|
||||
}
|
||||
if (custom_value->type() == typeid(UniversalBleCharacteristic)) {
|
||||
stream->WriteByte(131);
|
||||
stream->WriteByte(132);
|
||||
WriteValue(EncodableValue(std::any_cast<UniversalBleCharacteristic>(*custom_value).ToEncodableList()), stream);
|
||||
return;
|
||||
}
|
||||
if (custom_value->type() == typeid(UniversalScanFilter)) {
|
||||
stream->WriteByte(132);
|
||||
stream->WriteByte(133);
|
||||
WriteValue(EncodableValue(std::any_cast<UniversalScanFilter>(*custom_value).ToEncodableList()), stream);
|
||||
return;
|
||||
}
|
||||
if (custom_value->type() == typeid(UniversalManufacturerDataFilter)) {
|
||||
stream->WriteByte(133);
|
||||
stream->WriteByte(134);
|
||||
WriteValue(EncodableValue(std::any_cast<UniversalManufacturerDataFilter>(*custom_value).ToEncodableList()), stream);
|
||||
return;
|
||||
}
|
||||
if (custom_value->type() == typeid(UniversalManufacturerData)) {
|
||||
stream->WriteByte(134);
|
||||
stream->WriteByte(135);
|
||||
WriteValue(EncodableValue(std::any_cast<UniversalManufacturerData>(*custom_value).ToEncodableList()), stream);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
#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.
|
||||
class UniversalBleScanResult {
|
||||
@@ -96,7 +161,6 @@ class UniversalBleScanResult {
|
||||
void set_services(const flutter::EncodableList* value_arg);
|
||||
void set_services(const flutter::EncodableList& value_arg);
|
||||
|
||||
|
||||
private:
|
||||
static UniversalBleScanResult FromEncodableList(const flutter::EncodableList& list);
|
||||
flutter::EncodableList ToEncodableList() const;
|
||||
@@ -109,7 +173,6 @@ class UniversalBleScanResult {
|
||||
std::optional<int64_t> rssi_;
|
||||
std::optional<flutter::EncodableList> manufacturer_data_list_;
|
||||
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);
|
||||
|
||||
|
||||
private:
|
||||
static UniversalBleService FromEncodableList(const flutter::EncodableList& list);
|
||||
flutter::EncodableList ToEncodableList() const;
|
||||
@@ -140,7 +202,6 @@ class UniversalBleService {
|
||||
friend class PigeonInternalCodecSerializer;
|
||||
std::string uuid_;
|
||||
std::optional<flutter::EncodableList> characteristics_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -158,7 +219,6 @@ class UniversalBleCharacteristic {
|
||||
const flutter::EncodableList& properties() const;
|
||||
void set_properties(const flutter::EncodableList& value_arg);
|
||||
|
||||
|
||||
private:
|
||||
static UniversalBleCharacteristic FromEncodableList(const flutter::EncodableList& list);
|
||||
flutter::EncodableList ToEncodableList() const;
|
||||
@@ -167,7 +227,6 @@ class UniversalBleCharacteristic {
|
||||
friend class PigeonInternalCodecSerializer;
|
||||
std::string uuid_;
|
||||
flutter::EncodableList properties_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -191,7 +250,6 @@ class UniversalScanFilter {
|
||||
const flutter::EncodableList& with_manufacturer_data() const;
|
||||
void set_with_manufacturer_data(const flutter::EncodableList& value_arg);
|
||||
|
||||
|
||||
private:
|
||||
static UniversalScanFilter FromEncodableList(const flutter::EncodableList& list);
|
||||
flutter::EncodableList ToEncodableList() const;
|
||||
@@ -201,7 +259,6 @@ class UniversalScanFilter {
|
||||
flutter::EncodableList with_services_;
|
||||
flutter::EncodableList with_name_prefix_;
|
||||
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);
|
||||
|
||||
|
||||
private:
|
||||
static UniversalManufacturerDataFilter FromEncodableList(const flutter::EncodableList& list);
|
||||
flutter::EncodableList ToEncodableList() const;
|
||||
@@ -238,7 +294,6 @@ class UniversalManufacturerDataFilter {
|
||||
int64_t company_identifier_;
|
||||
std::optional<std::vector<uint8_t>> data_;
|
||||
std::optional<std::vector<uint8_t>> mask_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -256,7 +311,6 @@ class UniversalManufacturerData {
|
||||
const std::vector<uint8_t>& data() const;
|
||||
void set_data(const std::vector<uint8_t>& value_arg);
|
||||
|
||||
|
||||
private:
|
||||
static UniversalManufacturerData FromEncodableList(const flutter::EncodableList& list);
|
||||
flutter::EncodableList ToEncodableList() const;
|
||||
@@ -265,7 +319,6 @@ class UniversalManufacturerData {
|
||||
friend class PigeonInternalCodecSerializer;
|
||||
int64_t company_identifier_;
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -280,12 +333,10 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer {
|
||||
void WriteValue(
|
||||
const flutter::EncodableValue& value,
|
||||
flutter::ByteStreamWriter* stream) const override;
|
||||
|
||||
protected:
|
||||
flutter::EncodableValue ReadValueOfType(
|
||||
uint8_t type,
|
||||
flutter::ByteStreamReader* stream) const override;
|
||||
|
||||
};
|
||||
|
||||
// Flutter -> Native
|
||||
@@ -352,10 +403,8 @@ class UniversalBlePlatformChannel {
|
||||
const std::string& message_channel_suffix);
|
||||
static flutter::EncodableValue WrapError(std::string_view error_message);
|
||||
static flutter::EncodableValue WrapError(const FlutterError& error);
|
||||
|
||||
protected:
|
||||
UniversalBlePlatformChannel() = default;
|
||||
|
||||
};
|
||||
// Native -> Flutter
|
||||
//
|
||||
@@ -393,7 +442,6 @@ class UniversalBleCallbackChannel {
|
||||
const std::string* error,
|
||||
std::function<void(void)>&& on_success,
|
||||
std::function<void(const FlutterError&)>&& on_error);
|
||||
|
||||
private:
|
||||
flutter::BinaryMessenger* binary_messenger_;
|
||||
std::string message_channel_suffix_;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "Utils.h"
|
||||
#include "utils.h"
|
||||
#include "../generated/universal_ble.g.h"
|
||||
#include "../enum_parser.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <sdkddkver.h>
|
||||
@@ -158,4 +161,142 @@ namespace universal_ble
|
||||
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
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/Windows.Storage.Streams.h"
|
||||
#include "winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h"
|
||||
#include "winrt/base.h"
|
||||
#include "universal_ble_base.h"
|
||||
#include "../generated/universal_ble.g.h"
|
||||
|
||||
constexpr uint32_t TEN_SECONDS_IN_MSECS = 10000;
|
||||
|
||||
@@ -28,6 +30,40 @@ namespace universal_ble
|
||||
bool is_little_endian();
|
||||
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
|
||||
template <typename AsyncT>
|
||||
static auto async_get(AsyncT const &async)
|
||||
@@ -42,11 +78,11 @@ namespace universal_ble
|
||||
}
|
||||
catch (const hresult_error &err)
|
||||
{
|
||||
throw FlutterError("Failed", to_string(err.message()));
|
||||
throw create_flutter_error(UniversalBleErrorCode::kFailed, to_string(err.message()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw FlutterError("Failed", "Unknown error");
|
||||
throw create_flutter_unknown_error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -61,11 +61,11 @@ namespace universal_ble
|
||||
{
|
||||
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)
|
||||
{
|
||||
throw FlutterError("IllegalArgument", "Characteristic not found");
|
||||
throw create_flutter_error(UniversalBleErrorCode::kCharacteristicNotFound, "Characteristic not found");
|
||||
}
|
||||
return gatt_map[service_uuid].characteristics.at(characteristic_uuid);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user