From ac98427893d1cf328ecdf95e4f075c75a66d197a Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 15:26:15 +0100 Subject: [PATCH 01/23] Add peripheral mode support --- CHANGELOG.md | 6 +- README.md | 81 +- .../universal_ble/UniversalBlePeripheral.g.kt | 737 +++++++++++ .../UniversalBlePeripheralExtensions.kt | 143 +++ .../UniversalBlePeripheralPlugin.kt | 446 +++++++ .../universal_ble/UniversalBlePlugin.kt | 11 + build_pigeon.sh | 2 + .../UniversalBlePeripheral.g.swift | 747 +++++++++++ .../UniversalBlePeripheralExtensions.swift | 126 ++ .../UniversalBlePeripheralPlugin.swift | 203 +++ .../universal_ble/UniversalBlePlugin.swift | 6 + example/ios/Podfile.lock | 36 + example/ios/Runner.xcodeproj/project.pbxproj | 121 +- example/lib/home/home.dart | 43 +- example/lib/main.dart | 33 +- example/lib/peripheral/peripheral_home.dart | 188 +++ .../Flutter/GeneratedPluginRegistrant.swift | 2 + example/macos/Podfile.lock | 30 + lib/src/models/model_exports.dart | 1 + .../peripheral/attribute_permissions.dart | 6 + .../models/peripheral/peripheral_exports.dart | 2 + .../peripheral/peripheral_request_result.dart | 25 + .../generated/universal_ble_peripheral.g.dart | 914 ++++++++++++++ .../universal_ble_peripheral.dart | 104 ++ .../universal_ble_peripheral_mapper.dart | 53 + .../universal_ble_peripheral_pigeon.dart | 198 +++ ...sal_ble_peripheral_platform_interface.dart | 144 +++ lib/universal_ble.dart | 2 + lib/universal_ble_peripheral.dart | 5 + pigeon/universal_ble_peripheral.dart | 123 ++ pubspec.yaml | 2 +- test/universal_ble_peripheral_test.dart | 40 + windows/CMakeLists.txt | 2 + .../generated/universal_ble_peripheral.g.cpp | 1093 +++++++++++++++++ .../generated/universal_ble_peripheral.g.h | 397 ++++++ windows/src/universal_ble_plugin.cpp | 632 +++++++++- windows/src/universal_ble_plugin.h | 79 +- 37 files changed, 6738 insertions(+), 45 deletions(-) create mode 100644 android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt create mode 100644 android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt create mode 100644 android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt create mode 100644 darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift create mode 100644 darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift create mode 100644 darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift create mode 100644 example/ios/Podfile.lock create mode 100644 example/lib/peripheral/peripheral_home.dart create mode 100644 example/macos/Podfile.lock create mode 100644 lib/src/models/peripheral/attribute_permissions.dart create mode 100644 lib/src/models/peripheral/peripheral_exports.dart create mode 100644 lib/src/models/peripheral/peripheral_request_result.dart create mode 100644 lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart create mode 100644 lib/src/universal_ble_peripheral/universal_ble_peripheral.dart create mode 100644 lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart create mode 100644 lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart create mode 100644 lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart create mode 100644 lib/universal_ble_peripheral.dart create mode 100644 pigeon/universal_ble_peripheral.dart create mode 100644 test/universal_ble_peripheral_test.dart create mode 100644 windows/src/generated/universal_ble_peripheral.g.cpp create mode 100644 windows/src/generated/universal_ble_peripheral.g.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 14aff2f8..0eab3694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -## 1.3.0 +## 2.0.0 +* Add first-party `UniversalBlePeripheral` API to integrate peripheral mode directly in `universal_ble` +* Add peripheral pigeon channels and platform hooks for Android/iOS/macOS/Windows +* Reuse shared `universal_ble` models for peripheral workflows where applicable +* Merge central and peripheral demos into a single tabbed example app * Add `requestConnectionPriority` to allow tuning BLE connection intervals on Android * Add SPM support on Apple diff --git a/README.md b/README.md index 73ea2124..6667dc30 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,12 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE - [Error Handling](#error-handling) - [UUID Format Agnostic](#uuid-format-agnostic) - [Permissions](#permissions) +- [Peripheral Mode](#peripheral-mode) ## API Support +### Client Mode (`UniversalBle`) + | | Android | iOS | macOS | Windows | Linux | Web | | :---------------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | | startScan/stopScan | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | @@ -58,6 +61,24 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | readRssi | ✔️ | ✔️ | ✔️ | ❌ | 🚧 | ❌ | | requestPermissions | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | +### Peripheral Mode (`UniversalBlePeripheral`) + +| API | Android | iOS | macOS | Windows | Linux | Web | +| :--------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | +| initialize | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| isSupported | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| isAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| addService | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| removeService | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| clearServices | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| getServices | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| startAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| stopAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| updateCharacteristic | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| peripheral callbacks\* | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | + +\* callbacks include advertising state, read/write requests, subscription changes, and related peripheral events. + ## Getting Started Add universal_ble in your pubspec.yaml: @@ -440,7 +461,7 @@ explicitly controlled by applications: * **Android ≤ 13**: Apps may request MTU once per connection (up to 517). If never requested, the default MTU is 23. - * **Android 14+**: The first GATT client effectively drives MTU negotiation + * **Android 14+**: The first Bluetooth client effectively drives MTU negotiation to 517 (or the link’s maximum); subsequent MTU requests are ignored. * **Windows** @@ -451,7 +472,7 @@ explicitly controlled by applications: * **Linux (BlueZ)** * MTU is negotiated automatically by default. - * The standard D-Bus GATT API does not expose MTU control. + * The standard D-Bus Bluetooth API does not expose MTU control. * MTU can be requested via BlueZ tools or lower-level APIs, but most apps treat it as stack-defined. @@ -606,6 +627,39 @@ try { 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. +## Peripheral Mode + +`universal_ble` provides peripheral mode through `UniversalBlePeripheral`, so your app can advertise as a peripheral "server" in addition to client mode. + +### Basic setup + +```dart +import 'package:universal_ble/universal_ble.dart'; + +await UniversalBlePeripheral.initialize(); +await UniversalBlePeripheral.addService( + BleService("0000180F-0000-1000-8000-00805F9B34FB", [ + BleCharacteristic( + "00002A19-0000-1000-8000-00805F9B34FB", + [CharacteristicProperty.read, CharacteristicProperty.notify], + [], + ), + ]), + primary: true, +); + +await UniversalBlePeripheral.startAdvertising( + services: ["0000180F-0000-1000-8000-00805F9B34FB"], + localName: "UniversalBlePeripheral", +); +``` + +### Platform notes + +- Linux/Web currently return unsupported for peripheral mode. +- Windows peripheral advertising does not expose all advertising payload customization options from Android/Apple stacks. +- iOS/macOS setup (including required `Info.plist` keys for peripheral usage) is documented in [Permissions → iOS / macOS](#ios--macos). + ## 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. @@ -692,7 +746,21 @@ await UniversalBle.startScan(); ### iOS / macOS -Add `NSBluetoothPeripheralUsageDescription` and `NSBluetoothAlwaysUsageDescription` to Info.plist of your iOS and macOS app. +For Bluetooth usage (including peripheral mode), add both keys to your app's `Info.plist`: + +- `NSBluetoothAlwaysUsageDescription`: message shown when the app requests Bluetooth access. +- `NSBluetoothPeripheralUsageDescription`: message used for peripheral role access on Apple platforms. + +Example: + +```xml +NSBluetoothAlwaysUsageDescription +This app uses Bluetooth to scan, connect, and advertise to nearby devices. +NSBluetoothPeripheralUsageDescription +This app uses Bluetooth to advertise services to nearby devices. +``` + +Use clear, user-facing text that explains why Bluetooth is needed in your app. Add the `Bluetooth` capability to the macOS app from Xcode. @@ -865,7 +933,12 @@ Future resetBleState() async { ## Example app -This repo includes an [example app](example/) you can run to try the API. For a full-blown app, check [Universal-BLE](https://github.com/Navideck/Universal-BLE). +This repo includes an [example app](example/) with two tabs: + +- `Client`: scanning and device communication workflows. +- `Peripheral`: peripheral server and advertising workflows. + +For a full-blown app, check [Universal-BLE](https://github.com/Navideck/Universal-BLE). ## Low level API diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt new file mode 100644 index 00000000..fd536512 --- /dev/null +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt @@ -0,0 +1,737 @@ +// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") + +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 UniversalBlePeripheralPigeonUtils { + + fun createConnectionError(channelName: String): PeripheralFlutterError { + return PeripheralFlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") } + + fun wrapResult(result: Any?): List { + return listOf(result) + } + + fun wrapError(exception: Throwable): List { + return if (exception is PeripheralFlutterError) { + listOf( + exception.code, + exception.message, + exception.details + ) + } else { + listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a is ByteArray && b is ByteArray) { + return a.contentEquals(b) + } + if (a is IntArray && b is IntArray) { + return a.contentEquals(b) + } + if (a is LongArray && b is LongArray) { + return a.contentEquals(b) + } + if (a is DoubleArray && b is DoubleArray) { + return a.contentEquals(b) + } + if (a is Array<*> && b is Array<*>) { + return a.size == b.size && + a.indices.all{ deepEquals(a[it], b[it]) } + } + if (a is List<*> && b is List<*>) { + return a.size == b.size && + a.indices.all{ deepEquals(a[it], b[it]) } + } + if (a is Map<*, *> && b is Map<*, *>) { + return a.size == b.size && a.all { + (b as Map).contains(it.key) && + deepEquals(it.value, b[it.key]) + } + } + return a == b + } + +} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class PeripheralFlutterError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() + +enum class PeripheralBondState(val raw: Int) { + BONDING(0), + BONDED(1), + NONE(2); + + companion object { + fun ofRaw(raw: Int): PeripheralBondState? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralService ( + val uuid: String, + val primary: Boolean, + val characteristics: List +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralService { + val uuid = pigeonVar_list[0] as String + val primary = pigeonVar_list[1] as Boolean + val characteristics = pigeonVar_list[2] as List + return PeripheralService(uuid, primary, characteristics) + } + } + fun toList(): List { + return listOf( + uuid, + primary, + characteristics, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is PeripheralService) { + return false + } + if (this === other) { + return true + } + return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralCharacteristic ( + val uuid: String, + val properties: List, + val permissions: List, + val descriptors: List? = null, + val value: ByteArray? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralCharacteristic { + val uuid = pigeonVar_list[0] as String + val properties = pigeonVar_list[1] as List + val permissions = pigeonVar_list[2] as List + val descriptors = pigeonVar_list[3] as List? + val value = pigeonVar_list[4] as ByteArray? + return PeripheralCharacteristic(uuid, properties, permissions, descriptors, value) + } + } + fun toList(): List { + return listOf( + uuid, + properties, + permissions, + descriptors, + value, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is PeripheralCharacteristic) { + return false + } + if (this === other) { + return true + } + return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralDescriptor ( + val uuid: String, + val value: ByteArray? = null, + val permissions: List? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralDescriptor { + val uuid = pigeonVar_list[0] as String + val value = pigeonVar_list[1] as ByteArray? + val permissions = pigeonVar_list[2] as List? + return PeripheralDescriptor(uuid, value, permissions) + } + } + fun toList(): List { + return listOf( + uuid, + value, + permissions, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is PeripheralDescriptor) { + return false + } + if (this === other) { + return true + } + return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralReadRequestResult ( + val value: ByteArray, + val offset: Long? = null, + val status: Long? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralReadRequestResult { + val value = pigeonVar_list[0] as ByteArray + val offset = pigeonVar_list[1] as Long? + val status = pigeonVar_list[2] as Long? + return PeripheralReadRequestResult(value, offset, status) + } + } + fun toList(): List { + return listOf( + value, + offset, + status, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is PeripheralReadRequestResult) { + return false + } + if (this === other) { + return true + } + return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralWriteRequestResult ( + val value: ByteArray? = null, + val offset: Long? = null, + val status: Long? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralWriteRequestResult { + val value = pigeonVar_list[0] as ByteArray? + val offset = pigeonVar_list[1] as Long? + val status = pigeonVar_list[2] as Long? + return PeripheralWriteRequestResult(value, offset, status) + } + } + fun toList(): List { + return listOf( + value, + offset, + status, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is PeripheralWriteRequestResult) { + return false + } + if (this === other) { + return true + } + return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralManufacturerData ( + val manufacturerId: Long, + val data: ByteArray +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralManufacturerData { + val manufacturerId = pigeonVar_list[0] as Long + val data = pigeonVar_list[1] as ByteArray + return PeripheralManufacturerData(manufacturerId, data) + } + } + fun toList(): List { + return listOf( + manufacturerId, + data, + ) + } + override fun equals(other: Any?): Boolean { + if (other !is PeripheralManufacturerData) { + return false + } + if (this === other) { + return true + } + return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + + override fun hashCode(): Int = toList().hashCode() +} +private open class UniversalBlePeripheralPigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 129.toByte() -> { + return (readValue(buffer) as Long?)?.let { + PeripheralBondState.ofRaw(it.toInt()) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralService.fromList(it) + } + } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralCharacteristic.fromList(it) + } + } + 132.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralDescriptor.fromList(it) + } + } + 133.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralReadRequestResult.fromList(it) + } + } + 134.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralWriteRequestResult.fromList(it) + } + } + 135.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralManufacturerData.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is PeripheralBondState -> { + stream.write(129) + writeValue(stream, value.raw.toLong()) + } + is PeripheralService -> { + stream.write(130) + writeValue(stream, value.toList()) + } + is PeripheralCharacteristic -> { + stream.write(131) + writeValue(stream, value.toList()) + } + is PeripheralDescriptor -> { + stream.write(132) + writeValue(stream, value.toList()) + } + is PeripheralReadRequestResult -> { + stream.write(133) + writeValue(stream, value.toList()) + } + is PeripheralWriteRequestResult -> { + stream.write(134) + writeValue(stream, value.toList()) + } + is PeripheralManufacturerData -> { + stream.write(135) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface UniversalBlePeripheralChannel { + fun initialize() + fun isAdvertising(): Boolean? + fun isSupported(): Boolean + fun stopAdvertising() + fun addService(service: PeripheralService) + fun removeService(serviceId: String) + fun clearServices() + fun getServices(): List + fun startAdvertising(services: List, localName: String?, timeout: Long?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Boolean) + fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) + + companion object { + /** The codec used by UniversalBlePeripheralChannel. */ + val codec: MessageCodec by lazy { + UniversalBlePeripheralPigeonCodec() + } + /** Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.initialize() + listOf(null) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.isAdvertising()) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.isSupported()) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.stopAdvertising() + listOf(null) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val serviceArg = args[0] as PeripheralService + val wrapped: List = try { + api.addService(serviceArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val serviceIdArg = args[0] as String + val wrapped: List = try { + api.removeService(serviceIdArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.clearServices() + listOf(null) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.getServices()) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val servicesArg = args[0] as List + val localNameArg = args[1] as String? + val timeoutArg = args[2] as Long? + val manufacturerDataArg = args[3] as PeripheralManufacturerData? + val addManufacturerDataInScanResponseArg = args[4] as Boolean + val wrapped: List = try { + api.startAdvertising(servicesArg, localNameArg, timeoutArg, manufacturerDataArg, addManufacturerDataInScanResponseArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val characteristicIdArg = args[0] as String + val valueArg = args[1] as ByteArray + val deviceIdArg = args[2] as String? + val wrapped: List = try { + api.updateCharacteristic(characteristicIdArg, valueArg, deviceIdArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by UniversalBlePeripheralCallback. */ + val codec: MessageCodec by lazy { + UniversalBlePeripheralPigeonCodec() + } + } + fun onReadRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + val output = it[0] as PeripheralReadRequestResult? + callback(Result.success(output)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onWriteRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + val output = it[0] as PeripheralWriteRequestResult? + callback(Result.success(output)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onCharacteristicSubscriptionChange(deviceIdArg: String, characteristicIdArg: String, isSubscribedArg: Boolean, nameArg: String?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onAdvertisingStatusUpdate(advertisingArg: Boolean, errorArg: String?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(advertisingArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onBleStateChange(stateArg: Boolean, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(stateArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onServiceAdded(serviceIdArg: String, errorArg: String?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(serviceIdArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onMtuChange(deviceIdArg: String, mtuArg: Long, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, mtuArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onConnectionStateChange(deviceIdArg: String, connectedArg: Boolean, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, connectedArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } + fun onBondStateChange(deviceIdArg: String, bondStateArg: PeripheralBondState, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, bondStateArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) + } + } + } +} diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt new file mode 100644 index 00000000..25b9f423 --- /dev/null +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt @@ -0,0 +1,143 @@ +package com.navideck.universal_ble + +import android.app.Activity +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothGattService +import android.content.pm.PackageManager +import android.util.Log +import java.util.Collections +import java.util.UUID + +private val bluetoothGattCharacteristics: + MutableMap = HashMap() +private val descriptorValueReadMap: MutableMap = HashMap() +val subscribedCharDevicesMap: MutableMap> = HashMap() +const val peripheralDescriptorCCUUID = "00002902-0000-1000-8000-00805f9b34fb" + +fun Activity.havePermission(permissions: Array): Boolean { + for (perm in permissions) { + if (checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { + return false + } + } + return true +} + +fun PeripheralService.toGattService(): BluetoothGattService { + val service = BluetoothGattService( + UUID.fromString(uuid), + if (primary) BluetoothGattService.SERVICE_TYPE_PRIMARY else BluetoothGattService.SERVICE_TYPE_SECONDARY, + ) + characteristics.forEach { + service.addCharacteristic(it.toGattCharacteristic()) + } + return service +} + +fun PeripheralCharacteristic.toGattCharacteristic(): BluetoothGattCharacteristic { + val characteristic = BluetoothGattCharacteristic( + UUID.fromString(uuid), + properties.toPropertiesList(), + permissions.toPermissionsList(), + ) + value?.let { characteristic.value = it } + descriptors?.forEach { + characteristic.addDescriptor(it.toGattDescriptor()) + } + + addCCDescriptorIfRequired(this, characteristic) + if (bluetoothGattCharacteristics[uuid] == null) { + bluetoothGattCharacteristics[uuid] = characteristic + } + return characteristic +} + +private fun addCCDescriptorIfRequired( + peripheralCharacteristic: PeripheralCharacteristic, + characteristic: BluetoothGattCharacteristic, +) { + val hasNotifyOrIndicate = + characteristic.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0 || + characteristic.properties and BluetoothGattCharacteristic.PROPERTY_INDICATE != 0 + if (!hasNotifyOrIndicate) return + + var hasCccd = false + for (descriptor in peripheralCharacteristic.descriptors ?: Collections.emptyList()) { + if (descriptor.uuid.equals(peripheralDescriptorCCUUID, ignoreCase = true)) { + hasCccd = true + break + } + } + if (hasCccd) return + + val cccd = BluetoothGattDescriptor( + UUID.fromString(peripheralDescriptorCCUUID), + BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE, + ) + cccd.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + characteristic.addDescriptor(cccd) + Log.d("UniversalBlePeripheral", "Added CCCD for ${characteristic.uuid}") +} + +fun PeripheralDescriptor.toGattDescriptor(): BluetoothGattDescriptor { + val permission = permissions?.toPermissionsList() + ?: BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE + val descriptor = BluetoothGattDescriptor(UUID.fromString(uuid), permission) + value?.let { + descriptor.value = it + descriptorValueReadMap[uuid.lowercase()] = it + } + return descriptor +} + +fun BluetoothGattDescriptor.getCacheValue(): ByteArray? = + descriptorValueReadMap[uuid.toString().lowercase()] + +fun String.findCharacteristic(): BluetoothGattCharacteristic? = + bluetoothGattCharacteristics[this] + +fun String.findService(): BluetoothGattService? { + for (characteristic in bluetoothGattCharacteristics.values) { + if (characteristic.service?.uuid.toString() == this) { + return characteristic.service + } + } + return null +} + +private fun List.toPropertiesList(): Int = + map { it.toInt() }.fold(0) { acc, i -> acc or i.toPropertyBits() } + +private fun List.toPermissionsList(): Int = + map { it.toInt() }.fold(0) { acc, i -> acc or i.toPermissionBits() } + +private fun Int.toPropertyBits(): Int = when (this) { + 0 -> BluetoothGattCharacteristic.PROPERTY_BROADCAST + 1 -> BluetoothGattCharacteristic.PROPERTY_READ + 2 -> BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE + 3 -> BluetoothGattCharacteristic.PROPERTY_WRITE + 4 -> BluetoothGattCharacteristic.PROPERTY_NOTIFY + 5 -> BluetoothGattCharacteristic.PROPERTY_INDICATE + 6 -> BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE + 7 -> BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS + 8 -> BluetoothGattCharacteristic.PROPERTY_NOTIFY + 9 -> BluetoothGattCharacteristic.PROPERTY_INDICATE + else -> 0 +} + +private fun Int.toPermissionBits(): Int = when (this) { + 0 -> BluetoothGattCharacteristic.PERMISSION_READ + 1 -> BluetoothGattCharacteristic.PERMISSION_WRITE + 2 -> BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED + 3 -> BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED + else -> 0 +} + +fun Int.toPeripheralBondState(): PeripheralBondState = when (this) { + BluetoothDevice.BOND_BONDING -> PeripheralBondState.BONDING + BluetoothDevice.BOND_BONDED -> PeripheralBondState.BONDED + BluetoothDevice.BOND_NONE -> PeripheralBondState.NONE + else -> PeripheralBondState.NONE +} diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt new file mode 100644 index 00000000..26ad4052 --- /dev/null +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -0,0 +1,446 @@ +package com.navideck.universal_ble + +import android.annotation.SuppressLint +import android.app.Activity +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothGattServer +import android.bluetooth.BluetoothGattServerCallback +import android.bluetooth.BluetoothGattService +import android.bluetooth.BluetoothManager +import android.bluetooth.BluetoothProfile +import android.bluetooth.le.AdvertiseCallback +import android.bluetooth.le.AdvertiseData +import android.bluetooth.le.AdvertiseSettings +import android.bluetooth.le.BluetoothLeAdvertiser +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Context.RECEIVER_EXPORTED +import android.content.Intent +import android.content.IntentFilter +import android.os.Build +import android.os.Handler +import android.os.ParcelUuid +import android.util.Log +import io.flutter.plugin.common.BinaryMessenger + +private const val TAG = "UniversalBlePeripheral" + +@SuppressLint("MissingPermission") +class UniversalBlePeripheralPlugin( + private val applicationContext: Context, + messenger: BinaryMessenger, +) : UniversalBlePeripheralChannel { + private var activity: Activity? = null + private val callback = UniversalBlePeripheralCallback(messenger) + private val handler = Handler(applicationContext.mainLooper) + private val bluetoothManager = + applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager + private var bluetoothLeAdvertiser: BluetoothLeAdvertiser? = null + private var gattServer: BluetoothGattServer? = null + private val bluetoothDevicesMap: MutableMap = HashMap() + private val listOfDevicesWaitingForBond = mutableListOf() + private val emptyBytes = byteArrayOf() + private var advertising: Boolean? = null + private var receiverRegistered = false + + fun attachActivity(activity: Activity?) { + this.activity = activity + } + + fun dispose() { + if (receiverRegistered) { + kotlin.runCatching { applicationContext.unregisterReceiver(broadcastReceiver) } + receiverRegistered = false + } + kotlin.runCatching { bluetoothLeAdvertiser?.stopAdvertising(advertiseCallback) } + gattServer?.close() + gattServer = null + bluetoothDevicesMap.clear() + } + + override fun initialize() { + val adapter = bluetoothManager.adapter + ?: throw UnsupportedOperationException("Bluetooth is not available.") + bluetoothLeAdvertiser = adapter.bluetoothLeAdvertiser + ?: throw UnsupportedOperationException( + "Bluetooth LE Advertising not supported on this device.", + ) + gattServer = bluetoothManager.openGattServer(applicationContext, gattServerCallback) + ?: throw UnsupportedOperationException("gattServer is null, check Bluetooth is ON.") + + if (!receiverRegistered) { + val intentFilter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) + intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + applicationContext.registerReceiver(broadcastReceiver, intentFilter, RECEIVER_EXPORTED) + } else { + @Suppress("DEPRECATION") + applicationContext.registerReceiver(broadcastReceiver, intentFilter) + } + receiverRegistered = true + } + + callback.onBleStateChange(isBluetoothEnabled()) {} + } + + override fun isAdvertising(): Boolean? = advertising + + override fun isSupported(): Boolean { + val adapter = bluetoothManager.adapter ?: return false + if (!adapter.isMultipleAdvertisementSupported) { + throw UnsupportedOperationException( + "Bluetooth LE Advertising not supported on this device.", + ) + } + return true + } + + override fun addService(service: PeripheralService) { + gattServer?.addService(service.toGattService()) + } + + override fun removeService(serviceId: String) { + serviceId.findService()?.let { gattServer?.removeService(it) } + } + + override fun clearServices() { + gattServer?.clearServices() + } + + override fun getServices(): List = + gattServer?.services?.map { it.uuid.toString() } ?: emptyList() + + override fun startAdvertising( + services: List, + localName: String?, + timeout: Long?, + manufacturerData: PeripheralManufacturerData?, + addManufacturerDataInScanResponse: Boolean, + ) { + if (!isBluetoothEnabled()) { + activity?.startActivityForResult( + Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), + 0xB1E, + ) + throw Exception("Bluetooth is not enabled") + } + + handler.post { + localName?.let { bluetoothManager.adapter?.name = it } + val advertiseSettings = AdvertiseSettings.Builder() + .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) + .setConnectable(true) + .setTimeout(timeout?.toInt() ?: 0) + .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) + .build() + + val advertiseDataBuilder = AdvertiseData.Builder() + .setIncludeTxPowerLevel(false) + .setIncludeDeviceName(localName != null) + val scanResponseBuilder = AdvertiseData.Builder() + .setIncludeTxPowerLevel(false) + .setIncludeDeviceName(localName != null) + + manufacturerData?.let { + if (addManufacturerDataInScanResponse) { + scanResponseBuilder.addManufacturerData( + it.manufacturerId.toInt(), + it.data, + ) + } else { + advertiseDataBuilder.addManufacturerData( + it.manufacturerId.toInt(), + it.data, + ) + } + } + services.forEach { advertiseDataBuilder.addServiceUuid(ParcelUuid.fromString(it)) } + + bluetoothLeAdvertiser?.startAdvertising( + advertiseSettings, + advertiseDataBuilder.build(), + scanResponseBuilder.build(), + advertiseCallback, + ) + } + } + + override fun stopAdvertising() { + handler.post { + bluetoothLeAdvertiser?.stopAdvertising(advertiseCallback) + advertising = false + callback.onAdvertisingStatusUpdate(false, null) {} + } + } + + override fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) { + val characteristic = + characteristicId.findCharacteristic() ?: throw Exception("Characteristic not found") + characteristic.value = value + if (deviceId != null) { + val device = bluetoothDevicesMap[deviceId] ?: throw Exception("Device not found") + handler.post { gattServer?.notifyCharacteristicChanged(device, characteristic, true) } + } else { + bluetoothDevicesMap.values.forEach { device -> + handler.post { gattServer?.notifyCharacteristicChanged(device, characteristic, true) } + } + } + } + + private fun isBluetoothEnabled(): Boolean = + bluetoothManager.adapter?.isEnabled ?: false + + private fun onConnectionUpdate(device: BluetoothDevice, status: Int, newState: Int) { + Log.e(TAG, "onConnectionStateChange: $status -> $newState") + handler.post { + callback.onConnectionStateChange( + device.address, + newState == BluetoothProfile.STATE_CONNECTED, + ) {} + } + if (newState == BluetoothProfile.STATE_DISCONNECTED) cleanConnection(device) + } + + private fun cleanConnection(device: BluetoothDevice) { + val deviceAddress = device.address + val subscribedCharUUID = subscribedCharDevicesMap[deviceAddress] ?: mutableListOf() + subscribedCharUUID.forEach { charUUID -> + handler.post { + callback.onCharacteristicSubscriptionChange( + deviceAddress, + charUUID, + false, + device.name, + ) {} + } + } + subscribedCharDevicesMap.remove(deviceAddress) + } + + private val advertiseCallback = object : AdvertiseCallback() { + override fun onStartFailure(errorCode: Int) { + super.onStartFailure(errorCode) + handler.post { + val errorMessage = when (errorCode) { + ADVERTISE_FAILED_ALREADY_STARTED -> "Already started" + ADVERTISE_FAILED_DATA_TOO_LARGE -> "Data too large" + ADVERTISE_FAILED_FEATURE_UNSUPPORTED -> "Feature unsupported" + ADVERTISE_FAILED_INTERNAL_ERROR -> "Internal error" + ADVERTISE_FAILED_TOO_MANY_ADVERTISERS -> "Too many advertisers" + else -> "Failed to start advertising: $errorCode" + } + callback.onAdvertisingStatusUpdate(false, errorMessage) {} + } + } + + override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) { + super.onStartSuccess(settingsInEffect) + advertising = true + handler.post { callback.onAdvertisingStatusUpdate(true, null) {} } + } + } + + private val gattServerCallback = object : BluetoothGattServerCallback() { + override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) { + super.onConnectionStateChange(device, status, newState) + when (newState) { + BluetoothProfile.STATE_CONNECTED -> { + if (device.bondState == BluetoothDevice.BOND_NONE) { + listOfDevicesWaitingForBond.add(device.address) + device.createBond() + } else if (device.bondState == BluetoothDevice.BOND_BONDED) { + handler.post { gattServer?.connect(device, true) } + synchronized(bluetoothDevicesMap) { + bluetoothDevicesMap[device.address] = device + } + } + onConnectionUpdate(device, status, newState) + } + BluetoothProfile.STATE_DISCONNECTED -> { + synchronized(bluetoothDevicesMap) { + bluetoothDevicesMap.remove(device.address) + } + onConnectionUpdate(device, status, newState) + } + } + } + + override fun onMtuChanged(device: BluetoothDevice?, mtu: Int) { + super.onMtuChanged(device, mtu) + device?.address?.let { address -> + handler.post { callback.onMtuChange(address, mtu.toLong()) {} } + } + } + + override fun onCharacteristicReadRequest( + device: BluetoothDevice, + requestId: Int, + offset: Int, + characteristic: BluetoothGattCharacteristic, + ) { + super.onCharacteristicReadRequest(device, requestId, offset, characteristic) + if (gattServer == null) return + handler.post { + callback.onReadRequest( + deviceIdArg = device.address, + characteristicIdArg = characteristic.uuid.toString(), + offsetArg = offset.toLong(), + valueArg = characteristic.value, + ) { result -> + val readResult = result.getOrNull() + if (readResult == null) { + gattServer?.sendResponse( + device, requestId, BluetoothGatt.GATT_FAILURE, 0, emptyBytes, + ) + } else { + gattServer?.sendResponse( + device, + requestId, + readResult.status?.toInt() ?: BluetoothGatt.GATT_SUCCESS, + readResult.offset?.toInt() ?: 0, + readResult.value, + ) + } + } + } + } + + override fun onCharacteristicWriteRequest( + device: BluetoothDevice, + requestId: Int, + characteristic: BluetoothGattCharacteristic, + preparedWrite: Boolean, + responseNeeded: Boolean, + offset: Int, + value: ByteArray, + ) { + super.onCharacteristicWriteRequest( + device, requestId, characteristic, preparedWrite, responseNeeded, offset, value, + ) + handler.post { + callback.onWriteRequest( + deviceIdArg = device.address, + characteristicIdArg = characteristic.uuid.toString(), + offsetArg = offset.toLong(), + valueArg = value, + ) { writeResponse -> + val writeResult = writeResponse.getOrNull() + gattServer?.sendResponse( + device, + requestId, + writeResult?.status?.toInt() ?: BluetoothGatt.GATT_SUCCESS, + writeResult?.offset?.toInt() ?: 0, + writeResult?.value ?: emptyBytes, + ) + } + } + } + + override fun onServiceAdded(status: Int, service: BluetoothGattService) { + super.onServiceAdded(status, service) + val error = if (status != BluetoothGatt.GATT_SUCCESS) "Adding Service failed" else null + handler.post { callback.onServiceAdded(service.uuid.toString(), error) {} } + } + + override fun onDescriptorReadRequest( + device: BluetoothDevice, + requestId: Int, + offset: Int, + descriptor: BluetoothGattDescriptor, + ) { + super.onDescriptorReadRequest(device, requestId, offset, descriptor) + handler.post { + val value = descriptor.getCacheValue() + if (value != null) { + gattServer?.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value) + } else { + gattServer?.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, emptyBytes) + } + } + } + + override fun onDescriptorWriteRequest( + device: BluetoothDevice?, + requestId: Int, + descriptor: BluetoothGattDescriptor, + preparedWrite: Boolean, + responseNeeded: Boolean, + offset: Int, + value: ByteArray?, + ) { + super.onDescriptorWriteRequest( + device, requestId, descriptor, preparedWrite, responseNeeded, offset, value, + ) + descriptor.value = value + if (descriptor.uuid.toString().lowercase() == peripheralDescriptorCCUUID.lowercase()) { + val isSubscribed = + BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE.contentEquals(value) || + BluetoothGattDescriptor.ENABLE_INDICATION_VALUE.contentEquals(value) + val characteristicId = descriptor.characteristic.uuid.toString() + device?.address?.let { address -> + handler.post { + callback.onCharacteristicSubscriptionChange( + address, characteristicId, isSubscribed, device.name, + ) {} + } + val charList = subscribedCharDevicesMap[address] ?: mutableListOf() + if (isSubscribed) { + charList.add(characteristicId) + } else { + charList.remove(characteristicId) + } + subscribedCharDevicesMap[address] = charList + } + } + if (responseNeeded) { + gattServer?.sendResponse( + device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value ?: emptyBytes, + ) + } + } + } + + private val broadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + BluetoothAdapter.ACTION_STATE_CHANGED -> { + val state = intent.getIntExtra( + BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR, + ) + if (state == BluetoothAdapter.STATE_OFF) { + handler.post { callback.onBleStateChange(false) {} } + } else if (state == BluetoothAdapter.STATE_ON) { + handler.post { callback.onBleStateChange(true) {} } + } + } + BluetoothDevice.ACTION_BOND_STATE_CHANGED -> { + val state = intent.getIntExtra( + BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR, + ) + val device: BluetoothDevice? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, BluetoothDevice::class.java) + } else { + @Suppress("DEPRECATION") + intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) + } + handler.post { + callback.onBondStateChange( + device?.address ?: "", + state.toPeripheralBondState(), + ) {} + } + + val waitingForConnection = listOfDevicesWaitingForBond.contains(device?.address) + if (state == BluetoothDevice.BOND_BONDED && device != null && waitingForConnection) { + listOfDevicesWaitingForBond.remove(device.address) + handler.post { gattServer?.connect(device, true) } + } + } + } + } + } +} diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePlugin.kt index beac594f..eb5247d4 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePlugin.kt @@ -50,6 +50,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(), private lateinit var safeScanner: SafeScanner private val cachedServicesMap = mutableMapOf>() private val universalBleFilterUtil = UniversalBleFilterUtil() + private lateinit var peripheralPlugin: UniversalBlePeripheralPlugin // Flutter Futures private var bluetoothEnableRequestFuture: ((Result) -> Unit)? = null @@ -65,6 +66,11 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(), override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { UniversalBlePlatformChannel.setUp(flutterPluginBinding.binaryMessenger, this) + peripheralPlugin = UniversalBlePeripheralPlugin( + flutterPluginBinding.applicationContext, + flutterPluginBinding.binaryMessenger + ) + UniversalBlePeripheralChannel.setUp(flutterPluginBinding.binaryMessenger, peripheralPlugin) callbackChannel = UniversalBleCallbackChannel(flutterPluginBinding.binaryMessenger) context = flutterPluginBinding.applicationContext mainThreadHandler = Handler(Looper.getMainLooper()) @@ -85,6 +91,8 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(), override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { bluetoothManager.adapter.bluetoothLeScanner?.stopScan(scanCallback) context.unregisterReceiver(broadcastReceiver) + peripheralPlugin.dispose() + UniversalBlePeripheralChannel.setUp(binding.binaryMessenger, null) callbackChannel = null mainThreadHandler = null permissionHandler = null @@ -1355,6 +1363,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(), override fun onAttachedToActivity(binding: ActivityPluginBinding) { activity = binding.activity + peripheralPlugin.attachActivity(binding.activity) binding.addActivityResultListener(this) binding.addRequestPermissionsResultListener(this) permissionHandler?.attachActivity(binding.activity) @@ -1362,6 +1371,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(), override fun onDetachedFromActivity() { activity = null + peripheralPlugin.attachActivity(null) permissionHandler?.attachActivity(null) } @@ -1371,6 +1381,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(), override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { activity = binding.activity + peripheralPlugin.attachActivity(binding.activity) permissionHandler?.attachActivity(binding.activity) } diff --git a/build_pigeon.sh b/build_pigeon.sh index 3dbe7ba9..c3a8aeb3 100755 --- a/build_pigeon.sh +++ b/build_pigeon.sh @@ -2,10 +2,12 @@ echo "Building pigeon..." dart run pigeon --input pigeon/universal_ble.dart +dart run pigeon --input pigeon/universal_ble_peripheral.dart echo "Pigeon built successfully" echo "Formatting generated files..." dart format lib/src/universal_ble_pigeon/universal_ble.g.dart +dart format lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart echo "Generated files formatted successfully" echo "Done" \ No newline at end of file diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift new file mode 100644 index 00000000..35c3e6c2 --- /dev/null +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift @@ -0,0 +1,747 @@ +// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +private func wrapResult(_ result: Any?) -> [Any?] { + return [result] +} + +private func wrapError(_ error: Any) -> [Any?] { + if let pigeonError = error as? PigeonError { + return [ + pigeonError.code, + pigeonError.message, + pigeonError.details, + ] + } + if let flutterError = error as? FlutterError { + return [ + flutterError.code, + flutterError.message, + flutterError.details, + ] + } + return [ + "\(error)", + "\(type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)", + ] +} + +private func createConnectionError(withChannelName channelName: String) -> PigeonError { + return PigeonError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "") +} + +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + +private func nilOrValue(_ value: Any?) -> T? { + if value is NSNull { return nil } + return value as! T? +} + +func deepEqualsUniversalBlePeripheral(_ 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 !deepEqualsUniversalBlePeripheral(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 !deepEqualsUniversalBlePeripheral(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 deepHashUniversalBlePeripheral(value: Any?, hasher: inout Hasher) { + if let valueList = value as? [AnyHashable] { + for item in valueList { deepHashUniversalBlePeripheral(value: item, hasher: &hasher) } + return + } + + if let valueDict = value as? [AnyHashable: AnyHashable] { + for key in valueDict.keys { + hasher.combine(key) + deepHashUniversalBlePeripheral(value: valueDict[key]!, hasher: &hasher) + } + return + } + + if let hashableValue = value as? AnyHashable { + hasher.combine(hashableValue.hashValue) + } + + return hasher.combine(String(describing: value)) +} + + + +enum PeripheralBondState: Int { + case bonding = 0 + case bonded = 1 + case none = 2 +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralService: Hashable { + var uuid: String + var primary: Bool + var characteristics: [PeripheralCharacteristic] + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralService? { + let uuid = pigeonVar_list[0] as! String + let primary = pigeonVar_list[1] as! Bool + let characteristics = pigeonVar_list[2] as! [PeripheralCharacteristic] + + return PeripheralService( + uuid: uuid, + primary: primary, + characteristics: characteristics + ) + } + func toList() -> [Any?] { + return [ + uuid, + primary, + characteristics, + ] + } + static func == (lhs: PeripheralService, rhs: PeripheralService) -> Bool { + return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + func hash(into hasher: inout Hasher) { + deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralCharacteristic: Hashable { + var uuid: String + var properties: [Int64] + var permissions: [Int64] + var descriptors: [PeripheralDescriptor]? = nil + var value: FlutterStandardTypedData? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralCharacteristic? { + let uuid = pigeonVar_list[0] as! String + let properties = pigeonVar_list[1] as! [Int64] + let permissions = pigeonVar_list[2] as! [Int64] + let descriptors: [PeripheralDescriptor]? = nilOrValue(pigeonVar_list[3]) + let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[4]) + + return PeripheralCharacteristic( + uuid: uuid, + properties: properties, + permissions: permissions, + descriptors: descriptors, + value: value + ) + } + func toList() -> [Any?] { + return [ + uuid, + properties, + permissions, + descriptors, + value, + ] + } + static func == (lhs: PeripheralCharacteristic, rhs: PeripheralCharacteristic) -> Bool { + return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + func hash(into hasher: inout Hasher) { + deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralDescriptor: Hashable { + var uuid: String + var value: FlutterStandardTypedData? = nil + var permissions: [Int64]? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralDescriptor? { + let uuid = pigeonVar_list[0] as! String + let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[1]) + let permissions: [Int64]? = nilOrValue(pigeonVar_list[2]) + + return PeripheralDescriptor( + uuid: uuid, + value: value, + permissions: permissions + ) + } + func toList() -> [Any?] { + return [ + uuid, + value, + permissions, + ] + } + static func == (lhs: PeripheralDescriptor, rhs: PeripheralDescriptor) -> Bool { + return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + func hash(into hasher: inout Hasher) { + deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralReadRequestResult: Hashable { + var value: FlutterStandardTypedData + var offset: Int64? = nil + var status: Int64? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralReadRequestResult? { + let value = pigeonVar_list[0] as! FlutterStandardTypedData + let offset: Int64? = nilOrValue(pigeonVar_list[1]) + let status: Int64? = nilOrValue(pigeonVar_list[2]) + + return PeripheralReadRequestResult( + value: value, + offset: offset, + status: status + ) + } + func toList() -> [Any?] { + return [ + value, + offset, + status, + ] + } + static func == (lhs: PeripheralReadRequestResult, rhs: PeripheralReadRequestResult) -> Bool { + return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + func hash(into hasher: inout Hasher) { + deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralWriteRequestResult: Hashable { + var value: FlutterStandardTypedData? = nil + var offset: Int64? = nil + var status: Int64? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralWriteRequestResult? { + let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[0]) + let offset: Int64? = nilOrValue(pigeonVar_list[1]) + let status: Int64? = nilOrValue(pigeonVar_list[2]) + + return PeripheralWriteRequestResult( + value: value, + offset: offset, + status: status + ) + } + func toList() -> [Any?] { + return [ + value, + offset, + status, + ] + } + static func == (lhs: PeripheralWriteRequestResult, rhs: PeripheralWriteRequestResult) -> Bool { + return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + func hash(into hasher: inout Hasher) { + deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralManufacturerData: Hashable { + var manufacturerId: Int64 + var data: FlutterStandardTypedData + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralManufacturerData? { + let manufacturerId = pigeonVar_list[0] as! Int64 + let data = pigeonVar_list[1] as! FlutterStandardTypedData + + return PeripheralManufacturerData( + manufacturerId: manufacturerId, + data: data + ) + } + func toList() -> [Any?] { + return [ + manufacturerId, + data, + ] + } + static func == (lhs: PeripheralManufacturerData, rhs: PeripheralManufacturerData) -> Bool { + return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + func hash(into hasher: inout Hasher) { + deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + } +} + +private class UniversalBlePeripheralPigeonCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 129: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return PeripheralBondState(rawValue: enumResultAsInt) + } + return nil + case 130: + return PeripheralService.fromList(self.readValue() as! [Any?]) + case 131: + return PeripheralCharacteristic.fromList(self.readValue() as! [Any?]) + case 132: + return PeripheralDescriptor.fromList(self.readValue() as! [Any?]) + case 133: + return PeripheralReadRequestResult.fromList(self.readValue() as! [Any?]) + case 134: + return PeripheralWriteRequestResult.fromList(self.readValue() as! [Any?]) + case 135: + return PeripheralManufacturerData.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class UniversalBlePeripheralPigeonCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? PeripheralBondState { + super.writeByte(129) + super.writeValue(value.rawValue) + } else if let value = value as? PeripheralService { + super.writeByte(130) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralCharacteristic { + super.writeByte(131) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralDescriptor { + super.writeByte(132) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralReadRequestResult { + super.writeByte(133) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralWriteRequestResult { + super.writeByte(134) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralManufacturerData { + super.writeByte(135) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class UniversalBlePeripheralPigeonCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return UniversalBlePeripheralPigeonCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return UniversalBlePeripheralPigeonCodecWriter(data: data) + } +} + +class UniversalBlePeripheralPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = UniversalBlePeripheralPigeonCodec(readerWriter: UniversalBlePeripheralPigeonCodecReaderWriter()) +} + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol UniversalBlePeripheralChannel { + func initialize() throws + func isAdvertising() throws -> Bool? + func isSupported() throws -> Bool + func stopAdvertising() throws + func addService(service: PeripheralService) throws + func removeService(serviceId: String) throws + func clearServices() throws + func getServices() throws -> [String] + func startAdvertising(services: [String], localName: String?, timeout: Int64?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Bool) throws + func updateCharacteristic(characteristicId: String, value: FlutterStandardTypedData, deviceId: String?) throws +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class UniversalBlePeripheralChannelSetup { + static var codec: FlutterStandardMessageCodec { UniversalBlePeripheralPigeonCodec.shared } + /// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let initializeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + initializeChannel.setMessageHandler { _, reply in + do { + try api.initialize() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + initializeChannel.setMessageHandler(nil) + } + let isAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + isAdvertisingChannel.setMessageHandler { _, reply in + do { + let result = try api.isAdvertising() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + isAdvertisingChannel.setMessageHandler(nil) + } + let isSupportedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + isSupportedChannel.setMessageHandler { _, reply in + do { + let result = try api.isSupported() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + isSupportedChannel.setMessageHandler(nil) + } + let stopAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + stopAdvertisingChannel.setMessageHandler { _, reply in + do { + try api.stopAdvertising() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + stopAdvertisingChannel.setMessageHandler(nil) + } + let addServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addServiceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let serviceArg = args[0] as! PeripheralService + do { + try api.addService(service: serviceArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + addServiceChannel.setMessageHandler(nil) + } + let removeServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeServiceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let serviceIdArg = args[0] as! String + do { + try api.removeService(serviceId: serviceIdArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + removeServiceChannel.setMessageHandler(nil) + } + let clearServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + clearServicesChannel.setMessageHandler { _, reply in + do { + try api.clearServices() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + clearServicesChannel.setMessageHandler(nil) + } + let getServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getServicesChannel.setMessageHandler { _, reply in + do { + let result = try api.getServices() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getServicesChannel.setMessageHandler(nil) + } + let startAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + startAdvertisingChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let servicesArg = args[0] as! [String] + let localNameArg: String? = nilOrValue(args[1]) + let timeoutArg: Int64? = nilOrValue(args[2]) + let manufacturerDataArg: PeripheralManufacturerData? = nilOrValue(args[3]) + let addManufacturerDataInScanResponseArg = args[4] as! Bool + do { + try api.startAdvertising(services: servicesArg, localName: localNameArg, timeout: timeoutArg, manufacturerData: manufacturerDataArg, addManufacturerDataInScanResponse: addManufacturerDataInScanResponseArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + startAdvertisingChannel.setMessageHandler(nil) + } + let updateCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + updateCharacteristicChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let characteristicIdArg = args[0] as! String + let valueArg = args[1] as! FlutterStandardTypedData + let deviceIdArg: String? = nilOrValue(args[2]) + do { + try api.updateCharacteristic(characteristicId: characteristicIdArg, value: valueArg, deviceId: deviceIdArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + updateCharacteristicChannel.setMessageHandler(nil) + } + } +} +/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. +protocol UniversalBlePeripheralCallbackProtocol { + func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) + func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) + func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) + func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) + func onBleStateChange(state stateArg: Bool, completion: @escaping (Result) -> Void) + func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) + func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) + func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) + func onBondStateChange(deviceId deviceIdArg: String, bondState bondStateArg: PeripheralBondState, completion: @escaping (Result) -> Void) +} +class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { + private let binaryMessenger: FlutterBinaryMessenger + private let messageChannelSuffix: String + init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { + self.binaryMessenger = binaryMessenger + self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + } + var codec: UniversalBlePeripheralPigeonCodec { + return UniversalBlePeripheralPigeonCodec.shared + } + func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + let result: PeripheralReadRequestResult? = nilOrValue(listResponse[0]) + completion(.success(result)) + } + } + } + func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + let result: PeripheralWriteRequestResult? = nilOrValue(listResponse[0]) + completion(.success(result)) + } + } + } + func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([advertisingArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onBleStateChange(state stateArg: Bool, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([stateArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([serviceIdArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, mtuArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, connectedArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onBondStateChange(deviceId deviceIdArg: String, bondState bondStateArg: PeripheralBondState, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, bondStateArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } +} diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift new file mode 100644 index 00000000..388fb2e9 --- /dev/null +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift @@ -0,0 +1,126 @@ +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif +import CoreBluetooth +import Foundation + +enum UniversalBlePeripheralError: Error { + case notFound(String) +} + +var peripheralCharacteristicsList = [CBMutableCharacteristic]() +var peripheralServicesList = [CBMutableService]() + +extension PeripheralService { + func toCBService() -> CBMutableService { + let service = CBMutableService(type: CBUUID(string: uuid), primary: primary) + let chars = characteristics.compactMap { $0.toCBCharacteristic() } + if !chars.isEmpty { + service.characteristics = chars + } + peripheralServicesList.removeAll { + $0.uuid.uuidString.lowercased() == service.uuid.uuidString.lowercased() + } + peripheralServicesList.append(service) + return service + } +} + +extension PeripheralDescriptor { + func toCBMutableDescriptor() -> CBMutableDescriptor { + return CBMutableDescriptor(type: CBUUID(string: uuid), value: value?.toData()) + } +} + +extension PeripheralCharacteristic { + func toCBCharacteristic() -> CBMutableCharacteristic { + let properties = self.properties.compactMap { $0.toCBCharacteristicProperties() } + let permissions = self.permissions.compactMap { $0.toCBAttributePermissions() } + let combinedProperties = properties.reduce(CBCharacteristicProperties()) { $0.union($1) } + let combinedPermissions = permissions.reduce(CBAttributePermissions()) { $0.union($1) } + let characteristic = CBMutableCharacteristic( + type: CBUUID(string: uuid), + properties: combinedProperties, + value: value?.toData(), + permissions: combinedPermissions + ) + characteristic.descriptors = descriptors?.compactMap { $0.toCBMutableDescriptor() } + peripheralCharacteristicsList.removeAll { + $0.uuid.uuidString.lowercased() == characteristic.uuid.uuidString.lowercased() + } + peripheralCharacteristicsList.append(characteristic) + return characteristic + } +} + +extension String { + func findPeripheralCharacteristic() -> CBMutableCharacteristic? { + peripheralCharacteristicsList.first { $0.uuid.uuidString == self } + } + + func findPeripheralService() -> CBMutableService? { + peripheralServicesList.first { $0.uuid.uuidString == self } + } +} + +extension Int64 { + func toCBCharacteristicProperties() -> CBCharacteristicProperties? { + switch self { + case 0: return .broadcast + case 1: return .read + case 2: return .writeWithoutResponse + case 3: return .write + case 4: return .notify + case 5: return .indicate + case 6: return .authenticatedSignedWrites + case 7: return .extendedProperties + case 8: return .notifyEncryptionRequired + case 9: return .indicateEncryptionRequired + default: return nil + } + } + + func toCBAttributePermissions() -> CBAttributePermissions? { + switch self { + case 0: return .readable + case 1: return .writeable + case 2: return .readEncryptionRequired + case 3: return .writeEncryptionRequired + default: return nil + } + } + + func toCBATTErrorCode() -> CBATTError.Code { + switch self { + case 0: return .success + case 1: return .invalidHandle + case 2: return .readNotPermitted + case 3: return .writeNotPermitted + case 4: return .invalidPdu + case 5: return .insufficientAuthentication + case 6: return .requestNotSupported + case 7: return .invalidOffset + case 8: return .insufficientAuthorization + case 9: return .prepareQueueFull + case 10: return .attributeNotFound + case 11: return .attributeNotLong + case 12: return .insufficientEncryptionKeySize + case 13: return .invalidAttributeValueLength + case 14: return .unlikelyError + case 15: return .insufficientEncryption + case 16: return .unsupportedGroupType + case 17: return .insufficientResources + default: return .success + } + } +} + +extension Data { + func toFlutterBytes() -> FlutterStandardTypedData { + FlutterStandardTypedData(bytes: self) + } +} diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift new file mode 100644 index 00000000..5527bdd4 --- /dev/null +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -0,0 +1,203 @@ +#if os(iOS) + import Flutter +#elseif os(macOS) + import Cocoa + import FlutterMacOS +#endif +import CoreBluetooth +import Foundation + +final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChannel, + CBPeripheralManagerDelegate +{ + private let callbackChannel: UniversalBlePeripheralCallback + private lazy var peripheralManager: CBPeripheralManager = + .init(delegate: self, queue: nil, options: nil) + private var centrals = [CBCentral]() + + init(callbackChannel: UniversalBlePeripheralCallback) { + self.callbackChannel = callbackChannel + super.init() + } + + func initialize() throws { + _ = peripheralManager.isAdvertising + } + + func isSupported() throws -> Bool { + true + } + + func isAdvertising() throws -> Bool? { + peripheralManager.isAdvertising + } + + func stopAdvertising() throws { + peripheralManager.stopAdvertising() + callbackChannel.onAdvertisingStatusUpdate(advertising: false, error: nil) { _ in } + } + + func addService(service: PeripheralService) throws { + peripheralManager.add(service.toCBService()) + } + + func removeService(serviceId: String) throws { + if let service = serviceId.findPeripheralService() { + peripheralManager.remove(service) + peripheralServicesList.removeAll { + $0.uuid.uuidString.lowercased() == service.uuid.uuidString.lowercased() + } + } + } + + func clearServices() throws { + peripheralManager.removeAllServices() + peripheralServicesList.removeAll() + } + + func getServices() throws -> [String] { + peripheralServicesList.map { $0.uuid.uuidString } + } + + func startAdvertising( + services: [String], + localName: String?, + timeout _: Int64?, + manufacturerData _: PeripheralManufacturerData?, + addManufacturerDataInScanResponse _: Bool + ) throws { + let cbServices = services.map { CBUUID(string: $0) } + var advertisementData: [String: Any] = [CBAdvertisementDataServiceUUIDsKey: cbServices] + if let localName { + advertisementData[CBAdvertisementDataLocalNameKey] = localName + } + peripheralManager.startAdvertising(advertisementData) + } + + func updateCharacteristic( + characteristicId: String, + value: FlutterStandardTypedData, + deviceId: String? + ) throws { + guard let characteristic = characteristicId.findPeripheralCharacteristic() else { + throw UniversalBlePeripheralError.notFound("\(characteristicId) characteristic not found") + } + if let deviceId { + guard let central = centrals.first(where: { $0.identifier.uuidString == deviceId }) else { + throw UniversalBlePeripheralError.notFound("\(deviceId) device not found") + } + peripheralManager.updateValue( + value.toData(), + for: characteristic, + onSubscribedCentrals: [central] + ) + } else { + peripheralManager.updateValue(value.toData(), for: characteristic, onSubscribedCentrals: nil) + } + } + + nonisolated func peripheralManagerDidStartAdvertising( + _: CBPeripheralManager, + error: Error? + ) { + callbackChannel.onAdvertisingStatusUpdate( + advertising: error == nil, + error: error?.localizedDescription + ) { _ in } + } + + nonisolated func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { + callbackChannel.onBleStateChange(state: peripheral.state == .poweredOn) { _ in } + } + + nonisolated func peripheralManager( + _: CBPeripheralManager, + didAdd service: CBService, + error: Error? + ) { + callbackChannel.onServiceAdded( + serviceId: service.uuid.uuidString, + error: error?.localizedDescription + ) { _ in } + } + + nonisolated func peripheralManager( + _: CBPeripheralManager, + central: CBCentral, + didSubscribeTo characteristic: CBCharacteristic + ) { + if !centrals.contains(where: { $0.identifier == central.identifier }) { + centrals.append(central) + } + callbackChannel.onCharacteristicSubscriptionChange( + deviceId: central.identifier.uuidString, + characteristicId: characteristic.uuid.uuidString, + isSubscribed: true, + name: nil + ) { _ in } + callbackChannel.onMtuChange( + deviceId: central.identifier.uuidString, + mtu: Int64(central.maximumUpdateValueLength) + ) { _ in } + } + + nonisolated func peripheralManager( + _: CBPeripheralManager, + central: CBCentral, + didUnsubscribeFrom characteristic: CBCharacteristic + ) { + centrals.removeAll { $0.identifier == central.identifier } + callbackChannel.onCharacteristicSubscriptionChange( + deviceId: central.identifier.uuidString, + characteristicId: characteristic.uuid.uuidString, + isSubscribed: false, + name: nil + ) { _ in } + } + + nonisolated func peripheralManager( + _: CBPeripheralManager, + didReceiveRead request: CBATTRequest + ) { + callbackChannel.onReadRequest( + deviceId: request.central.identifier.uuidString, + characteristicId: request.characteristic.uuid.uuidString, + offset: Int64(request.offset), + value: request.value?.toFlutterBytes() + ) { readReq in + do { + let result = try readReq.get() + guard let data = result?.value.toData() as Data? else { + self.peripheralManager.respond(to: request, withResult: .requestNotSupported) + return + } + request.value = data + self.peripheralManager.respond(to: request, withResult: .success) + } catch { + self.peripheralManager.respond(to: request, withResult: .requestNotSupported) + } + } + } + + nonisolated func peripheralManager( + _: CBPeripheralManager, + didReceiveWrite requests: [CBATTRequest] + ) { + requests.forEach { req in + callbackChannel.onWriteRequest( + deviceId: req.central.identifier.uuidString, + characteristicId: req.characteristic.uuid.uuidString, + offset: Int64(req.offset), + value: req.value?.toFlutterBytes() + ) { writeRes in + do { + let response = try writeRes.get() + let status = response?.status?.toCBATTErrorCode() ?? .success + self.peripheralManager.respond(to: req, withResult: status) + } catch { + self.peripheralManager.respond(to: req, withResult: .requestNotSupported) + } + } + } + } +} diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift index 4f6b1fb3..042a2e97 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift @@ -18,7 +18,13 @@ public class UniversalBlePlugin: NSObject, FlutterPlugin { #endif let callbackChannel = UniversalBleCallbackChannel(binaryMessenger: messenger) let api = BleCentralDarwin(callbackChannel: callbackChannel) + let peripheralCallbackChannel = UniversalBlePeripheralCallback(binaryMessenger: messenger) + let peripheralApi = UniversalBlePeripheralPlugin(callbackChannel: peripheralCallbackChannel) UniversalBlePlatformChannelSetup.setUp(binaryMessenger: messenger, api: api) + UniversalBlePeripheralChannelSetup.setUp( + binaryMessenger: messenger, + api: peripheralApi + ) } } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 00000000..987d4b6e --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,36 @@ +PODS: + - ble_peripheral (0.0.1): + - Flutter + - FlutterMacOS + - Flutter (1.0.0) + - integration_test (0.0.1): + - Flutter + - universal_ble (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - ble_peripheral (from `.symlinks/plugins/ble_peripheral/darwin`) + - Flutter (from `Flutter`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) + - universal_ble (from `.symlinks/plugins/universal_ble/darwin`) + +EXTERNAL SOURCES: + ble_peripheral: + :path: ".symlinks/plugins/ble_peripheral/darwin" + Flutter: + :path: Flutter + integration_test: + :path: ".symlinks/plugins/integration_test/ios" + universal_ble: + :path: ".symlinks/plugins/universal_ble/darwin" + +SPEC CHECKSUMS: + ble_peripheral: 1d6cb378caaef61cd39410652a4de1a68dfba4f2 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e + universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914 + +PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694 + +COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index ea2a2e8a..730c7de2 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -10,11 +10,13 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3C020DDC565FF8D37F3235C5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E92536821956EA00892DD639 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + B2742FE9E6C1C51A78D26865 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AB88605F389EEED340E5872 /* Pods_RunnerTests.framework */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -41,14 +43,18 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0D9A3CA727A1375BDCCC70CF /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 30B9BF32CD25D1ECB8BB5DCA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 411AF23EC127806AE083685B /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 4414252E2351EBDB7761F83A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 6CF659084054FE2807275A3A /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -57,6 +63,10 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9AB88605F389EEED340E5872 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A11EED44BE0324AD23055698 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + E92536821956EA00892DD639 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -64,6 +74,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B2742FE9E6C1C51A78D26865 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -72,6 +83,7 @@ buildActionMask = 2147483647; files = ( 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + 3C020DDC565FF8D37F3235C5 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -86,6 +98,15 @@ path = RunnerTests; sourceTree = ""; }; + 68033A1F47BF85C19A1ED513 /* Frameworks */ = { + isa = PBXGroup; + children = ( + E92536821956EA00892DD639 /* Pods_Runner.framework */, + 9AB88605F389EEED340E5872 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -106,6 +127,7 @@ 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, FAF8A3758B0770B81319B3AE /* Pods */, + 68033A1F47BF85C19A1ED513 /* Frameworks */, ); sourceTree = ""; }; @@ -136,6 +158,12 @@ FAF8A3758B0770B81319B3AE /* Pods */ = { isa = PBXGroup; children = ( + 30B9BF32CD25D1ECB8BB5DCA /* Pods-Runner.debug.xcconfig */, + 4414252E2351EBDB7761F83A /* Pods-Runner.release.xcconfig */, + A11EED44BE0324AD23055698 /* Pods-Runner.profile.xcconfig */, + 411AF23EC127806AE083685B /* Pods-RunnerTests.debug.xcconfig */, + 0D9A3CA727A1375BDCCC70CF /* Pods-RunnerTests.release.xcconfig */, + 6CF659084054FE2807275A3A /* Pods-RunnerTests.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -147,6 +175,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 7E79F47357B64513A488AC3E /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, 8EE4584064C335A1F66BB6D9 /* Frameworks */, @@ -162,24 +191,26 @@ productType = "com.apple.product-type.bundle.unit-test"; }; 97C146ED1CF9000F007C117D /* Runner */ = { + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 3CE2E408302E9BF272A3BE07 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 2F5EDC3CC74E7431E4CB95DF /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = Runner; - packageProductDependencies = ( - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, - ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -188,6 +219,9 @@ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; @@ -213,9 +247,6 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; - packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, - ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -248,6 +279,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 2F5EDC3CC74E7431E4CB95DF /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -264,6 +312,50 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 3CE2E408302E9BF272A3BE07 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 7E79F47357B64513A488AC3E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -370,7 +462,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.1; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -403,6 +495,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 411AF23EC127806AE083685B /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -420,6 +513,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0D9A3CA727A1375BDCCC70CF /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -435,6 +529,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 6CF659084054FE2807275A3A /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -495,7 +590,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.1; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -544,7 +639,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.1; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -634,14 +729,12 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ - /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; /* End XCLocalSwiftPackageReference section */ - /* Begin XCSwiftPackageProductDependency section */ 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { isa = XCSwiftPackageProductDependency; diff --git a/example/lib/home/home.dart b/example/lib/home/home.dart index 0ab9c57b..d3daea1f 100644 --- a/example/lib/home/home.dart +++ b/example/lib/home/home.dart @@ -11,14 +11,15 @@ import 'package:universal_ble_example/peripheral_details/peripheral_detail_page. import 'package:universal_ble_example/widgets/platform_button.dart'; import 'package:universal_ble_example/widgets/responsive_buttons_grid.dart'; -class MyApp extends StatefulWidget { - const MyApp({super.key}); +class CentralHome extends StatefulWidget { + final bool showAppBar; + const CentralHome({super.key, this.showAppBar = true}); @override - State createState() => _MyAppState(); + State createState() => _CentralHomeState(); } -class _MyAppState extends State { +class _CentralHomeState extends State { final _bleDevices = []; final _hiddenDevices = []; bool _isScanning = false; @@ -150,22 +151,24 @@ class _MyAppState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Universal BLE'), - elevation: 4, - actions: [ - if (_isScanning) - const Padding( - padding: EdgeInsets.all(8.0), - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - )), - ), - ], - ), + appBar: widget.showAppBar + ? AppBar( + title: const Text('Universal BLE - Central'), + elevation: 4, + actions: [ + if (_isScanning) + const Padding( + padding: EdgeInsets.all(8.0), + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator.adaptive( + strokeWidth: 2, + )), + ), + ], + ) + : null, body: Column( children: [ Padding( diff --git a/example/lib/main.dart b/example/lib/main.dart index 01f1d477..c73bb0ea 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:universal_ble/universal_ble.dart'; -import 'package:universal_ble_example/home/home.dart'; +import 'package:universal_ble_example/home/home.dart' show CentralHome; +import 'package:universal_ble_example/peripheral/peripheral_home.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -11,7 +12,35 @@ void main() async { debugShowCheckedModeBanner: false, darkTheme: ThemeData.dark(), themeMode: ThemeMode.system, - home: const MyApp(), + home: const _TabbedExample(), ), ); } + +class _TabbedExample extends StatelessWidget { + const _TabbedExample(); + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 2, + child: Scaffold( + appBar: AppBar( + title: const Text('Universal BLE'), + bottom: const TabBar( + tabs: [ + Tab(text: 'Central'), + Tab(text: 'Peripheral'), + ], + ), + ), + body: const TabBarView( + children: [ + CentralHome(showAppBar: false), + PeripheralHome(), + ], + ), + ), + ); + } +} diff --git a/example/lib/peripheral/peripheral_home.dart b/example/lib/peripheral/peripheral_home.dart new file mode 100644 index 00000000..40cbccb0 --- /dev/null +++ b/example/lib/peripheral/peripheral_home.dart @@ -0,0 +1,188 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:universal_ble/universal_ble.dart'; + +class PeripheralHome extends StatefulWidget { + const PeripheralHome({super.key}); + + @override + State createState() => _PeripheralHomeState(); +} + +class _PeripheralHomeState extends State { + final List _logs = []; + bool _initialized = false; + bool _advertising = false; + + static const String _serviceBattery = '0000180F-0000-1000-8000-00805F9B34FB'; + static const String _charBattery = '00002A19-0000-1000-8000-00805F9B34FB'; + static const String _serviceTest = '0000180D-0000-1000-8000-00805F9B34FB'; + static const String _charTest = '00002A18-0000-1000-8000-00805F9B34FB'; + + @override + void initState() { + super.initState(); + UniversalBlePeripheral.onAdvertisingStatusUpdate = (advertising, error) { + setState(() { + _advertising = advertising; + }); + _log('Advertising: $advertising ${error ?? ''}'.trim()); + }; + UniversalBlePeripheral.onServiceAdded = (serviceId, error) { + _log('Service added: $serviceId ${error ?? ''}'.trim()); + }; + UniversalBlePeripheral.onSubscriptionChange = ( + deviceId, + characteristicId, + isSubscribed, + name, + ) { + _log( + 'Subscription ${isSubscribed ? 'on' : 'off'}: ' + '${name ?? deviceId} -> $characteristicId', + ); + }; + UniversalBlePeripheral.onReadRequest = (deviceId, characteristicId, _, __) { + _log('Read request: $deviceId $characteristicId'); + return BleReadRequestResult(value: utf8.encode('Hello World')); + }; + UniversalBlePeripheral.onWriteRequest = ( + deviceId, + characteristicId, + _, + value, + ) { + _log('Write request: $deviceId $characteristicId $value'); + return const BleWriteRequestResult(); + }; + } + + void _log(String text) { + setState(() { + _logs.insert(0, text); + }); + } + + Future _initialize() async { + await UniversalBlePeripheral.initialize(); + final supported = await UniversalBlePeripheral.isSupported(); + setState(() { + _initialized = true; + }); + _log('Peripheral initialized. supported=$supported'); + } + + Future _addServices() async { + await UniversalBlePeripheral.addService( + BleService(_serviceBattery, [ + BleCharacteristic( + _charBattery, + [CharacteristicProperty.read, CharacteristicProperty.notify], + [], + ), + ]), + ); + await UniversalBlePeripheral.addService( + BleService(_serviceTest, [ + BleCharacteristic( + _charTest, + [ + CharacteristicProperty.read, + CharacteristicProperty.notify, + CharacteristicProperty.write, + ], + [BleDescriptor('00002908-0000-1000-8000-00805F9B34FB')], + ), + ]), + ); + _log('Services queued'); + } + + Future _startAdvertising() async { + await UniversalBlePeripheral.startAdvertising( + services: [_serviceBattery, _serviceTest], + localName: 'UniversalBlePeripheral', + manufacturerData: ManufacturerData( + 0x012D, + Uint8List.fromList([0x03, 0x00, 0x64, 0x00]), + ), + addManufacturerDataInScanResponse: true, + ); + _log('Start advertising requested'); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 8, + runSpacing: 8, + children: [ + ElevatedButton( + onPressed: _initialize, + child: Text(_initialized ? 'Reinitialize' : 'Initialize'), + ), + ElevatedButton( + onPressed: _initialized ? _addServices : null, + child: const Text('Add Services'), + ), + ElevatedButton( + onPressed: _initialized ? _startAdvertising : null, + child: const Text('Start Advertising'), + ), + ElevatedButton( + onPressed: _initialized + ? () async { + await UniversalBlePeripheral.stopAdvertising(); + setState(() { + _advertising = false; + }); + _log('Stop advertising requested'); + } + : null, + child: const Text('Stop Advertising'), + ), + ElevatedButton( + onPressed: _initialized + ? () async { + await UniversalBlePeripheral.updateCharacteristic( + characteristicId: _charTest, + value: utf8.encode('Test Data'), + ); + _log('Characteristic updated'); + } + : null, + child: const Text('Update Characteristic'), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + Text('Initialized: $_initialized'), + const SizedBox(width: 16), + Text('Advertising: $_advertising'), + ], + ), + ), + const Divider(), + Expanded( + child: ListView.builder( + itemCount: _logs.length, + itemBuilder: (context, index) => ListTile( + dense: true, + title: Text(_logs[index]), + ), + ), + ), + ], + ); + } +} diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 7ddba83e..474e8d78 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,10 @@ import FlutterMacOS import Foundation +import ble_peripheral import universal_ble func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + BlePeripheralPlugin.register(with: registry.registrar(forPlugin: "BlePeripheralPlugin")) UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin")) } diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock new file mode 100644 index 00000000..cffb3dba --- /dev/null +++ b/example/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - ble_peripheral (0.0.1): + - Flutter + - FlutterMacOS + - FlutterMacOS (1.0.0) + - universal_ble (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - ble_peripheral (from `Flutter/ephemeral/.symlinks/plugins/ble_peripheral/darwin`) + - FlutterMacOS (from `Flutter/ephemeral`) + - universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`) + +EXTERNAL SOURCES: + ble_peripheral: + :path: Flutter/ephemeral/.symlinks/plugins/ble_peripheral/darwin + FlutterMacOS: + :path: Flutter/ephemeral + universal_ble: + :path: Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin + +SPEC CHECKSUMS: + ble_peripheral: 1d6cb378caaef61cd39410652a4de1a68dfba4f2 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914 + +PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 + +COCOAPODS: 1.16.2 diff --git a/lib/src/models/model_exports.dart b/lib/src/models/model_exports.dart index 7533772d..55ffbd9b 100644 --- a/lib/src/models/model_exports.dart +++ b/lib/src/models/model_exports.dart @@ -13,3 +13,4 @@ export 'package:universal_ble/src/models/ble_device.dart'; export 'package:universal_ble/src/models/ble_command.dart'; export 'package:universal_ble/src/models/ble_capabilities.dart'; export 'package:universal_ble/src/models/ble_connection_priority.dart'; +export 'package:universal_ble/src/models/peripheral/peripheral_exports.dart'; diff --git a/lib/src/models/peripheral/attribute_permissions.dart b/lib/src/models/peripheral/attribute_permissions.dart new file mode 100644 index 00000000..0d665601 --- /dev/null +++ b/lib/src/models/peripheral/attribute_permissions.dart @@ -0,0 +1,6 @@ +enum AttributePermission { + readable, + writeable, + readEncryptionRequired, + writeEncryptionRequired; +} diff --git a/lib/src/models/peripheral/peripheral_exports.dart b/lib/src/models/peripheral/peripheral_exports.dart new file mode 100644 index 00000000..e2956739 --- /dev/null +++ b/lib/src/models/peripheral/peripheral_exports.dart @@ -0,0 +1,2 @@ +export 'package:universal_ble/src/models/peripheral/attribute_permissions.dart'; +export 'package:universal_ble/src/models/peripheral/peripheral_request_result.dart'; diff --git a/lib/src/models/peripheral/peripheral_request_result.dart b/lib/src/models/peripheral/peripheral_request_result.dart new file mode 100644 index 00000000..28f6ccf2 --- /dev/null +++ b/lib/src/models/peripheral/peripheral_request_result.dart @@ -0,0 +1,25 @@ +import 'dart:typed_data'; + +class BleReadRequestResult { + final Uint8List value; + final int? offset; + final int? status; + + const BleReadRequestResult({ + required this.value, + this.offset, + this.status, + }); +} + +class BleWriteRequestResult { + final Uint8List? value; + final int? offset; + final int? status; + + const BleWriteRequestResult({ + this.value, + this.offset, + this.status, + }); +} diff --git a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart new file mode 100644 index 00000000..b6e935c2 --- /dev/null +++ b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart @@ -0,0 +1,914 @@ +// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List; + +import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; + +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; +} + +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [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 entry) => + (b as Map).containsKey(entry.key) && + _deepEquals(entry.value, b[entry.key])); + } + return a == b; +} + +enum PeripheralBondState { + bonding, + bonded, + none, +} + +class PeripheralService { + PeripheralService({ + required this.uuid, + required this.primary, + required this.characteristics, + }); + + String uuid; + + bool primary; + + List characteristics; + + List _toList() { + return [ + uuid, + primary, + characteristics, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralService decode(Object result) { + result as List; + return PeripheralService( + uuid: result[0]! as String, + primary: result[1]! as bool, + characteristics: + (result[2]! as List).cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralService || 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 PeripheralCharacteristic { + PeripheralCharacteristic({ + required this.uuid, + required this.properties, + required this.permissions, + this.descriptors, + this.value, + }); + + String uuid; + + List properties; + + List permissions; + + List? descriptors; + + Uint8List? value; + + List _toList() { + return [ + uuid, + properties, + permissions, + descriptors, + value, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralCharacteristic decode(Object result) { + result as List; + return PeripheralCharacteristic( + uuid: result[0]! as String, + properties: (result[1]! as List).cast(), + permissions: (result[2]! as List).cast(), + descriptors: (result[3] as List?)?.cast(), + value: result[4] as Uint8List?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralCharacteristic || + 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 PeripheralDescriptor { + PeripheralDescriptor({ + required this.uuid, + this.value, + this.permissions, + }); + + String uuid; + + Uint8List? value; + + List? permissions; + + List _toList() { + return [ + uuid, + value, + permissions, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralDescriptor decode(Object result) { + result as List; + return PeripheralDescriptor( + uuid: result[0]! as String, + value: result[1] as Uint8List?, + permissions: (result[2] as List?)?.cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralDescriptor || 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 PeripheralReadRequestResult { + PeripheralReadRequestResult({ + required this.value, + this.offset, + this.status, + }); + + Uint8List value; + + int? offset; + + int? status; + + List _toList() { + return [ + value, + offset, + status, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralReadRequestResult decode(Object result) { + result as List; + return PeripheralReadRequestResult( + value: result[0]! as Uint8List, + offset: result[1] as int?, + status: result[2] as int?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralReadRequestResult || + 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 PeripheralWriteRequestResult { + PeripheralWriteRequestResult({ + this.value, + this.offset, + this.status, + }); + + Uint8List? value; + + int? offset; + + int? status; + + List _toList() { + return [ + value, + offset, + status, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralWriteRequestResult decode(Object result) { + result as List; + return PeripheralWriteRequestResult( + value: result[0] as Uint8List?, + offset: result[1] as int?, + status: result[2] as int?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralWriteRequestResult || + 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 PeripheralManufacturerData { + PeripheralManufacturerData({ + required this.manufacturerId, + required this.data, + }); + + int manufacturerId; + + Uint8List data; + + List _toList() { + return [ + manufacturerId, + data, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralManufacturerData decode(Object result) { + result as List; + return PeripheralManufacturerData( + manufacturerId: result[0]! as int, + data: result[1]! as Uint8List, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralManufacturerData || + 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(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is PeripheralBondState) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is PeripheralService) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is PeripheralCharacteristic) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is PeripheralDescriptor) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else if (value is PeripheralReadRequestResult) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is PeripheralWriteRequestResult) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is PeripheralManufacturerData) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final value = readValue(buffer) as int?; + return value == null ? null : PeripheralBondState.values[value]; + case 130: + return PeripheralService.decode(readValue(buffer)!); + case 131: + return PeripheralCharacteristic.decode(readValue(buffer)!); + case 132: + return PeripheralDescriptor.decode(readValue(buffer)!); + case 133: + return PeripheralReadRequestResult.decode(readValue(buffer)!); + case 134: + return PeripheralWriteRequestResult.decode(readValue(buffer)!); + case 135: + return PeripheralManufacturerData.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class UniversalBlePeripheralChannel { + /// Constructor for [UniversalBlePeripheralChannel]. 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. + UniversalBlePeripheralChannel( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future initialize() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future isAdvertising() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as bool?; + } + + Future isSupported() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; + } + + Future stopAdvertising() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future addService(PeripheralService service) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([service]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future removeService(String serviceId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([serviceId]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future clearServices() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future> getServices() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); + } + + Future startAdvertising( + List services, + String? localName, + int? timeout, + PeripheralManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([ + services, + localName, + timeout, + manufacturerData, + addManufacturerDataInScanResponse + ]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future updateCharacteristic( + String characteristicId, Uint8List value, String? deviceId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([characteristicId, value, deviceId]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } +} + +abstract class UniversalBlePeripheralCallback { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + PeripheralReadRequestResult? onReadRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); + + PeripheralWriteRequestResult? onWriteRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); + + void onCharacteristicSubscriptionChange(String deviceId, + String characteristicId, bool isSubscribed, String? name); + + void onAdvertisingStatusUpdate(bool advertising, String? error); + + void onBleStateChange(bool state); + + void onServiceAdded(String serviceId, String? error); + + void onMtuChange(String deviceId, int mtu); + + void onConnectionStateChange(String deviceId, bool connected); + + void onBondStateChange(String deviceId, PeripheralBondState bondState); + + static void setUp( + UniversalBlePeripheralCallback? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final int arg_offset = args[2]! as int; + final Uint8List? arg_value = args[3] as Uint8List?; + try { + final PeripheralReadRequestResult? output = api.onReadRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final int arg_offset = args[2]! as int; + final Uint8List? arg_value = args[3] as Uint8List?; + try { + final PeripheralWriteRequestResult? output = api.onWriteRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final bool arg_isSubscribed = args[2]! as bool; + final String? arg_name = args[3] as String?; + try { + api.onCharacteristicSubscriptionChange( + arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final bool arg_advertising = args[0]! as bool; + final String? arg_error = args[1] as String?; + try { + api.onAdvertisingStatusUpdate(arg_advertising, arg_error); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final bool arg_state = args[0]! as bool; + try { + api.onBleStateChange(arg_state); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_serviceId = args[0]! as String; + final String? arg_error = args[1] as String?; + try { + api.onServiceAdded(arg_serviceId, arg_error); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final int arg_mtu = args[1]! as int; + try { + api.onMtuChange(arg_deviceId, arg_mtu); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final bool arg_connected = args[1]! as bool; + try { + api.onConnectionStateChange(arg_deviceId, arg_connected); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final PeripheralBondState arg_bondState = + args[1]! as PeripheralBondState; + try { + api.onBondStateChange(arg_deviceId, arg_bondState); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart new file mode 100644 index 00000000..ce7601d9 --- /dev/null +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -0,0 +1,104 @@ +import 'package:flutter/foundation.dart'; +import 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart'; +import 'package:universal_ble/universal_ble.dart'; + +class UniversalBlePeripheral { + static UniversalBlePeripheralPlatform _platform = _defaultPlatform(); + + static UniversalBlePeripheralPlatform _defaultPlatform() { + if (kIsWeb || defaultTargetPlatform == TargetPlatform.linux) { + return UniversalBlePeripheralUnsupported(); + } + return UniversalBlePeripheralPigeon.instance; + } + + static void setInstance(UniversalBlePeripheralPlatform instance) { + _platform = instance; + } + + static Future initialize() => _platform.initialize(); + static Future isSupported() => _platform.isSupported(); + static Future isAdvertising() => _platform.isAdvertising(); + + static Future addService( + BleService service, { + bool primary = true, + Duration? timeout, + }) => + _platform.addService(service, primary: primary, timeout: timeout); + + static Future removeService(String serviceId) => + _platform.removeService(serviceId); + static Future clearServices() => _platform.clearServices(); + static Future> getServices() => _platform.getServices(); + + static Future startAdvertising({ + required List services, + String? localName, + int? timeout, + ManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse = false, + }) => + _platform.startAdvertising( + services: services.map(BleUuidParser.string).toList(), + localName: localName, + timeout: timeout, + manufacturerData: manufacturerData, + addManufacturerDataInScanResponse: addManufacturerDataInScanResponse, + ); + + static Future stopAdvertising() => _platform.stopAdvertising(); + + static Future updateCharacteristic({ + required String characteristicId, + required Uint8List value, + String? deviceId, + }) => + _platform.updateCharacteristic( + characteristicId: characteristicId, + value: value, + deviceId: deviceId, + ); + + static set onAdvertisingStatusUpdate( + OnPeripheralAdvertisingStatusUpdate? callback, + ) { + _platform.advertisingStatusUpdateCallback = callback; + } + + static set onBleStateChange(OnPeripheralBleStateChange? callback) { + _platform.bleStateChangeCallback = callback; + } + + static set onBondStateChange(OnPeripheralBondStateChange? callback) { + _platform.bondStateChangeCallback = callback; + } + + static set onSubscriptionChange( + OnPeripheralCharacteristicSubscriptionChange? callback, + ) { + _platform.subscriptionChangeCallback = callback; + } + + static set onConnectionStateChange( + OnPeripheralConnectionStateChange? callback, + ) { + _platform.connectionStateChangeCallback = callback; + } + + static set onReadRequest(OnPeripheralReadRequest? callback) { + _platform.readRequestCallback = callback; + } + + static set onServiceAdded(OnPeripheralServiceAdded? callback) { + _platform.serviceAddedCallback = callback; + } + + static set onWriteRequest(OnPeripheralWriteRequest? callback) { + _platform.writeRequestCallback = callback; + } + + static set onMtuChange(OnPeripheralMtuChange? callback) { + _platform.mtuChangeCallback = callback; + } +} diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart new file mode 100644 index 00000000..562b0b62 --- /dev/null +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart @@ -0,0 +1,53 @@ +import 'package:universal_ble/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart' + as pigeon; +import 'package:universal_ble/universal_ble.dart'; + +class UniversalBlePeripheralMapper { + static pigeon.PeripheralService toPigeonService( + BleService service, { + required bool primary, + }) { + return pigeon.PeripheralService( + uuid: BleUuidParser.string(service.uuid), + primary: primary, + characteristics: service.characteristics + .map( + (c) => pigeon.PeripheralCharacteristic( + uuid: BleUuidParser.string(c.uuid), + properties: c.properties.map((e) => e.index).toList(), + // Attribute permissions are peripheral-only and optional. + permissions: const [], + descriptors: c.descriptors + .map( + (d) => pigeon.PeripheralDescriptor( + uuid: BleUuidParser.string(d.uuid), + value: null, + permissions: const [], + ), + ) + .toList(), + value: null, + ), + ) + .toList(), + ); + } + + static pigeon.PeripheralManufacturerData? toPigeonManufacturerData( + ManufacturerData? manufacturerData, + ) { + if (manufacturerData == null) return null; + return pigeon.PeripheralManufacturerData( + manufacturerId: manufacturerData.companyId, + data: manufacturerData.payload, + ); + } + + static PeripheralBondState fromPigeonBondState(pigeon.PeripheralBondState s) { + return switch (s) { + pigeon.PeripheralBondState.bonding => PeripheralBondState.bonding, + pigeon.PeripheralBondState.bonded => PeripheralBondState.bonded, + pigeon.PeripheralBondState.none => PeripheralBondState.none, + }; + } +} diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart new file mode 100644 index 00000000..a9d0f644 --- /dev/null +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -0,0 +1,198 @@ +import 'dart:async'; +import 'package:flutter/services.dart'; +import 'package:universal_ble/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart' + as pigeon; +import 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart'; +import 'package:universal_ble/universal_ble.dart'; + +class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform + implements pigeon.UniversalBlePeripheralCallback { + UniversalBlePeripheralPigeon._() { + pigeon.UniversalBlePeripheralCallback.setUp(this); + } + + static UniversalBlePeripheralPigeon? _instance; + static UniversalBlePeripheralPigeon get instance => + _instance ??= UniversalBlePeripheralPigeon._(); + + final pigeon.UniversalBlePeripheralChannel _channel = + pigeon.UniversalBlePeripheralChannel(); + final StreamController<({String serviceId, String? error})> + _serviceResultController = + StreamController<({String serviceId, String? error})>.broadcast(); + + @override + Future initialize() => _channel.initialize(); + + @override + Future isSupported() => _channel.isSupported(); + + @override + Future isAdvertising() async => + (await _channel.isAdvertising()) ?? false; + + @override + Future addService( + BleService service, { + bool primary = true, + Duration? timeout, + }) async { + final String serviceId = BleUuidParser.string(service.uuid); + final Completer completer = Completer(); + _serviceResultController.stream + .where((e) => BleUuidParser.compareStrings(e.serviceId, serviceId)) + .first + .timeout( + timeout ?? const Duration(seconds: 5), + onTimeout: () => + (serviceId: serviceId, error: 'Service add timed out'), + ) + .then((e) { + if (completer.isCompleted) return; + if (e.error != null) { + completer.completeError( + PlatformException(code: 'service-add-failed', message: e.error), + ); + } else { + completer.complete(); + } + }); + + await _channel.addService( + UniversalBlePeripheralMapper.toPigeonService(service, primary: primary), + ); + await completer.future; + } + + @override + Future removeService(String serviceId) => + _channel.removeService(BleUuidParser.string(serviceId)); + + @override + Future clearServices() => _channel.clearServices(); + + @override + Future> getServices() => _channel.getServices(); + + @override + Future startAdvertising({ + required List services, + String? localName, + int? timeout, + ManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse = false, + }) { + return _channel.startAdvertising( + services.map(BleUuidParser.string).toList(), + localName, + timeout, + UniversalBlePeripheralMapper.toPigeonManufacturerData(manufacturerData), + addManufacturerDataInScanResponse, + ); + } + + @override + Future stopAdvertising() => _channel.stopAdvertising(); + + @override + Future updateCharacteristic({ + required String characteristicId, + required Uint8List value, + String? deviceId, + }) { + return _channel.updateCharacteristic( + BleUuidParser.string(characteristicId), + value, + deviceId, + ); + } + + @override + void onAdvertisingStatusUpdate(bool advertising, String? error) { + super.advertisingStatusUpdateCallback?.call(advertising, error); + } + + @override + void onBleStateChange(bool state) { + super.bleStateChangeCallback?.call(state); + } + + @override + void onBondStateChange( + String deviceId, pigeon.PeripheralBondState bondState) { + super.bondStateChangeCallback?.call( + deviceId, + UniversalBlePeripheralMapper.fromPigeonBondState(bondState), + ); + } + + @override + void onCharacteristicSubscriptionChange( + String deviceId, + String characteristicId, + bool isSubscribed, + String? name, + ) { + super.subscriptionChangeCallback?.call( + deviceId, + characteristicId, + isSubscribed, + name, + ); + } + + @override + void onConnectionStateChange(String deviceId, bool connected) { + super.connectionStateChangeCallback?.call(deviceId, connected); + } + + @override + void onMtuChange(String deviceId, int mtu) { + super.mtuChangeCallback?.call(deviceId, mtu); + } + + @override + pigeon.PeripheralReadRequestResult? onReadRequest( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + ) { + final result = super + .readRequestCallback + ?.call(deviceId, characteristicId, offset, value); + if (result == null) return null; + return pigeon.PeripheralReadRequestResult( + value: result.value, + offset: result.offset, + status: result.status, + ); + } + + @override + void onServiceAdded(String serviceId, String? error) { + super.serviceAddedCallback?.call(serviceId, error); + _serviceResultController.add((serviceId: serviceId, error: error)); + } + + @override + pigeon.PeripheralWriteRequestResult? onWriteRequest( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + ) { + final result = super.writeRequestCallback?.call( + deviceId, + characteristicId, + offset, + value, + ); + if (result == null) return null; + return pigeon.PeripheralWriteRequestResult( + value: result.value, + offset: result.offset, + status: result.status, + ); + } +} diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart new file mode 100644 index 00000000..69e1e721 --- /dev/null +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -0,0 +1,144 @@ +import 'dart:typed_data'; + +import 'package:universal_ble/universal_ble.dart'; + +typedef OnPeripheralAdvertisingStatusUpdate = void Function( + bool advertising, String? error); +typedef OnPeripheralBleStateChange = void Function(bool enabled); +typedef OnPeripheralBondStateChange = void Function( + String deviceId, + PeripheralBondState state, +); +typedef OnPeripheralCharacteristicSubscriptionChange = void Function( + String deviceId, + String characteristicId, + bool isSubscribed, + String? name, +); +typedef OnPeripheralConnectionStateChange = void Function( + String deviceId, + bool connected, +); +typedef OnPeripheralReadRequest = BleReadRequestResult? Function( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, +); +typedef OnPeripheralServiceAdded = void Function( + String serviceId, String? error); +typedef OnPeripheralWriteRequest = BleWriteRequestResult? Function( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, +); +typedef OnPeripheralMtuChange = void Function(String deviceId, int mtu); + +enum PeripheralBondState { bonding, bonded, none } + +abstract class UniversalBlePeripheralPlatform { + OnPeripheralAdvertisingStatusUpdate? advertisingStatusUpdateCallback; + OnPeripheralBleStateChange? bleStateChangeCallback; + OnPeripheralBondStateChange? bondStateChangeCallback; + OnPeripheralCharacteristicSubscriptionChange? subscriptionChangeCallback; + OnPeripheralConnectionStateChange? connectionStateChangeCallback; + OnPeripheralReadRequest? readRequestCallback; + OnPeripheralServiceAdded? serviceAddedCallback; + OnPeripheralWriteRequest? writeRequestCallback; + OnPeripheralMtuChange? mtuChangeCallback; + + Future initialize(); + Future isSupported(); + Future isAdvertising(); + + Future addService( + BleService service, { + bool primary = true, + Duration? timeout, + }); + + Future removeService(String serviceId); + Future clearServices(); + Future> getServices(); + Future startAdvertising({ + required List services, + String? localName, + int? timeout, + ManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse = false, + }); + Future stopAdvertising(); + Future updateCharacteristic({ + required String characteristicId, + required Uint8List value, + String? deviceId, + }); +} + +class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { + UnsupportedError _notSupported() => + UnsupportedError('BLE peripheral mode is not supported on this platform'); + + @override + Future addService( + BleService service, { + bool primary = true, + Duration? timeout, + }) async { + throw _notSupported(); + } + + @override + Future clearServices() async { + throw _notSupported(); + } + + @override + Future> getServices() async { + throw _notSupported(); + } + + @override + Future initialize() async { + throw _notSupported(); + } + + @override + Future isAdvertising() async { + throw _notSupported(); + } + + @override + Future isSupported() async => false; + + @override + Future removeService(String serviceId) async { + throw _notSupported(); + } + + @override + Future startAdvertising({ + required List services, + String? localName, + int? timeout, + ManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse = false, + }) async { + throw _notSupported(); + } + + @override + Future stopAdvertising() async { + throw _notSupported(); + } + + @override + Future updateCharacteristic({ + required String characteristicId, + required Uint8List value, + String? deviceId, + }) async { + throw _notSupported(); + } +} diff --git a/lib/universal_ble.dart b/lib/universal_ble.dart index aaaeec66..a966d263 100644 --- a/lib/universal_ble.dart +++ b/lib/universal_ble.dart @@ -3,6 +3,8 @@ library; export 'package:universal_ble/src/universal_ble_exceptions.dart'; export 'package:universal_ble/src/universal_ble_platform_interface.dart'; export 'package:universal_ble/src/universal_ble.dart'; +export 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral.dart'; +export 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart'; export 'package:universal_ble/src/models/model_exports.dart'; export 'package:universal_ble/src/extensions/exports.dart'; export 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart' diff --git a/lib/universal_ble_peripheral.dart b/lib/universal_ble_peripheral.dart new file mode 100644 index 00000000..bd37d01c --- /dev/null +++ b/lib/universal_ble_peripheral.dart @@ -0,0 +1,5 @@ +library; + +export 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral.dart'; +export 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart'; +export 'package:universal_ble/src/models/peripheral/peripheral_exports.dart'; diff --git a/pigeon/universal_ble_peripheral.dart b/pigeon/universal_ble_peripheral.dart new file mode 100644 index 00000000..ea63613f --- /dev/null +++ b/pigeon/universal_ble_peripheral.dart @@ -0,0 +1,123 @@ +import 'package:pigeon/pigeon.dart'; + +// dart run pigeon --input pigeon/universal_ble_peripheral.dart +@ConfigurePigeon( + PigeonOptions( + dartPackageName: 'universal_ble', + dartOut: + 'lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart', + kotlinOut: + 'android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt', + swiftOut: 'darwin/Classes/UniversalBlePeripheral.g.swift', + kotlinOptions: KotlinOptions(package: 'com.navideck.universal_ble'), + cppOptions: CppOptions(namespace: 'universal_ble'), + cppHeaderOut: 'windows/src/generated/universal_ble_peripheral.g.h', + cppSourceOut: 'windows/src/generated/universal_ble_peripheral.g.cpp', + ), +) +enum PeripheralBondState { bonding, bonded, none } + +class PeripheralService { + String uuid; + bool primary; + List characteristics; + PeripheralService(this.uuid, this.primary, this.characteristics); +} + +class PeripheralCharacteristic { + String uuid; + List properties; + List permissions; + List? descriptors; + Uint8List? value; + + PeripheralCharacteristic( + this.uuid, + this.properties, + this.permissions, + this.descriptors, + this.value, + ); +} + +class PeripheralDescriptor { + String uuid; + Uint8List? value; + List? permissions; + PeripheralDescriptor(this.uuid, this.value, this.permissions); +} + +class PeripheralReadRequestResult { + Uint8List value; + int? offset; + int? status; + PeripheralReadRequestResult({required this.value, this.offset, this.status}); +} + +class PeripheralWriteRequestResult { + Uint8List? value; + int? offset; + int? status; + PeripheralWriteRequestResult({this.value, this.offset, this.status}); +} + +class PeripheralManufacturerData { + int manufacturerId; + Uint8List data; + PeripheralManufacturerData( + {required this.manufacturerId, required this.data}); +} + +@HostApi() +abstract class UniversalBlePeripheralChannel { + void initialize(); + bool? isAdvertising(); + bool isSupported(); + void stopAdvertising(); + void addService(PeripheralService service); + void removeService(String serviceId); + void clearServices(); + List getServices(); + void startAdvertising( + List services, + String? localName, + int? timeout, + PeripheralManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse, + ); + void updateCharacteristic( + String characteristicId, + Uint8List value, + String? deviceId, + ); +} + +@FlutterApi() +abstract class UniversalBlePeripheralCallback { + PeripheralReadRequestResult? onReadRequest( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + ); + + PeripheralWriteRequestResult? onWriteRequest( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + ); + + void onCharacteristicSubscriptionChange( + String deviceId, + String characteristicId, + bool isSubscribed, + String? name, + ); + void onAdvertisingStatusUpdate(bool advertising, String? error); + void onBleStateChange(bool state); + void onServiceAdded(String serviceId, String? error); + void onMtuChange(String deviceId, int mtu); + void onConnectionStateChange(String deviceId, bool connected); + void onBondStateChange(String deviceId, PeripheralBondState bondState); +} diff --git a/pubspec.yaml b/pubspec.yaml index 487daff9..e730795a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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: 1.3.0 +version: 2.0.0 homepage: https://navideck.com repository: https://github.com/Navideck/universal_ble issue_tracker: https://github.com/Navideck/universal_ble/issues diff --git a/test/universal_ble_peripheral_test.dart b/test/universal_ble_peripheral_test.dart new file mode 100644 index 00000000..33d34772 --- /dev/null +++ b/test/universal_ble_peripheral_test.dart @@ -0,0 +1,40 @@ +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:universal_ble/universal_ble.dart'; + +void main() { + test('peripheral request result models store values', () { + final read = BleReadRequestResult( + value: Uint8List.fromList([1, 2, 3]), + offset: 1, + status: 0, + ); + const write = BleWriteRequestResult(offset: 2, status: 0); + + expect(read.value, Uint8List.fromList([1, 2, 3])); + expect(read.offset, 1); + expect(read.status, 0); + expect(write.offset, 2); + expect(write.status, 0); + }); + + test('peripheral uses shared model types', () { + final service = BleService('180f', [ + BleCharacteristic( + '2a19', + [CharacteristicProperty.read, CharacteristicProperty.notify], + [BleDescriptor('2908')], + ), + ]); + + expect(service.uuid, BleUuidParser.string('180f')); + expect(service.characteristics.single.uuid, BleUuidParser.string('2a19')); + expect( + service.characteristics.single.properties.contains( + CharacteristicProperty.notify, + ), + true, + ); + }); +} diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 606812f9..5e8ca131 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -41,6 +41,8 @@ list(APPEND PLUGIN_SOURCES "src/ui_thread_handler.hpp" "src/generated/universal_ble.g.cpp" "src/generated/universal_ble.g.h" + "src/generated/universal_ble_peripheral.g.cpp" + "src/generated/universal_ble_peripheral.g.h" "src/pin_entry.h" "src/universal_ble_filter_util.cpp" "src/universal_ble_filter_util.h" diff --git a/windows/src/generated/universal_ble_peripheral.g.cpp b/windows/src/generated/universal_ble_peripheral.g.cpp new file mode 100644 index 00000000..a396cb6a --- /dev/null +++ b/windows/src/generated/universal_ble_peripheral.g.cpp @@ -0,0 +1,1093 @@ +// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#undef _HAS_EXCEPTIONS + +#include "universal_ble_peripheral.g.h" + +#include +#include +#include +#include + +#include +#include +#include + +namespace universal_ble { +using flutter::BasicMessageChannel; +using flutter::CustomEncodableValue; +using flutter::EncodableList; +using flutter::EncodableMap; +using flutter::EncodableValue; + +FlutterError CreateConnectionError(const std::string channel_name) { + return FlutterError( + "channel-error", + "Unable to establish connection on channel: '" + channel_name + "'.", + EncodableValue("")); +} + +// PeripheralService + +PeripheralService::PeripheralService( + const std::string& uuid, + bool primary, + const EncodableList& characteristics) + : uuid_(uuid), + primary_(primary), + characteristics_(characteristics) {} + +const std::string& PeripheralService::uuid() const { + return uuid_; +} + +void PeripheralService::set_uuid(std::string_view value_arg) { + uuid_ = value_arg; +} + + +bool PeripheralService::primary() const { + return primary_; +} + +void PeripheralService::set_primary(bool value_arg) { + primary_ = value_arg; +} + + +const EncodableList& PeripheralService::characteristics() const { + return characteristics_; +} + +void PeripheralService::set_characteristics(const EncodableList& value_arg) { + characteristics_ = value_arg; +} + + +EncodableList PeripheralService::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(EncodableValue(uuid_)); + list.push_back(EncodableValue(primary_)); + list.push_back(EncodableValue(characteristics_)); + return list; +} + +PeripheralService PeripheralService::FromEncodableList(const EncodableList& list) { + PeripheralService decoded( + std::get(list[0]), + std::get(list[1]), + std::get(list[2])); + return decoded; +} + +// PeripheralCharacteristic + +PeripheralCharacteristic::PeripheralCharacteristic( + const std::string& uuid, + const EncodableList& properties, + const EncodableList& permissions) + : uuid_(uuid), + properties_(properties), + permissions_(permissions) {} + +PeripheralCharacteristic::PeripheralCharacteristic( + const std::string& uuid, + const EncodableList& properties, + const EncodableList& permissions, + const EncodableList* descriptors, + const std::vector* value) + : uuid_(uuid), + properties_(properties), + permissions_(permissions), + descriptors_(descriptors ? std::optional(*descriptors) : std::nullopt), + value_(value ? std::optional>(*value) : std::nullopt) {} + +const std::string& PeripheralCharacteristic::uuid() const { + return uuid_; +} + +void PeripheralCharacteristic::set_uuid(std::string_view value_arg) { + uuid_ = value_arg; +} + + +const EncodableList& PeripheralCharacteristic::properties() const { + return properties_; +} + +void PeripheralCharacteristic::set_properties(const EncodableList& value_arg) { + properties_ = value_arg; +} + + +const EncodableList& PeripheralCharacteristic::permissions() const { + return permissions_; +} + +void PeripheralCharacteristic::set_permissions(const EncodableList& value_arg) { + permissions_ = value_arg; +} + + +const EncodableList* PeripheralCharacteristic::descriptors() const { + return descriptors_ ? &(*descriptors_) : nullptr; +} + +void PeripheralCharacteristic::set_descriptors(const EncodableList* value_arg) { + descriptors_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralCharacteristic::set_descriptors(const EncodableList& value_arg) { + descriptors_ = value_arg; +} + + +const std::vector* PeripheralCharacteristic::value() const { + return value_ ? &(*value_) : nullptr; +} + +void PeripheralCharacteristic::set_value(const std::vector* value_arg) { + value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; +} + +void PeripheralCharacteristic::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +EncodableList PeripheralCharacteristic::ToEncodableList() const { + EncodableList list; + list.reserve(5); + list.push_back(EncodableValue(uuid_)); + list.push_back(EncodableValue(properties_)); + list.push_back(EncodableValue(permissions_)); + list.push_back(descriptors_ ? EncodableValue(*descriptors_) : EncodableValue()); + list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + return list; +} + +PeripheralCharacteristic PeripheralCharacteristic::FromEncodableList(const EncodableList& list) { + PeripheralCharacteristic decoded( + std::get(list[0]), + std::get(list[1]), + std::get(list[2])); + auto& encodable_descriptors = list[3]; + if (!encodable_descriptors.IsNull()) { + decoded.set_descriptors(std::get(encodable_descriptors)); + } + auto& encodable_value = list[4]; + if (!encodable_value.IsNull()) { + decoded.set_value(std::get>(encodable_value)); + } + return decoded; +} + +// PeripheralDescriptor + +PeripheralDescriptor::PeripheralDescriptor(const std::string& uuid) + : uuid_(uuid) {} + +PeripheralDescriptor::PeripheralDescriptor( + const std::string& uuid, + const std::vector* value, + const EncodableList* permissions) + : uuid_(uuid), + value_(value ? std::optional>(*value) : std::nullopt), + permissions_(permissions ? std::optional(*permissions) : std::nullopt) {} + +const std::string& PeripheralDescriptor::uuid() const { + return uuid_; +} + +void PeripheralDescriptor::set_uuid(std::string_view value_arg) { + uuid_ = value_arg; +} + + +const std::vector* PeripheralDescriptor::value() const { + return value_ ? &(*value_) : nullptr; +} + +void PeripheralDescriptor::set_value(const std::vector* value_arg) { + value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; +} + +void PeripheralDescriptor::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +const EncodableList* PeripheralDescriptor::permissions() const { + return permissions_ ? &(*permissions_) : nullptr; +} + +void PeripheralDescriptor::set_permissions(const EncodableList* value_arg) { + permissions_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralDescriptor::set_permissions(const EncodableList& value_arg) { + permissions_ = value_arg; +} + + +EncodableList PeripheralDescriptor::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(EncodableValue(uuid_)); + list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + list.push_back(permissions_ ? EncodableValue(*permissions_) : EncodableValue()); + return list; +} + +PeripheralDescriptor PeripheralDescriptor::FromEncodableList(const EncodableList& list) { + PeripheralDescriptor decoded( + std::get(list[0])); + auto& encodable_value = list[1]; + if (!encodable_value.IsNull()) { + decoded.set_value(std::get>(encodable_value)); + } + auto& encodable_permissions = list[2]; + if (!encodable_permissions.IsNull()) { + decoded.set_permissions(std::get(encodable_permissions)); + } + return decoded; +} + +// PeripheralReadRequestResult + +PeripheralReadRequestResult::PeripheralReadRequestResult(const std::vector& value) + : value_(value) {} + +PeripheralReadRequestResult::PeripheralReadRequestResult( + const std::vector& value, + const int64_t* offset, + const int64_t* status) + : value_(value), + offset_(offset ? std::optional(*offset) : std::nullopt), + status_(status ? std::optional(*status) : std::nullopt) {} + +const std::vector& PeripheralReadRequestResult::value() const { + return value_; +} + +void PeripheralReadRequestResult::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +const int64_t* PeripheralReadRequestResult::offset() const { + return offset_ ? &(*offset_) : nullptr; +} + +void PeripheralReadRequestResult::set_offset(const int64_t* value_arg) { + offset_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralReadRequestResult::set_offset(int64_t value_arg) { + offset_ = value_arg; +} + + +const int64_t* PeripheralReadRequestResult::status() const { + return status_ ? &(*status_) : nullptr; +} + +void PeripheralReadRequestResult::set_status(const int64_t* value_arg) { + status_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralReadRequestResult::set_status(int64_t value_arg) { + status_ = value_arg; +} + + +EncodableList PeripheralReadRequestResult::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(EncodableValue(value_)); + list.push_back(offset_ ? EncodableValue(*offset_) : EncodableValue()); + list.push_back(status_ ? EncodableValue(*status_) : EncodableValue()); + return list; +} + +PeripheralReadRequestResult PeripheralReadRequestResult::FromEncodableList(const EncodableList& list) { + PeripheralReadRequestResult decoded( + std::get>(list[0])); + auto& encodable_offset = list[1]; + if (!encodable_offset.IsNull()) { + decoded.set_offset(std::get(encodable_offset)); + } + auto& encodable_status = list[2]; + if (!encodable_status.IsNull()) { + decoded.set_status(std::get(encodable_status)); + } + return decoded; +} + +// PeripheralWriteRequestResult + +PeripheralWriteRequestResult::PeripheralWriteRequestResult() {} + +PeripheralWriteRequestResult::PeripheralWriteRequestResult( + const std::vector* value, + const int64_t* offset, + const int64_t* status) + : value_(value ? std::optional>(*value) : std::nullopt), + offset_(offset ? std::optional(*offset) : std::nullopt), + status_(status ? std::optional(*status) : std::nullopt) {} + +const std::vector* PeripheralWriteRequestResult::value() const { + return value_ ? &(*value_) : nullptr; +} + +void PeripheralWriteRequestResult::set_value(const std::vector* value_arg) { + value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; +} + +void PeripheralWriteRequestResult::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +const int64_t* PeripheralWriteRequestResult::offset() const { + return offset_ ? &(*offset_) : nullptr; +} + +void PeripheralWriteRequestResult::set_offset(const int64_t* value_arg) { + offset_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralWriteRequestResult::set_offset(int64_t value_arg) { + offset_ = value_arg; +} + + +const int64_t* PeripheralWriteRequestResult::status() const { + return status_ ? &(*status_) : nullptr; +} + +void PeripheralWriteRequestResult::set_status(const int64_t* value_arg) { + status_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralWriteRequestResult::set_status(int64_t value_arg) { + status_ = value_arg; +} + + +EncodableList PeripheralWriteRequestResult::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + list.push_back(offset_ ? EncodableValue(*offset_) : EncodableValue()); + list.push_back(status_ ? EncodableValue(*status_) : EncodableValue()); + return list; +} + +PeripheralWriteRequestResult PeripheralWriteRequestResult::FromEncodableList(const EncodableList& list) { + PeripheralWriteRequestResult decoded; + auto& encodable_value = list[0]; + if (!encodable_value.IsNull()) { + decoded.set_value(std::get>(encodable_value)); + } + auto& encodable_offset = list[1]; + if (!encodable_offset.IsNull()) { + decoded.set_offset(std::get(encodable_offset)); + } + auto& encodable_status = list[2]; + if (!encodable_status.IsNull()) { + decoded.set_status(std::get(encodable_status)); + } + return decoded; +} + +// PeripheralManufacturerData + +PeripheralManufacturerData::PeripheralManufacturerData( + int64_t manufacturer_id, + const std::vector& data) + : manufacturer_id_(manufacturer_id), + data_(data) {} + +int64_t PeripheralManufacturerData::manufacturer_id() const { + return manufacturer_id_; +} + +void PeripheralManufacturerData::set_manufacturer_id(int64_t value_arg) { + manufacturer_id_ = value_arg; +} + + +const std::vector& PeripheralManufacturerData::data() const { + return data_; +} + +void PeripheralManufacturerData::set_data(const std::vector& value_arg) { + data_ = value_arg; +} + + +EncodableList PeripheralManufacturerData::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(EncodableValue(manufacturer_id_)); + list.push_back(EncodableValue(data_)); + return list; +} + +PeripheralManufacturerData PeripheralManufacturerData::FromEncodableList(const EncodableList& list) { + PeripheralManufacturerData decoded( + std::get(list[0]), + std::get>(list[1])); + return decoded; +} + + +PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} + +EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( + uint8_t type, + flutter::ByteStreamReader* stream) const { + switch (type) { + case 129: { + 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(enum_arg_value)); + } + case 130: { + return CustomEncodableValue(PeripheralService::FromEncodableList(std::get(ReadValue(stream)))); + } + case 131: { + return CustomEncodableValue(PeripheralCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); + } + case 132: { + return CustomEncodableValue(PeripheralDescriptor::FromEncodableList(std::get(ReadValue(stream)))); + } + case 133: { + return CustomEncodableValue(PeripheralReadRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + } + case 134: { + return CustomEncodableValue(PeripheralWriteRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + } + case 135: { + return CustomEncodableValue(PeripheralManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); + } + default: + return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + } +} + +void PigeonInternalCodecSerializer::WriteValue( + const EncodableValue& value, + flutter::ByteStreamWriter* stream) const { + if (const CustomEncodableValue* custom_value = std::get_if(&value)) { + if (custom_value->type() == typeid(PeripheralBondState)) { + stream->WriteByte(129); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(PeripheralService)) { + stream->WriteByte(130); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralCharacteristic)) { + stream->WriteByte(131); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralDescriptor)) { + stream->WriteByte(132); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralReadRequestResult)) { + stream->WriteByte(133); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralWriteRequestResult)) { + stream->WriteByte(134); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralManufacturerData)) { + stream->WriteByte(135); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + } + flutter::StandardCodecSerializer::WriteValue(value, stream); +} + +/// The codec used by UniversalBlePeripheralChannel. +const flutter::StandardMessageCodec& UniversalBlePeripheralChannel::GetCodec() { + return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +} + +// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. +void UniversalBlePeripheralChannel::SetUp( + flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api) { + UniversalBlePeripheralChannel::SetUp(binary_messenger, api, ""); +} + +void UniversalBlePeripheralChannel::SetUp( + flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api, + const std::string& message_channel_suffix) { + const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + std::optional output = api->Initialize(); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + ErrorOr> output = api->IsAdvertising(); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back(EncodableValue(std::move(output_optional).value())); + } else { + wrapped.push_back(EncodableValue()); + } + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + ErrorOr output = api->IsSupported(); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + std::optional output = api->StopAdvertising(); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_service_arg = args.at(0); + if (encodable_service_arg.IsNull()) { + reply(WrapError("service_arg unexpectedly null.")); + return; + } + const auto& service_arg = std::any_cast(std::get(encodable_service_arg)); + std::optional output = api->AddService(service_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_service_id_arg = args.at(0); + if (encodable_service_id_arg.IsNull()) { + reply(WrapError("service_id_arg unexpectedly null.")); + return; + } + const auto& service_id_arg = std::get(encodable_service_id_arg); + std::optional output = api->RemoveService(service_id_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + std::optional output = api->ClearServices(); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + ErrorOr output = api->GetServices(); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_services_arg = args.at(0); + if (encodable_services_arg.IsNull()) { + reply(WrapError("services_arg unexpectedly null.")); + return; + } + const auto& services_arg = std::get(encodable_services_arg); + const auto& encodable_local_name_arg = args.at(1); + const auto* local_name_arg = std::get_if(&encodable_local_name_arg); + const auto& encodable_timeout_arg = args.at(2); + const auto* timeout_arg = std::get_if(&encodable_timeout_arg); + const auto& encodable_manufacturer_data_arg = args.at(3); + const auto* manufacturer_data_arg = encodable_manufacturer_data_arg.IsNull() ? nullptr : &(std::any_cast(std::get(encodable_manufacturer_data_arg))); + const auto& encodable_add_manufacturer_data_in_scan_response_arg = args.at(4); + if (encodable_add_manufacturer_data_in_scan_response_arg.IsNull()) { + reply(WrapError("add_manufacturer_data_in_scan_response_arg unexpectedly null.")); + return; + } + const auto& add_manufacturer_data_in_scan_response_arg = std::get(encodable_add_manufacturer_data_in_scan_response_arg); + std::optional output = api->StartAdvertising(services_arg, local_name_arg, timeout_arg, manufacturer_data_arg, add_manufacturer_data_in_scan_response_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_characteristic_id_arg = args.at(0); + if (encodable_characteristic_id_arg.IsNull()) { + reply(WrapError("characteristic_id_arg unexpectedly null.")); + return; + } + const auto& characteristic_id_arg = std::get(encodable_characteristic_id_arg); + const auto& encodable_value_arg = args.at(1); + if (encodable_value_arg.IsNull()) { + reply(WrapError("value_arg unexpectedly null.")); + return; + } + const auto& value_arg = std::get>(encodable_value_arg); + const auto& encodable_device_id_arg = args.at(2); + const auto* device_id_arg = std::get_if(&encodable_device_id_arg); + std::optional output = api->UpdateCharacteristic(characteristic_id_arg, value_arg, device_id_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } +} + +EncodableValue UniversalBlePeripheralChannel::WrapError(std::string_view error_message) { + return EncodableValue(EncodableList{ + EncodableValue(std::string(error_message)), + EncodableValue("Error"), + EncodableValue() + }); +} + +EncodableValue UniversalBlePeripheralChannel::WrapError(const FlutterError& error) { + return EncodableValue(EncodableList{ + EncodableValue(error.code()), + EncodableValue(error.message()), + error.details() + }); +} + +// Generated class from Pigeon that represents Flutter messages that can be called from C++. +UniversalBlePeripheralCallback::UniversalBlePeripheralCallback(flutter::BinaryMessenger* binary_messenger) + : binary_messenger_(binary_messenger), + message_channel_suffix_("") {} + +UniversalBlePeripheralCallback::UniversalBlePeripheralCallback( + flutter::BinaryMessenger* binary_messenger, + const std::string& message_channel_suffix) + : binary_messenger_(binary_messenger), + message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} + +const flutter::StandardMessageCodec& UniversalBlePeripheralCallback::GetCodec() { + return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +} + +void UniversalBlePeripheralCallback::OnReadRequest( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + int64_t offset_arg, + const std::vector* value_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(offset_arg), + value_arg ? EncodableValue(*value_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); + on_success(return_value); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnWriteRequest( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + int64_t offset_arg, + const std::vector* value_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(offset_arg), + value_arg ? EncodableValue(*value_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); + on_success(return_value); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnCharacteristicSubscriptionChange( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + bool is_subscribed_arg, + const std::string* name_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(is_subscribed_arg), + name_arg ? EncodableValue(*name_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnAdvertisingStatusUpdate( + bool advertising_arg, + const std::string* error_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(advertising_arg), + error_arg ? EncodableValue(*error_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnBleStateChange( + bool state_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(state_arg), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnServiceAdded( + const std::string& service_id_arg, + const std::string* error_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(service_id_arg), + error_arg ? EncodableValue(*error_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnMtuChange( + const std::string& device_id_arg, + int64_t mtu_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(mtu_arg), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnConnectionStateChange( + const std::string& device_id_arg, + bool connected_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(connected_arg), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnBondStateChange( + const std::string& device_id_arg, + const PeripheralBondState& bond_state_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + CustomEncodableValue(bond_state_arg), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +} // namespace universal_ble diff --git a/windows/src/generated/universal_ble_peripheral.g.h b/windows/src/generated/universal_ble_peripheral.g.h new file mode 100644 index 00000000..6a5a8660 --- /dev/null +++ b/windows/src/generated/universal_ble_peripheral.g.h @@ -0,0 +1,397 @@ +// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#ifndef PIGEON_UNIVERSAL_BLE_PERIPHERAL_G_H_ +#define PIGEON_UNIVERSAL_BLE_PERIPHERAL_G_H_ +#include +#include +#include +#include + +#include +#include +#include + +namespace universal_ble { + + +// Generated class from Pigeon. + +class FlutterError { + public: + explicit FlutterError(const std::string& code) + : code_(code) {} + explicit FlutterError(const std::string& code, const std::string& message) + : code_(code), message_(message) {} + explicit FlutterError(const std::string& code, const std::string& message, const flutter::EncodableValue& details) + : code_(code), message_(message), details_(details) {} + + const std::string& code() const { return code_; } + const std::string& message() const { return message_; } + const flutter::EncodableValue& details() const { return details_; } + + private: + std::string code_; + std::string message_; + flutter::EncodableValue details_; +}; + +template class ErrorOr { + public: + ErrorOr(const T& rhs) : v_(rhs) {} + ErrorOr(const T&& rhs) : v_(std::move(rhs)) {} + ErrorOr(const FlutterError& rhs) : v_(rhs) {} + ErrorOr(const FlutterError&& rhs) : v_(std::move(rhs)) {} + + bool has_error() const { return std::holds_alternative(v_); } + const T& value() const { return std::get(v_); }; + const FlutterError& error() const { return std::get(v_); }; + + private: + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + ErrorOr() = default; + T TakeValue() && { return std::get(std::move(v_)); } + + std::variant v_; +}; + + +enum class PeripheralBondState { + kBonding = 0, + kBonded = 1, + kNone = 2 +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralService { + public: + // Constructs an object setting all fields. + explicit PeripheralService( + const std::string& uuid, + bool primary, + const flutter::EncodableList& characteristics); + + const std::string& uuid() const; + void set_uuid(std::string_view value_arg); + + bool primary() const; + void set_primary(bool value_arg); + + const flutter::EncodableList& characteristics() const; + void set_characteristics(const flutter::EncodableList& value_arg); + + private: + static PeripheralService FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::string uuid_; + bool primary_; + flutter::EncodableList characteristics_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralCharacteristic { + public: + // Constructs an object setting all non-nullable fields. + explicit PeripheralCharacteristic( + const std::string& uuid, + const flutter::EncodableList& properties, + const flutter::EncodableList& permissions); + + // Constructs an object setting all fields. + explicit PeripheralCharacteristic( + const std::string& uuid, + const flutter::EncodableList& properties, + const flutter::EncodableList& permissions, + const flutter::EncodableList* descriptors, + const std::vector* value); + + const std::string& uuid() const; + void set_uuid(std::string_view value_arg); + + const flutter::EncodableList& properties() const; + void set_properties(const flutter::EncodableList& value_arg); + + const flutter::EncodableList& permissions() const; + void set_permissions(const flutter::EncodableList& value_arg); + + const flutter::EncodableList* descriptors() const; + void set_descriptors(const flutter::EncodableList* value_arg); + void set_descriptors(const flutter::EncodableList& value_arg); + + const std::vector* value() const; + void set_value(const std::vector* value_arg); + void set_value(const std::vector& value_arg); + + private: + static PeripheralCharacteristic FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::string uuid_; + flutter::EncodableList properties_; + flutter::EncodableList permissions_; + std::optional descriptors_; + std::optional> value_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralDescriptor { + public: + // Constructs an object setting all non-nullable fields. + explicit PeripheralDescriptor(const std::string& uuid); + + // Constructs an object setting all fields. + explicit PeripheralDescriptor( + const std::string& uuid, + const std::vector* value, + const flutter::EncodableList* permissions); + + const std::string& uuid() const; + void set_uuid(std::string_view value_arg); + + const std::vector* value() const; + void set_value(const std::vector* value_arg); + void set_value(const std::vector& value_arg); + + const flutter::EncodableList* permissions() const; + void set_permissions(const flutter::EncodableList* value_arg); + void set_permissions(const flutter::EncodableList& value_arg); + + private: + static PeripheralDescriptor FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::string uuid_; + std::optional> value_; + std::optional permissions_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralReadRequestResult { + public: + // Constructs an object setting all non-nullable fields. + explicit PeripheralReadRequestResult(const std::vector& value); + + // Constructs an object setting all fields. + explicit PeripheralReadRequestResult( + const std::vector& value, + const int64_t* offset, + const int64_t* status); + + const std::vector& value() const; + void set_value(const std::vector& value_arg); + + const int64_t* offset() const; + void set_offset(const int64_t* value_arg); + void set_offset(int64_t value_arg); + + const int64_t* status() const; + void set_status(const int64_t* value_arg); + void set_status(int64_t value_arg); + + private: + static PeripheralReadRequestResult FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::vector value_; + std::optional offset_; + std::optional status_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralWriteRequestResult { + public: + // Constructs an object setting all non-nullable fields. + PeripheralWriteRequestResult(); + + // Constructs an object setting all fields. + explicit PeripheralWriteRequestResult( + const std::vector* value, + const int64_t* offset, + const int64_t* status); + + const std::vector* value() const; + void set_value(const std::vector* value_arg); + void set_value(const std::vector& value_arg); + + const int64_t* offset() const; + void set_offset(const int64_t* value_arg); + void set_offset(int64_t value_arg); + + const int64_t* status() const; + void set_status(const int64_t* value_arg); + void set_status(int64_t value_arg); + + private: + static PeripheralWriteRequestResult FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::optional> value_; + std::optional offset_; + std::optional status_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralManufacturerData { + public: + // Constructs an object setting all fields. + explicit PeripheralManufacturerData( + int64_t manufacturer_id, + const std::vector& data); + + int64_t manufacturer_id() const; + void set_manufacturer_id(int64_t value_arg); + + const std::vector& data() const; + void set_data(const std::vector& value_arg); + + private: + static PeripheralManufacturerData FromEncodableList(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + int64_t manufacturer_id_; + std::vector data_; +}; + + +class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { + public: + PigeonInternalCodecSerializer(); + inline static PigeonInternalCodecSerializer& GetInstance() { + static PigeonInternalCodecSerializer sInstance; + return sInstance; + } + + void WriteValue( + const flutter::EncodableValue& value, + flutter::ByteStreamWriter* stream) const override; + protected: + flutter::EncodableValue ReadValueOfType( + uint8_t type, + flutter::ByteStreamReader* stream) const override; +}; + +// Generated interface from Pigeon that represents a handler of messages from Flutter. +class UniversalBlePeripheralChannel { + public: + UniversalBlePeripheralChannel(const UniversalBlePeripheralChannel&) = delete; + UniversalBlePeripheralChannel& operator=(const UniversalBlePeripheralChannel&) = delete; + virtual ~UniversalBlePeripheralChannel() {} + virtual std::optional Initialize() = 0; + virtual ErrorOr> IsAdvertising() = 0; + virtual ErrorOr IsSupported() = 0; + virtual std::optional StopAdvertising() = 0; + virtual std::optional AddService(const PeripheralService& service) = 0; + virtual std::optional RemoveService(const std::string& service_id) = 0; + virtual std::optional ClearServices() = 0; + virtual ErrorOr GetServices() = 0; + virtual std::optional StartAdvertising( + const flutter::EncodableList& services, + const std::string* local_name, + const int64_t* timeout, + const PeripheralManufacturerData* manufacturer_data, + bool add_manufacturer_data_in_scan_response) = 0; + virtual std::optional UpdateCharacteristic( + const std::string& characteristic_id, + const std::vector& value, + const std::string* device_id) = 0; + + // The codec used by UniversalBlePeripheralChannel. + static const flutter::StandardMessageCodec& GetCodec(); + // Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. + static void SetUp( + flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api); + static void SetUp( + flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api, + const std::string& message_channel_suffix); + static flutter::EncodableValue WrapError(std::string_view error_message); + static flutter::EncodableValue WrapError(const FlutterError& error); + protected: + UniversalBlePeripheralChannel() = default; +}; +// Generated class from Pigeon that represents Flutter messages that can be called from C++. +class UniversalBlePeripheralCallback { + public: + UniversalBlePeripheralCallback(flutter::BinaryMessenger* binary_messenger); + UniversalBlePeripheralCallback( + flutter::BinaryMessenger* binary_messenger, + const std::string& message_channel_suffix); + static const flutter::StandardMessageCodec& GetCodec(); + void OnReadRequest( + const std::string& device_id, + const std::string& characteristic_id, + int64_t offset, + const std::vector* value, + std::function&& on_success, + std::function&& on_error); + void OnWriteRequest( + const std::string& device_id, + const std::string& characteristic_id, + int64_t offset, + const std::vector* value, + std::function&& on_success, + std::function&& on_error); + void OnCharacteristicSubscriptionChange( + const std::string& device_id, + const std::string& characteristic_id, + bool is_subscribed, + const std::string* name, + std::function&& on_success, + std::function&& on_error); + void OnAdvertisingStatusUpdate( + bool advertising, + const std::string* error, + std::function&& on_success, + std::function&& on_error); + void OnBleStateChange( + bool state, + std::function&& on_success, + std::function&& on_error); + void OnServiceAdded( + const std::string& service_id, + const std::string* error, + std::function&& on_success, + std::function&& on_error); + void OnMtuChange( + const std::string& device_id, + int64_t mtu, + std::function&& on_success, + std::function&& on_error); + void OnConnectionStateChange( + const std::string& device_id, + bool connected, + std::function&& on_success, + std::function&& on_error); + void OnBondStateChange( + const std::string& device_id, + const PeripheralBondState& bond_state, + std::function&& on_success, + std::function&& on_error); + private: + flutter::BinaryMessenger* binary_messenger_; + std::string message_channel_suffix_; +}; + +} // namespace universal_ble +#endif // PIGEON_UNIVERSAL_BLE_PERIPHERAL_G_H_ diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index 3bf1c2e1..413602f8 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -14,6 +14,7 @@ #include "enum_parser.h" #include "generated/universal_ble.g.h" +#include "generated/universal_ble_peripheral.g.h" #include "helper/universal_ble_logger.h" #include "helper/universal_enum.h" #include "helper/utils.h" @@ -39,6 +40,7 @@ void UniversalBlePlugin::RegisterWithRegistrar( flutter::PluginRegistrarWindows *registrar) { auto plugin = std::make_unique(registrar); SetUp(registrar->messenger(), plugin.get()); + UniversalBlePeripheralChannel::SetUp(registrar->messenger(), plugin.get()); callback_channel = std::make_unique(registrar->messenger()); registrar->AddPlugin(std::move(plugin)); @@ -46,11 +48,16 @@ void UniversalBlePlugin::RegisterWithRegistrar( UniversalBlePlugin::UniversalBlePlugin( flutter::PluginRegistrarWindows *registrar) - : ui_thread_handler_(registrar) { + : registrar_(registrar), ui_thread_handler_(registrar) { + peripheral_callback_channel_ = + std::make_unique(registrar->messenger()); InitializeAsync(); } -UniversalBlePlugin::~UniversalBlePlugin() = default; +UniversalBlePlugin::~UniversalBlePlugin() { + ClearServices(); + peripheral_callback_channel_.reset(); +} // UniversalBlePlatformChannel implementation. void UniversalBlePlugin::GetBluetoothAvailabilityState( @@ -1613,4 +1620,625 @@ void UniversalBlePlugin::GattCharacteristicValueChanged( } } +std::optional UniversalBlePlugin::Initialize() { + if (!bluetooth_radio_) { + return create_flutter_error(UniversalBleErrorCode::kBluetoothNotAvailable, + "Bluetooth is not available"); + } + return std::nullopt; +} + +ErrorOr> UniversalBlePlugin::IsAdvertising() { + std::lock_guard lock(peripheral_mutex_); + if (peripheral_service_provider_map_.empty()) { + return std::optional(false); + } + return std::optional(AreAllPeripheralServicesStarted()); +} + +ErrorOr UniversalBlePlugin::IsSupported() { return bluetooth_radio_ != nullptr; } + +std::optional UniversalBlePlugin::StopAdvertising() { + std::lock_guard lock(peripheral_mutex_); + for (auto const &[key, provider] : peripheral_service_provider_map_) { + try { + provider->obj.StopAdvertising(); + } catch (...) { + } + } + ui_thread_handler_.Post([this] { + peripheral_callback_channel_->OnAdvertisingStatusUpdate( + false, nullptr, SuccessCallback, ErrorCallback); + }); + return std::nullopt; +} + +std::optional UniversalBlePlugin::AddService( + const PeripheralService &service) { + PeripheralAddServiceAsync(service); + return std::nullopt; +} + +std::optional UniversalBlePlugin::RemoveService( + const std::string &service_id) { + std::lock_guard lock(peripheral_mutex_); + const std::string service_id_lc = to_lower_case(service_id); + const auto it = peripheral_service_provider_map_.find(service_id_lc); + if (it == peripheral_service_provider_map_.end()) { + return FlutterError("not-found", "Service not found", nullptr); + } + DisposePeripheralServiceProvider(it->second.get()); + peripheral_service_provider_map_.erase(it); + return std::nullopt; +} + +std::optional UniversalBlePlugin::ClearServices() { + std::lock_guard lock(peripheral_mutex_); + for (auto const &[_, provider] : peripheral_service_provider_map_) { + DisposePeripheralServiceProvider(provider.get()); + } + peripheral_service_provider_map_.clear(); + return std::nullopt; +} + +ErrorOr UniversalBlePlugin::GetServices() { + std::lock_guard lock(peripheral_mutex_); + flutter::EncodableList services; + for (auto const &[key, _] : peripheral_service_provider_map_) { + services.emplace_back(key); + } + return services; +} + +std::optional UniversalBlePlugin::StartAdvertising( + const flutter::EncodableList &services, const std::string *local_name, + const int64_t *timeout, + const PeripheralManufacturerData *manufacturer_data, + bool add_manufacturer_data_in_scan_response) { + std::lock_guard lock(peripheral_mutex_); + if (peripheral_service_provider_map_.empty()) { + return FlutterError("failed", "No services added to advertise", nullptr); + } + try { + auto params = GattServiceProviderAdvertisingParameters(); + params.IsDiscoverable(true); + params.IsConnectable(true); + for (auto const &[key, provider] : peripheral_service_provider_map_) { + if (provider->obj.AdvertisementStatus() != + GattServiceProviderAdvertisementStatus::Started) { + provider->obj.StartAdvertising(params); + } + } + return std::nullopt; + } catch (...) { + return FlutterError("failed", "Failed to start advertising", nullptr); + } +} + +std::optional UniversalBlePlugin::UpdateCharacteristic( + const std::string &characteristic_id, const std::vector &value, + const std::string *device_id) { + std::lock_guard lock(peripheral_mutex_); + bool ambiguous_match = false; + auto *characteristic_object = + FindPeripheralGattCharacteristicObject(characteristic_id, &ambiguous_match); + if (ambiguous_match) { + return FlutterError( + "ambiguous-characteristic", + "Characteristic UUID exists in multiple services; cannot update uniquely", + nullptr); + } + if (characteristic_object == nullptr) { + return FlutterError("not-found", "Characteristic not found", nullptr); + } + IBuffer bytes = from_bytevc(value); + DataWriter writer; + writer.ByteOrder(ByteOrder::LittleEndian); + writer.WriteBuffer(bytes); + characteristic_object->obj.NotifyValueAsync(writer.DetachBuffer()); + return std::nullopt; +} + +fire_and_forget +UniversalBlePlugin::PeripheralAddServiceAsync(const PeripheralService &service) { + const auto service_uuid = service.uuid(); + try { + auto service_provider_result = + co_await GattServiceProvider::CreateAsync(uuid_to_guid(service_uuid)); + if (service_provider_result.Error() != BluetoothError::Success) { + auto err = std::string("Failed to create service provider: ") + service_uuid + + ", error: " + + ParsePeripheralBluetoothError(service_provider_result.Error()); + ui_thread_handler_.Post([this, service_uuid, err] { + peripheral_callback_channel_->OnServiceAdded(service_uuid, &err, + SuccessCallback, + ErrorCallback); + }); + co_return; + } + + GattServiceProvider service_provider = service_provider_result.ServiceProvider(); + auto service_provider_object = + std::make_unique(); + service_provider_object->obj = service_provider; + + const auto characteristics = service.characteristics(); + for (auto characteristic_encoded : characteristics) { + PeripheralCharacteristic characteristic = + std::any_cast( + std::get(characteristic_encoded)); + auto params = GattLocalCharacteristicParameters(); + const auto characteristic_uuid = characteristic.uuid(); + for (auto property_encoded : characteristic.properties()) { + int property = static_cast(std::get(property_encoded)); + params.CharacteristicProperties( + params.CharacteristicProperties() | + ToPeripheralGattCharacteristicProperties(property)); + } + for (auto permission_encoded : characteristic.permissions()) { + int permission = static_cast(std::get(permission_encoded)); + switch (ToPeripheralBlePermission(permission)) { + case PeripheralBlePermission::readable: + params.ReadProtectionLevel(GattProtectionLevel::Plain); + break; + case PeripheralBlePermission::writeable: + params.WriteProtectionLevel(GattProtectionLevel::Plain); + break; + case PeripheralBlePermission::readEncryptionRequired: + params.ReadProtectionLevel(GattProtectionLevel::EncryptionRequired); + break; + case PeripheralBlePermission::writeEncryptionRequired: + params.WriteProtectionLevel(GattProtectionLevel::EncryptionRequired); + break; + default: + break; + } + } + if (characteristic.value() != nullptr) { + params.StaticValue(from_bytevc(*characteristic.value())); + } + + auto characteristic_result = + co_await service_provider.Service().CreateCharacteristicAsync( + uuid_to_guid(characteristic_uuid), params); + if (characteristic_result.Error() != BluetoothError::Success) { + continue; + } + + auto gatt_local_characteristic = characteristic_result.Characteristic(); + auto characteristic_object = + std::make_unique(); + characteristic_object->obj = gatt_local_characteristic; + characteristic_object->stored_clients = + gatt_local_characteristic.SubscribedClients(); + characteristic_object->read_requested_token = + gatt_local_characteristic.ReadRequested( + {this, &UniversalBlePlugin::PeripheralReadRequestedAsync}); + characteristic_object->write_requested_token = + gatt_local_characteristic.WriteRequested( + {this, &UniversalBlePlugin::PeripheralWriteRequestedAsync}); + characteristic_object->subscribed_clients_changed_token = + gatt_local_characteristic.SubscribedClientsChanged( + {this, &UniversalBlePlugin::PeripheralSubscribedClientsChanged}); + + service_provider_object->characteristics.insert_or_assign( + guid_to_uuid(gatt_local_characteristic.Uuid()), + std::move(characteristic_object)); + + const auto descriptors_ptr = characteristic.descriptors(); + if (descriptors_ptr != nullptr) { + for (auto descriptor_encoded : *descriptors_ptr) { + PeripheralDescriptor descriptor = std::any_cast( + std::get(descriptor_encoded)); + auto descriptor_params = GattLocalDescriptorParameters(); + const auto permissions = descriptor.permissions(); + if (permissions != nullptr) { + for (auto permission_encoded : *permissions) { + int permission = + static_cast(std::get(permission_encoded)); + switch (ToPeripheralBlePermission(permission)) { + case PeripheralBlePermission::readable: + descriptor_params.ReadProtectionLevel(GattProtectionLevel::Plain); + break; + case PeripheralBlePermission::writeable: + descriptor_params.WriteProtectionLevel( + GattProtectionLevel::Plain); + break; + case PeripheralBlePermission::readEncryptionRequired: + descriptor_params.ReadProtectionLevel( + GattProtectionLevel::EncryptionRequired); + break; + case PeripheralBlePermission::writeEncryptionRequired: + descriptor_params.WriteProtectionLevel( + GattProtectionLevel::EncryptionRequired); + break; + default: + break; + } + } + } + if (descriptor.value() != nullptr) { + descriptor_params.StaticValue(from_bytevc(*descriptor.value())); + } + co_await gatt_local_characteristic.CreateDescriptorAsync( + uuid_to_guid(descriptor.uuid()), descriptor_params); + } + } + } + + service_provider_object->advertisement_status_changed_token = + service_provider.AdvertisementStatusChanged( + {this, &UniversalBlePlugin::PeripheralAdvertisementStatusChanged}); + { + std::lock_guard lock(peripheral_mutex_); + peripheral_service_provider_map_.insert_or_assign( + guid_to_uuid(service_provider.Service().Uuid()), + std::move(service_provider_object)); + } + + ui_thread_handler_.Post([this, service_uuid] { + peripheral_callback_channel_->OnServiceAdded(service_uuid, nullptr, + SuccessCallback, + ErrorCallback); + }); + } catch (const winrt::hresult_error &e) { + auto err = winrt::to_string(e.message()); + ui_thread_handler_.Post([this, service_uuid, err] { + peripheral_callback_channel_->OnServiceAdded(service_uuid, &err, + SuccessCallback, + ErrorCallback); + }); + } catch (...) { + auto err = std::string("Unknown error"); + ui_thread_handler_.Post([this, service_uuid, err] { + peripheral_callback_channel_->OnServiceAdded(service_uuid, &err, + SuccessCallback, + ErrorCallback); + }); + } +} + +fire_and_forget UniversalBlePlugin::PeripheralSubscribedClientsChanged( + GattLocalCharacteristic const &local_char, IInspectable const &) { + const auto characteristic_id = guid_to_uuid(local_char.Uuid()); + auto *characteristic_object = + FindPeripheralGattCharacteristicObject(characteristic_id); + if (characteristic_object == nullptr) { + co_return; + } + + auto current_clients = local_char.SubscribedClients(); + auto old_clients = characteristic_object->stored_clients; + + for (uint32_t i = 0; i < current_clients.Size(); ++i) { + auto client = current_clients.GetAt(i); + bool found = false; + for (uint32_t j = 0; j < old_clients.Size(); ++j) { + if (old_clients.GetAt(j) == client) { + found = true; + break; + } + } + if (!found) { + const auto device_id = + ParsePeripheralBluetoothClientId(client.Session().DeviceId().Id()); + std::string device_name; + try { + auto device_info = + co_await DeviceInformation::CreateFromIdAsync(client.Session().DeviceId().Id()); + device_name = winrt::to_string(device_info.Name()); + } catch (...) { + } + ui_thread_handler_.Post([this, device_id, characteristic_id, device_name] { + const std::string *name_ptr = device_name.empty() ? nullptr : &device_name; + peripheral_callback_channel_->OnCharacteristicSubscriptionChange( + device_id, characteristic_id, true, name_ptr, SuccessCallback, + ErrorCallback); + }); + const int64_t mtu = client.Session().MaxPduSize(); + ui_thread_handler_.Post([this, device_id, mtu] { + peripheral_callback_channel_->OnMtuChange(device_id, mtu, + SuccessCallback, + ErrorCallback); + }); + } + } + + for (uint32_t i = 0; i < old_clients.Size(); ++i) { + auto client = old_clients.GetAt(i); + bool found = false; + for (uint32_t j = 0; j < current_clients.Size(); ++j) { + if (current_clients.GetAt(j) == client) { + found = true; + break; + } + } + if (!found) { + const auto device_id = + ParsePeripheralBluetoothClientId(client.Session().DeviceId().Id()); + ui_thread_handler_.Post([this, device_id, characteristic_id] { + peripheral_callback_channel_->OnCharacteristicSubscriptionChange( + device_id, characteristic_id, false, nullptr, SuccessCallback, + ErrorCallback); + }); + } + } + + characteristic_object->stored_clients = current_clients; +} + +fire_and_forget UniversalBlePlugin::PeripheralReadRequestedAsync( + GattLocalCharacteristic const &local_char, GattReadRequestedEventArgs args) { + auto deferral = args.GetDeferral(); + auto request = co_await args.GetRequestAsync(); + if (request == nullptr) { + deferral.Complete(); + co_return; + } + + const auto characteristic_id = guid_to_uuid(local_char.Uuid()); + const auto device_id = + ParsePeripheralBluetoothClientId(args.Session().DeviceId().Id()); + const int64_t offset = request.Offset(); + auto value_holder = std::make_shared>(); + std::vector *value_ptr = nullptr; + if (local_char.StaticValue() != nullptr) { + *value_holder = to_bytevc(local_char.StaticValue()); + value_ptr = value_holder.get(); + } + ui_thread_handler_.Post([this, device_id, characteristic_id, offset, value_ptr, + value_holder, request, deferral] { + peripheral_callback_channel_->OnReadRequest( + device_id, characteristic_id, offset, value_ptr, + [request, deferral](const PeripheralReadRequestResult *result) { + if (result != nullptr) { + if (result->status() != nullptr) { + request.RespondWithProtocolError( + ToGattProtocolError(*result->status())); + deferral.Complete(); + return; + } + DataWriter writer; + writer.ByteOrder(ByteOrder::LittleEndian); + writer.WriteBuffer(from_bytevc(result->value())); + request.RespondWithValue(writer.DetachBuffer()); + } else { + request.RespondWithProtocolError(0x01); + } + deferral.Complete(); + }, + [request, deferral](const FlutterError &error) { + request.RespondWithProtocolError(0x0E); + deferral.Complete(); + }); + }); +} + +fire_and_forget UniversalBlePlugin::PeripheralWriteRequestedAsync( + GattLocalCharacteristic const &local_char, + GattWriteRequestedEventArgs args) { + auto deferral = args.GetDeferral(); + auto request = co_await args.GetRequestAsync(); + if (request == nullptr) { + deferral.Complete(); + co_return; + } + const auto characteristic_id = guid_to_uuid(local_char.Uuid()); + const auto device_id = + ParsePeripheralBluetoothClientId(args.Session().DeviceId().Id()); + const int64_t offset = request.Offset(); + auto value_holder = std::make_shared>(to_bytevc(request.Value())); + ui_thread_handler_.Post([this, device_id, characteristic_id, offset, + value_holder, request, deferral] { + peripheral_callback_channel_->OnWriteRequest( + device_id, characteristic_id, offset, value_holder.get(), + [request, deferral](const PeripheralWriteRequestResult *result) { + if (result != nullptr && result->status() != nullptr) { + request.RespondWithProtocolError( + ToGattProtocolError(*result->status())); + } else { + request.Respond(); + } + deferral.Complete(); + }, + [request, deferral](const FlutterError &error) { + request.RespondWithProtocolError(0x0E); + deferral.Complete(); + }); + }); +} + +void UniversalBlePlugin::PeripheralAdvertisementStatusChanged( + GattServiceProvider const &sender, + GattServiceProviderAdvertisementStatusChangedEventArgs const &args) { + if (args.Error() != BluetoothError::Success) { + auto error_str = ParsePeripheralBluetoothError(args.Error()); + ui_thread_handler_.Post([this, error_str] { + peripheral_callback_channel_->OnAdvertisingStatusUpdate( + false, &error_str, SuccessCallback, ErrorCallback); + }); + return; + } + if (AreAllPeripheralServicesStarted()) { + ui_thread_handler_.Post([this] { + peripheral_callback_channel_->OnAdvertisingStatusUpdate( + true, nullptr, SuccessCallback, ErrorCallback); + }); + } +} + +void UniversalBlePlugin::DisposePeripheralServiceProvider( + PeripheralGattServiceProviderObject *service_provider_object) { + if (service_provider_object == nullptr) { + return; + } + try { + if (service_provider_object->obj.AdvertisementStatus() == + GattServiceProviderAdvertisementStatus::Started) { + service_provider_object->obj.StopAdvertising(); + } + } catch (...) { + } + try { + service_provider_object->obj.AdvertisementStatusChanged( + service_provider_object->advertisement_status_changed_token); + } catch (...) { + } + for (auto const &[_, characteristic_object] : + service_provider_object->characteristics) { + try { + characteristic_object->obj.ReadRequested( + characteristic_object->read_requested_token); + characteristic_object->obj.WriteRequested( + characteristic_object->write_requested_token); + characteristic_object->obj.SubscribedClientsChanged( + characteristic_object->subscribed_clients_changed_token); + } catch (...) { + } + } +} + +PeripheralGattCharacteristicObject * +UniversalBlePlugin::FindPeripheralGattCharacteristicObject( + const std::string &characteristic_id, bool *ambiguous_match) { + const auto characteristic_id_lc = to_lower_case(characteristic_id); + PeripheralGattCharacteristicObject *first_match = nullptr; + for (auto const &[_, service_provider] : peripheral_service_provider_map_) { + for (auto const &[char_key, characteristic_object] : + service_provider->characteristics) { + if (to_lower_case(char_key) == characteristic_id_lc) { + if (first_match == nullptr) { + first_match = characteristic_object.get(); + } else { + if (ambiguous_match != nullptr) { + *ambiguous_match = true; + } + return nullptr; + } + } + } + } + return first_match; +} + +bool UniversalBlePlugin::AreAllPeripheralServicesStarted() const { + for (auto const &[_, service_provider] : peripheral_service_provider_map_) { + if (service_provider->obj.AdvertisementStatus() != + GattServiceProviderAdvertisementStatus::Started) { + return false; + } + } + return !peripheral_service_provider_map_.empty(); +} + +GattCharacteristicProperties +UniversalBlePlugin::ToPeripheralGattCharacteristicProperties(int property) { + switch (property) { + case 0: + return GattCharacteristicProperties::Broadcast; + case 1: + return GattCharacteristicProperties::Read; + case 2: + return GattCharacteristicProperties::WriteWithoutResponse; + case 3: + return GattCharacteristicProperties::Write; + case 4: + return GattCharacteristicProperties::Notify; + case 5: + return GattCharacteristicProperties::Indicate; + case 6: + return GattCharacteristicProperties::AuthenticatedSignedWrites; + case 7: + return GattCharacteristicProperties::ExtendedProperties; + case 8: + return GattCharacteristicProperties::Notify; + case 9: + return GattCharacteristicProperties::Indicate; + default: + return GattCharacteristicProperties::None; + } +} + +PeripheralBlePermission +UniversalBlePlugin::ToPeripheralBlePermission(int permission) { + switch (permission) { + case 0: + return PeripheralBlePermission::readable; + case 1: + return PeripheralBlePermission::writeable; + case 2: + return PeripheralBlePermission::readEncryptionRequired; + case 3: + return PeripheralBlePermission::writeEncryptionRequired; + default: + return PeripheralBlePermission::none; + } +} + +std::string UniversalBlePlugin::PeripheralAdvertisementStatusToString( + GattServiceProviderAdvertisementStatus status) { + switch (status) { + case GattServiceProviderAdvertisementStatus::Created: + return "Created"; + case GattServiceProviderAdvertisementStatus::Started: + return "Started"; + case GattServiceProviderAdvertisementStatus::Stopped: + return "Stopped"; + case GattServiceProviderAdvertisementStatus::Aborted: + return "Aborted"; + case GattServiceProviderAdvertisementStatus::StartedWithoutAllAdvertisementData: + return "StartedWithoutAllAdvertisementData"; + default: + return "Unknown"; + } +} + +std::string UniversalBlePlugin::ParsePeripheralBluetoothClientId( + hstring client_id) { + auto id = winrt::to_string(client_id); + const auto pos = id.find_last_of('-'); + if (pos != std::string::npos) { + return id.substr(pos + 1); + } + return id; +} + +std::string +UniversalBlePlugin::ParsePeripheralBluetoothError(BluetoothError error) { + switch (error) { + case BluetoothError::Success: + return "Success"; + case BluetoothError::RadioNotAvailable: + return "RadioNotAvailable"; + case BluetoothError::ResourceInUse: + return "ResourceInUse"; + case BluetoothError::DeviceNotConnected: + return "DeviceNotConnected"; + case BluetoothError::OtherError: + return "OtherError"; + case BluetoothError::DisabledByPolicy: + return "DisabledByPolicy"; + case BluetoothError::NotSupported: + return "NotSupported"; + case BluetoothError::DisabledByUser: + return "DisabledByUser"; + case BluetoothError::ConsentRequired: + return "ConsentRequired"; + case BluetoothError::TransportNotSupported: + return "TransportNotSupported"; + default: + return "Unknown"; + } +} + +uint8_t UniversalBlePlugin::ToGattProtocolError(int64_t status_code) { + if (status_code < 0) { + return 0x01; + } + if (status_code > 0xFF) { + return 0xFF; + } + return static_cast(status_code); +} + } // namespace universal_ble diff --git a/windows/src/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h index 867ed41e..e3b424e5 100644 --- a/windows/src/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -16,6 +16,7 @@ #include #include "generated/universal_ble.g.h" +#include "generated/universal_ble_peripheral.g.h" #include "helper/universal_ble_base.h" #include "helper/universal_enum.h" #include "helper/utils.h" @@ -34,6 +35,29 @@ struct GattServiceObject { std::unordered_map characteristics; }; +struct PeripheralGattCharacteristicObject { + GattLocalCharacteristic obj = nullptr; + event_token read_requested_token{}; + event_token write_requested_token{}; + event_token subscribed_clients_changed_token{}; + IVectorView stored_clients = nullptr; +}; + +struct PeripheralGattServiceProviderObject { + GattServiceProvider obj = nullptr; + event_token advertisement_status_changed_token{}; + std::unordered_map> + characteristics; +}; + +enum class PeripheralBlePermission { + none, + readable, + writeable, + readEncryptionRequired, + writeEncryptionRequired, +}; + struct BluetoothDeviceAgent { BluetoothLEDevice device; event_token connection_status_changed_token; @@ -66,7 +90,8 @@ struct BluetoothDeviceAgent { }; class UniversalBlePlugin : public flutter::Plugin, - public UniversalBlePlatformChannel { + public UniversalBlePlatformChannel, + public UniversalBlePeripheralChannel { public: static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); @@ -167,6 +192,40 @@ class UniversalBlePlugin : public flutter::Plugin, void GattCharacteristicValueChanged(const GattCharacteristic &sender, const GattValueChangedEventArgs &args); + // Peripheral runtime state + std::unordered_map> + peripheral_service_provider_map_{}; + event_revoker peripheral_radio_state_changed_revoker_; + std::unique_ptr peripheral_callback_channel_; + std::mutex peripheral_mutex_; + + // Peripheral helpers + fire_and_forget PeripheralAddServiceAsync(const PeripheralService &service); + fire_and_forget PeripheralReadRequestedAsync( + GattLocalCharacteristic const &local_char, + GattReadRequestedEventArgs args); + fire_and_forget PeripheralWriteRequestedAsync( + GattLocalCharacteristic const &local_char, + GattWriteRequestedEventArgs args); + fire_and_forget PeripheralSubscribedClientsChanged( + GattLocalCharacteristic const &local_char, IInspectable const &args); + void PeripheralAdvertisementStatusChanged( + GattServiceProvider const &sender, + GattServiceProviderAdvertisementStatusChangedEventArgs const &args); + void DisposePeripheralServiceProvider( + PeripheralGattServiceProviderObject *service_provider_object); + PeripheralGattCharacteristicObject *FindPeripheralGattCharacteristicObject( + const std::string &characteristic_id, + bool *ambiguous_match = nullptr); + bool AreAllPeripheralServicesStarted() const; + static uint8_t ToGattProtocolError(int64_t status_code); + static GattCharacteristicProperties ToPeripheralGattCharacteristicProperties( + int property); + static PeripheralBlePermission ToPeripheralBlePermission(int permission); + static std::string PeripheralAdvertisementStatusToString( + GattServiceProviderAdvertisementStatus status); + static std::string ParsePeripheralBluetoothClientId(hstring client_id); + static std::string ParsePeripheralBluetoothError(BluetoothError error); // UniversalBlePlatformChannel implementation. void GetBluetoothAvailabilityState( @@ -221,6 +280,24 @@ class UniversalBlePlugin : public flutter::Plugin, GetSystemDevices(const flutter::EncodableList &with_services, std::function reply)> result) override; + + // UniversalBlePeripheralChannel implementation. + std::optional Initialize() override; + ErrorOr> IsAdvertising() override; + ErrorOr IsSupported() override; + std::optional StopAdvertising() override; + std::optional AddService(const PeripheralService &service) override; + std::optional RemoveService(const std::string &service_id) override; + std::optional ClearServices() override; + ErrorOr GetServices() override; + std::optional StartAdvertising( + const flutter::EncodableList &services, const std::string *local_name, + const int64_t *timeout, + const PeripheralManufacturerData *manufacturer_data, + bool add_manufacturer_data_in_scan_response) override; + std::optional UpdateCharacteristic( + const std::string &characteristic_id, const std::vector &value, + const std::string *device_id) override; }; } // namespace universal_ble From 66d22957b2fdec499a6a23ed2465f49429051cab Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 15:47:47 +0100 Subject: [PATCH 02/23] Add cache clearing functionality for peripherals and improve synchronization in BLE plugin --- .../UniversalBlePeripheralExtensions.kt | 8 ++++ .../UniversalBlePeripheralPlugin.kt | 23 ++++++---- .../UniversalBlePeripheralExtensions.swift | 5 +++ .../UniversalBlePeripheralPlugin.swift | 44 ++++++++++++++++--- .../universal_ble_peripheral.dart | 1 + .../universal_ble_peripheral_pigeon.dart | 18 +++++++- ...sal_ble_peripheral_platform_interface.dart | 5 +++ 7 files changed, 89 insertions(+), 15 deletions(-) diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt index 25b9f423..7263039d 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt @@ -16,6 +16,14 @@ private val descriptorValueReadMap: MutableMap = HashMap() val subscribedCharDevicesMap: MutableMap> = HashMap() const val peripheralDescriptorCCUUID = "00002902-0000-1000-8000-00805f9b34fb" +fun clearPeripheralCaches() { + bluetoothGattCharacteristics.clear() + descriptorValueReadMap.clear() + synchronized(subscribedCharDevicesMap) { + subscribedCharDevicesMap.clear() + } +} + fun Activity.havePermission(permissions: Array): Boolean { for (perm in permissions) { if (checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index 26ad4052..3d88ee58 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -60,6 +60,8 @@ class UniversalBlePeripheralPlugin( gattServer?.close() gattServer = null bluetoothDevicesMap.clear() + listOfDevicesWaitingForBond.clear() + clearPeripheralCaches() } override fun initialize() { @@ -207,7 +209,11 @@ class UniversalBlePeripheralPlugin( private fun cleanConnection(device: BluetoothDevice) { val deviceAddress = device.address - val subscribedCharUUID = subscribedCharDevicesMap[deviceAddress] ?: mutableListOf() + val subscribedCharUUID = synchronized(subscribedCharDevicesMap) { + val current = subscribedCharDevicesMap[deviceAddress]?.toList() ?: emptyList() + subscribedCharDevicesMap.remove(deviceAddress) + current + } subscribedCharUUID.forEach { charUUID -> handler.post { callback.onCharacteristicSubscriptionChange( @@ -218,7 +224,6 @@ class UniversalBlePeripheralPlugin( ) {} } } - subscribedCharDevicesMap.remove(deviceAddress) } private val advertiseCallback = object : AdvertiseCallback() { @@ -387,13 +392,15 @@ class UniversalBlePeripheralPlugin( address, characteristicId, isSubscribed, device.name, ) {} } - val charList = subscribedCharDevicesMap[address] ?: mutableListOf() - if (isSubscribed) { - charList.add(characteristicId) - } else { - charList.remove(characteristicId) + synchronized(subscribedCharDevicesMap) { + val charList = subscribedCharDevicesMap[address] ?: mutableListOf() + if (isSubscribed) { + charList.add(characteristicId) + } else { + charList.remove(characteristicId) + } + subscribedCharDevicesMap[address] = charList } - subscribedCharDevicesMap[address] = charList } } if (responseNeeded) { diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift index 388fb2e9..a361c6fd 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift @@ -15,6 +15,11 @@ enum UniversalBlePeripheralError: Error { var peripheralCharacteristicsList = [CBMutableCharacteristic]() var peripheralServicesList = [CBMutableService]() +func clearPeripheralCaches() { + peripheralCharacteristicsList.removeAll() + peripheralServicesList.removeAll() +} + extension PeripheralService { func toCBService() -> CBMutableService { let service = CBMutableService(type: CBUUID(string: uuid), primary: primary) diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 5527bdd4..2279f836 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -13,13 +13,21 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne private let callbackChannel: UniversalBlePeripheralCallback private lazy var peripheralManager: CBPeripheralManager = .init(delegate: self, queue: nil, options: nil) - private var centrals = [CBCentral]() + private let centralsLock = NSLock() + private var centralsById = [String: CBCentral]() init(callbackChannel: UniversalBlePeripheralCallback) { self.callbackChannel = callbackChannel super.init() } + deinit { + peripheralManager.stopAdvertising() + peripheralManager.removeAllServices() + clearPeripheralCaches() + clearCentrals() + } + func initialize() throws { _ = peripheralManager.isAdvertising } @@ -83,7 +91,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne throw UniversalBlePeripheralError.notFound("\(characteristicId) characteristic not found") } if let deviceId { - guard let central = centrals.first(where: { $0.identifier.uuidString == deviceId }) else { + guard let central = central(for: deviceId) else { throw UniversalBlePeripheralError.notFound("\(deviceId) device not found") } peripheralManager.updateValue( @@ -126,9 +134,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne central: CBCentral, didSubscribeTo characteristic: CBCharacteristic ) { - if !centrals.contains(where: { $0.identifier == central.identifier }) { - centrals.append(central) - } + upsertCentral(central) callbackChannel.onCharacteristicSubscriptionChange( deviceId: central.identifier.uuidString, characteristicId: characteristic.uuid.uuidString, @@ -146,7 +152,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic ) { - centrals.removeAll { $0.identifier == central.identifier } + removeCentral(id: central.identifier.uuidString) callbackChannel.onCharacteristicSubscriptionChange( deviceId: central.identifier.uuidString, characteristicId: characteristic.uuid.uuidString, @@ -200,4 +206,30 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne } } } + + private func upsertCentral(_ central: CBCentral) { + let centralId = central.identifier.uuidString + centralsLock.lock() + centralsById[centralId] = central + centralsLock.unlock() + } + + private func removeCentral(id: String) { + centralsLock.lock() + centralsById.removeValue(forKey: id) + centralsLock.unlock() + } + + private func central(for id: String) -> CBCentral? { + centralsLock.lock() + let central = centralsById[id] + centralsLock.unlock() + return central + } + + private func clearCentrals() { + centralsLock.lock() + centralsById.removeAll() + centralsLock.unlock() + } } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart index ce7601d9..66f3fd91 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -13,6 +13,7 @@ class UniversalBlePeripheral { } static void setInstance(UniversalBlePeripheralPlatform instance) { + _platform.dispose(); _platform = instance; } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index a9d0f644..48188428 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -20,6 +20,7 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform final StreamController<({String serviceId, String? error})> _serviceResultController = StreamController<({String serviceId, String? error})>.broadcast(); + bool _disposed = false; @override Future initialize() => _channel.initialize(); @@ -172,7 +173,9 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform @override void onServiceAdded(String serviceId, String? error) { super.serviceAddedCallback?.call(serviceId, error); - _serviceResultController.add((serviceId: serviceId, error: error)); + if (!_serviceResultController.isClosed) { + _serviceResultController.add((serviceId: serviceId, error: error)); + } } @override @@ -195,4 +198,17 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform status: result.status, ); } + + @override + void dispose() { + if (_disposed) return; + _disposed = true; + pigeon.UniversalBlePeripheralCallback.setUp(null); + if (!_serviceResultController.isClosed) { + _serviceResultController.close(); + } + if (identical(_instance, this)) { + _instance = null; + } + } } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart index 69e1e721..ac023d42 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -74,6 +74,11 @@ abstract class UniversalBlePeripheralPlatform { required Uint8List value, String? deviceId, }); + + /// Called when this platform implementation is being replaced. + /// + /// Default is no-op so existing custom implementations remain compatible. + void dispose() {} } class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { From 5a879b7ab1f5e1e4964e2c2cd19583ef09f0ac1e Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 16:14:46 +0100 Subject: [PATCH 03/23] Enhance BLE plugin with encrypted notify/indicate properties and improve central subscription management --- .../UniversalBlePeripheralExtensions.kt | 5 +-- .../UniversalBlePeripheralPlugin.kt | 9 ++++-- .../UniversalBlePeripheralPlugin.swift | 31 ++++++++++++++++--- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt index 7263039d..291e1483 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt @@ -130,8 +130,9 @@ private fun Int.toPropertyBits(): Int = when (this) { 5 -> BluetoothGattCharacteristic.PROPERTY_INDICATE 6 -> BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE 7 -> BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS - 8 -> BluetoothGattCharacteristic.PROPERTY_NOTIFY - 9 -> BluetoothGattCharacteristic.PROPERTY_INDICATE + // Android uses dedicated encrypted notify/indicate property bits. + 8 -> 0x100 // PROPERTY_NOTIFY_ENCRYPTED + 9 -> 0x200 // PROPERTY_INDICATE_ENCRYPTED else -> 0 } diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index 3d88ee58..e1ff4358 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -254,14 +254,14 @@ class UniversalBlePeripheralPlugin( super.onConnectionStateChange(device, status, newState) when (newState) { BluetoothProfile.STATE_CONNECTED -> { + synchronized(bluetoothDevicesMap) { + bluetoothDevicesMap[device.address] = device + } if (device.bondState == BluetoothDevice.BOND_NONE) { listOfDevicesWaitingForBond.add(device.address) device.createBond() } else if (device.bondState == BluetoothDevice.BOND_BONDED) { handler.post { gattServer?.connect(device, true) } - synchronized(bluetoothDevicesMap) { - bluetoothDevicesMap[device.address] = device - } } onConnectionUpdate(device, status, newState) } @@ -444,6 +444,9 @@ class UniversalBlePeripheralPlugin( val waitingForConnection = listOfDevicesWaitingForBond.contains(device?.address) if (state == BluetoothDevice.BOND_BONDED && device != null && waitingForConnection) { listOfDevicesWaitingForBond.remove(device.address) + synchronized(bluetoothDevicesMap) { + bluetoothDevicesMap[device.address] = device + } handler.post { gattServer?.connect(device, true) } } } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 2279f836..5e6ad165 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -15,6 +15,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne .init(delegate: self, queue: nil, options: nil) private let centralsLock = NSLock() private var centralsById = [String: CBCentral]() + private var centralCharacteristicSubscriptions = [String: Set]() init(callbackChannel: UniversalBlePeripheralCallback) { self.callbackChannel = callbackChannel @@ -134,7 +135,10 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne central: CBCentral, didSubscribeTo characteristic: CBCharacteristic ) { - upsertCentral(central) + upsertCentralSubscription( + central: central, + characteristicId: characteristic.uuid.uuidString + ) callbackChannel.onCharacteristicSubscriptionChange( deviceId: central.identifier.uuidString, characteristicId: characteristic.uuid.uuidString, @@ -152,7 +156,10 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic ) { - removeCentral(id: central.identifier.uuidString) + removeCentralSubscription( + centralId: central.identifier.uuidString, + characteristicId: characteristic.uuid.uuidString + ) callbackChannel.onCharacteristicSubscriptionChange( deviceId: central.identifier.uuidString, characteristicId: characteristic.uuid.uuidString, @@ -207,16 +214,29 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne } } - private func upsertCentral(_ central: CBCentral) { + private func upsertCentralSubscription( + central: CBCentral, + characteristicId: String + ) { let centralId = central.identifier.uuidString centralsLock.lock() centralsById[centralId] = central + var subscriptions = centralCharacteristicSubscriptions[centralId] ?? Set() + subscriptions.insert(characteristicId) + centralCharacteristicSubscriptions[centralId] = subscriptions centralsLock.unlock() } - private func removeCentral(id: String) { + private func removeCentralSubscription(centralId: String, characteristicId: String) { centralsLock.lock() - centralsById.removeValue(forKey: id) + var subscriptions = centralCharacteristicSubscriptions[centralId] ?? Set() + subscriptions.remove(characteristicId) + if subscriptions.isEmpty { + centralCharacteristicSubscriptions.removeValue(forKey: centralId) + centralsById.removeValue(forKey: centralId) + } else { + centralCharacteristicSubscriptions[centralId] = subscriptions + } centralsLock.unlock() } @@ -230,6 +250,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne private func clearCentrals() { centralsLock.lock() centralsById.removeAll() + centralCharacteristicSubscriptions.removeAll() centralsLock.unlock() } } From fb57381ea1133fa502c79271cf605e020e285861 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 16:26:04 +0100 Subject: [PATCH 04/23] Improve synchronization in BLE plugin by adding synchronized blocks for shared collections to prevent concurrent modification issues --- .../UniversalBlePeripheralExtensions.kt | 34 +++++++++++++------ .../UniversalBlePeripheralPlugin.kt | 30 ++++++++++------ 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt index 291e1483..293ac7d0 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt @@ -17,8 +17,12 @@ val subscribedCharDevicesMap: MutableMap> = HashMap( const val peripheralDescriptorCCUUID = "00002902-0000-1000-8000-00805f9b34fb" fun clearPeripheralCaches() { - bluetoothGattCharacteristics.clear() - descriptorValueReadMap.clear() + synchronized(bluetoothGattCharacteristics) { + bluetoothGattCharacteristics.clear() + } + synchronized(descriptorValueReadMap) { + descriptorValueReadMap.clear() + } synchronized(subscribedCharDevicesMap) { subscribedCharDevicesMap.clear() } @@ -56,8 +60,10 @@ fun PeripheralCharacteristic.toGattCharacteristic(): BluetoothGattCharacteristic } addCCDescriptorIfRequired(this, characteristic) - if (bluetoothGattCharacteristics[uuid] == null) { - bluetoothGattCharacteristics[uuid] = characteristic + synchronized(bluetoothGattCharacteristics) { + if (bluetoothGattCharacteristics[uuid] == null) { + bluetoothGattCharacteristics[uuid] = characteristic + } } return characteristic } @@ -95,21 +101,29 @@ fun PeripheralDescriptor.toGattDescriptor(): BluetoothGattDescriptor { val descriptor = BluetoothGattDescriptor(UUID.fromString(uuid), permission) value?.let { descriptor.value = it - descriptorValueReadMap[uuid.lowercase()] = it + synchronized(descriptorValueReadMap) { + descriptorValueReadMap[uuid.lowercase()] = it + } } return descriptor } fun BluetoothGattDescriptor.getCacheValue(): ByteArray? = - descriptorValueReadMap[uuid.toString().lowercase()] + synchronized(descriptorValueReadMap) { + descriptorValueReadMap[uuid.toString().lowercase()] + } fun String.findCharacteristic(): BluetoothGattCharacteristic? = - bluetoothGattCharacteristics[this] + synchronized(bluetoothGattCharacteristics) { + bluetoothGattCharacteristics[this] + } fun String.findService(): BluetoothGattService? { - for (characteristic in bluetoothGattCharacteristics.values) { - if (characteristic.service?.uuid.toString() == this) { - return characteristic.service + synchronized(bluetoothGattCharacteristics) { + for (characteristic in bluetoothGattCharacteristics.values) { + if (characteristic.service?.uuid.toString() == this) { + return characteristic.service + } } } return null diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index e1ff4358..f9adf31c 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -60,7 +60,9 @@ class UniversalBlePeripheralPlugin( gattServer?.close() gattServer = null bluetoothDevicesMap.clear() - listOfDevicesWaitingForBond.clear() + synchronized(listOfDevicesWaitingForBond) { + listOfDevicesWaitingForBond.clear() + } clearPeripheralCaches() } @@ -183,14 +185,16 @@ class UniversalBlePeripheralPlugin( val characteristic = characteristicId.findCharacteristic() ?: throw Exception("Characteristic not found") characteristic.value = value - if (deviceId != null) { - val device = bluetoothDevicesMap[deviceId] ?: throw Exception("Device not found") - handler.post { gattServer?.notifyCharacteristicChanged(device, characteristic, true) } - } else { - bluetoothDevicesMap.values.forEach { device -> - handler.post { gattServer?.notifyCharacteristicChanged(device, characteristic, true) } + val targetDevices = synchronized(bluetoothDevicesMap) { + if (deviceId != null) { + listOf(bluetoothDevicesMap[deviceId] ?: throw Exception("Device not found")) + } else { + bluetoothDevicesMap.values.toList() } } + targetDevices.forEach { device -> + handler.post { gattServer?.notifyCharacteristicChanged(device, characteristic, true) } + } } private fun isBluetoothEnabled(): Boolean = @@ -258,7 +262,9 @@ class UniversalBlePeripheralPlugin( bluetoothDevicesMap[device.address] = device } if (device.bondState == BluetoothDevice.BOND_NONE) { - listOfDevicesWaitingForBond.add(device.address) + synchronized(listOfDevicesWaitingForBond) { + listOfDevicesWaitingForBond.add(device.address) + } device.createBond() } else if (device.bondState == BluetoothDevice.BOND_BONDED) { handler.post { gattServer?.connect(device, true) } @@ -441,9 +447,13 @@ class UniversalBlePeripheralPlugin( ) {} } - val waitingForConnection = listOfDevicesWaitingForBond.contains(device?.address) + val waitingForConnection = synchronized(listOfDevicesWaitingForBond) { + listOfDevicesWaitingForBond.contains(device?.address) + } if (state == BluetoothDevice.BOND_BONDED && device != null && waitingForConnection) { - listOfDevicesWaitingForBond.remove(device.address) + synchronized(listOfDevicesWaitingForBond) { + listOfDevicesWaitingForBond.remove(device.address) + } synchronized(bluetoothDevicesMap) { bluetoothDevicesMap[device.address] = device } From 641f6103ff02d2f2bc8db6918b3a7e3d6ad4c5fd Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 19:56:08 +0100 Subject: [PATCH 05/23] Refactor BLE plugin to improve advertising functionality and error handling. Update Android receiver registration to use RECEIVER_NOT_EXPORTED, enhance service and characteristic mapping in tests, and add error checks for unsupported features in Windows advertising. --- .../UniversalBlePeripheralPlugin.kt | 57 +++-- .../UniversalBlePeripheralPlugin.swift | 26 ++- .../Flutter/GeneratedPluginRegistrant.swift | 2 - test/universal_ble_peripheral_test.dart | 47 ++++ windows/src/universal_ble_plugin.cpp | 215 ++++++++++++------ 5 files changed, 253 insertions(+), 94 deletions(-) diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index f9adf31c..1c813a0e 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -18,7 +18,7 @@ import android.bluetooth.le.AdvertiseSettings import android.bluetooth.le.BluetoothLeAdvertiser import android.content.BroadcastReceiver import android.content.Context -import android.content.Context.RECEIVER_EXPORTED +import android.content.Context.RECEIVER_NOT_EXPORTED import android.content.Intent import android.content.IntentFilter import android.os.Build @@ -46,6 +46,8 @@ class UniversalBlePeripheralPlugin( private val emptyBytes = byteArrayOf() private var advertising: Boolean? = null private var receiverRegistered = false + private var originalAdapterName: String? = null + private var adapterNameOverridden = false fun attachActivity(activity: Activity?) { this.activity = activity @@ -57,6 +59,7 @@ class UniversalBlePeripheralPlugin( receiverRegistered = false } kotlin.runCatching { bluetoothLeAdvertiser?.stopAdvertising(advertiseCallback) } + restoreAdapterNameIfNeeded() gattServer?.close() gattServer = null bluetoothDevicesMap.clear() @@ -80,7 +83,11 @@ class UniversalBlePeripheralPlugin( val intentFilter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - applicationContext.registerReceiver(broadcastReceiver, intentFilter, RECEIVER_EXPORTED) + applicationContext.registerReceiver( + broadcastReceiver, + intentFilter, + RECEIVER_NOT_EXPORTED, + ) } else { @Suppress("DEPRECATION") applicationContext.registerReceiver(broadcastReceiver, intentFilter) @@ -96,9 +103,7 @@ class UniversalBlePeripheralPlugin( override fun isSupported(): Boolean { val adapter = bluetoothManager.adapter ?: return false if (!adapter.isMultipleAdvertisementSupported) { - throw UnsupportedOperationException( - "Bluetooth LE Advertising not supported on this device.", - ) + return false } return true } @@ -134,7 +139,14 @@ class UniversalBlePeripheralPlugin( } handler.post { - localName?.let { bluetoothManager.adapter?.name = it } + val adapter = bluetoothManager.adapter + if (localName != null && adapter != null && adapter.name != localName) { + if (!adapterNameOverridden) { + originalAdapterName = adapter.name + } + adapter.name = localName + adapterNameOverridden = true + } val advertiseSettings = AdvertiseSettings.Builder() .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) .setConnectable(true) @@ -176,6 +188,7 @@ class UniversalBlePeripheralPlugin( override fun stopAdvertising() { handler.post { bluetoothLeAdvertiser?.stopAdvertising(advertiseCallback) + restoreAdapterNameIfNeeded() advertising = false callback.onAdvertisingStatusUpdate(false, null) {} } @@ -192,8 +205,12 @@ class UniversalBlePeripheralPlugin( bluetoothDevicesMap.values.toList() } } + val indicate = + (characteristic.properties and BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0 targetDevices.forEach { device -> - handler.post { gattServer?.notifyCharacteristicChanged(device, characteristic, true) } + handler.post { + gattServer?.notifyCharacteristicChanged(device, characteristic, indicate) + } } } @@ -340,13 +357,15 @@ class UniversalBlePeripheralPlugin( valueArg = value, ) { writeResponse -> val writeResult = writeResponse.getOrNull() - gattServer?.sendResponse( - device, - requestId, - writeResult?.status?.toInt() ?: BluetoothGatt.GATT_SUCCESS, - writeResult?.offset?.toInt() ?: 0, - writeResult?.value ?: emptyBytes, - ) + if (responseNeeded) { + gattServer?.sendResponse( + device, + requestId, + writeResult?.status?.toInt() ?: BluetoothGatt.GATT_SUCCESS, + writeResult?.offset?.toInt() ?: 0, + writeResult?.value ?: emptyBytes, + ) + } } } } @@ -463,4 +482,14 @@ class UniversalBlePeripheralPlugin( } } } + + private fun restoreAdapterNameIfNeeded() { + if (!adapterNameOverridden) return + val adapter = bluetoothManager.adapter ?: return + kotlin.runCatching { + adapter.name = originalAdapterName + } + adapterNameOverridden = false + originalAdapterName = null + } } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 5e6ad165..1df4081b 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -71,15 +71,35 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne func startAdvertising( services: [String], localName: String?, - timeout _: Int64?, - manufacturerData _: PeripheralManufacturerData?, - addManufacturerDataInScanResponse _: Bool + timeout: Int64?, + manufacturerData: PeripheralManufacturerData?, + addManufacturerDataInScanResponse: Bool ) throws { + if let timeout, timeout > 0 { + throw NSError( + domain: "UniversalBlePeripheral", + code: -1, + userInfo: [NSLocalizedDescriptionKey: "Advertising timeout is not supported on Darwin."] + ) + } + if addManufacturerDataInScanResponse { + throw NSError( + domain: "UniversalBlePeripheral", + code: -1, + userInfo: [ + NSLocalizedDescriptionKey: + "Scan response manufacturer data placement is not supported on Darwin." + ] + ) + } let cbServices = services.map { CBUUID(string: $0) } var advertisementData: [String: Any] = [CBAdvertisementDataServiceUUIDsKey: cbServices] if let localName { advertisementData[CBAdvertisementDataLocalNameKey] = localName } + if let manufacturerData { + advertisementData[CBAdvertisementDataManufacturerDataKey] = manufacturerData.data.data + } peripheralManager.startAdvertising(advertisementData) } diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 474e8d78..7ddba83e 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,8 @@ import FlutterMacOS import Foundation -import ble_peripheral import universal_ble func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - BlePeripheralPlugin.register(with: registry.registrar(forPlugin: "BlePeripheralPlugin")) UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin")) } diff --git a/test/universal_ble_peripheral_test.dart b/test/universal_ble_peripheral_test.dart index 33d34772..14b144fd 100644 --- a/test/universal_ble_peripheral_test.dart +++ b/test/universal_ble_peripheral_test.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; +import 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart'; import 'package:universal_ble/universal_ble.dart'; void main() { @@ -37,4 +38,50 @@ void main() { true, ); }); + + test('mapper converts service/characteristic/descriptor to pigeon types', () { + final service = BleService('180f', [ + BleCharacteristic( + '2a19', + [CharacteristicProperty.read, CharacteristicProperty.indicate], + [BleDescriptor('2902')], + ), + ]); + + final mapped = UniversalBlePeripheralMapper.toPigeonService( + service, + primary: true, + ); + + expect(mapped.uuid, BleUuidParser.string('180f')); + expect(mapped.primary, isTrue); + expect(mapped.characteristics, hasLength(1)); + + final characteristic = mapped.characteristics.single; + expect(characteristic.uuid, BleUuidParser.string('2a19')); + expect( + characteristic.properties, + equals([ + CharacteristicProperty.read.index, + CharacteristicProperty.indicate.index, + ]), + ); + expect(characteristic.descriptors, hasLength(1)); + final descriptors = characteristic.descriptors; + expect(descriptors, isNotNull); + expect( + descriptors!.single.uuid, + BleUuidParser.string('2902'), + ); + }); + + test('mapper converts manufacturer data to pigeon type', () { + final data = ManufacturerData(0x004C, Uint8List.fromList([0x01, 0x02])); + + final mapped = UniversalBlePeripheralMapper.toPigeonManufacturerData(data); + + expect(mapped, isNotNull); + expect(mapped!.manufacturerId, 0x004C); + expect(mapped.data, Uint8List.fromList([0x01, 0x02])); + }); } diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index 413602f8..da2c8415 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -1699,11 +1699,51 @@ std::optional UniversalBlePlugin::StartAdvertising( if (peripheral_service_provider_map_.empty()) { return FlutterError("failed", "No services added to advertise", nullptr); } + if (local_name != nullptr) { + return FlutterError( + "not-supported", + "Windows GattServiceProvider advertising does not support overriding local name", + nullptr); + } + if (manufacturer_data != nullptr || add_manufacturer_data_in_scan_response) { + return FlutterError( + "not-supported", + "Windows GattServiceProvider advertising does not support manufacturer data", + nullptr); + } + if (timeout != nullptr && *timeout > 0) { + return FlutterError( + "not-supported", + "Windows GattServiceProvider advertising timeout is not supported", + nullptr); + } try { + std::vector selected_services_lc; + selected_services_lc.reserve(services.size()); + for (const auto &service_encoded : services) { + const auto &service_id = std::get(service_encoded); + const auto service_id_lc = to_lower_case(service_id); + selected_services_lc.push_back(service_id_lc); + if (peripheral_service_provider_map_.count(service_id_lc) == 0) { + return FlutterError("not-found", "Service not found for advertising", + service_id); + } + } + auto params = GattServiceProviderAdvertisingParameters(); params.IsDiscoverable(true); params.IsConnectable(true); + // TODO: migrate to BluetoothLEAdvertisementPublisher to support richer + // payload customization (local name, manufacturer data, scan response). for (auto const &[key, provider] : peripheral_service_provider_map_) { + const bool should_start = selected_services_lc.empty() || + std::find(selected_services_lc.begin(), + selected_services_lc.end(), + to_lower_case(key)) != + selected_services_lc.end(); + if (!should_start) { + continue; + } if (provider->obj.AdvertisementStatus() != GattServiceProviderAdvertisementStatus::Started) { provider->obj.StartAdvertising(params); @@ -1719,6 +1759,12 @@ std::optional UniversalBlePlugin::UpdateCharacteristic( const std::string &characteristic_id, const std::vector &value, const std::string *device_id) { std::lock_guard lock(peripheral_mutex_); + if (device_id != nullptr) { + return FlutterError( + "not-supported", + "Windows does not support targeting a specific device for notifications", + nullptr); + } bool ambiguous_match = false; auto *characteristic_object = FindPeripheralGattCharacteristicObject(characteristic_id, &ambiguous_match); @@ -1735,7 +1781,14 @@ std::optional UniversalBlePlugin::UpdateCharacteristic( DataWriter writer; writer.ByteOrder(ByteOrder::LittleEndian); writer.WriteBuffer(bytes); - characteristic_object->obj.NotifyValueAsync(writer.DetachBuffer()); + auto notify_result = + characteristic_object->obj.NotifyValueAsync(writer.DetachBuffer()).get(); + if (!notify_result) { + return FlutterError( + "failed", + "Failed to notify subscribed clients for characteristic update", + nullptr); + } return std::nullopt; } @@ -1901,15 +1954,20 @@ UniversalBlePlugin::PeripheralAddServiceAsync(const PeripheralService &service) fire_and_forget UniversalBlePlugin::PeripheralSubscribedClientsChanged( GattLocalCharacteristic const &local_char, IInspectable const &) { const auto characteristic_id = guid_to_uuid(local_char.Uuid()); - auto *characteristic_object = - FindPeripheralGattCharacteristicObject(characteristic_id); - if (characteristic_object == nullptr) { - co_return; + IVectorView current_clients = nullptr; + IVectorView old_clients = nullptr; + { + std::lock_guard lock(peripheral_mutex_); + auto *characteristic_object = + FindPeripheralGattCharacteristicObject(characteristic_id); + if (characteristic_object == nullptr) { + co_return; + } + current_clients = local_char.SubscribedClients(); + old_clients = characteristic_object->stored_clients; + characteristic_object->stored_clients = current_clients; } - auto current_clients = local_char.SubscribedClients(); - auto old_clients = characteristic_object->stored_clients; - for (uint32_t i = 0; i < current_clients.Size(); ++i) { auto client = current_clients.GetAt(i); bool found = false; @@ -1964,88 +2022,95 @@ fire_and_forget UniversalBlePlugin::PeripheralSubscribedClientsChanged( } } - characteristic_object->stored_clients = current_clients; } fire_and_forget UniversalBlePlugin::PeripheralReadRequestedAsync( GattLocalCharacteristic const &local_char, GattReadRequestedEventArgs args) { auto deferral = args.GetDeferral(); - auto request = co_await args.GetRequestAsync(); - if (request == nullptr) { - deferral.Complete(); - co_return; - } + try { + auto request = co_await args.GetRequestAsync(); + if (request == nullptr) { + deferral.Complete(); + co_return; + } - const auto characteristic_id = guid_to_uuid(local_char.Uuid()); - const auto device_id = - ParsePeripheralBluetoothClientId(args.Session().DeviceId().Id()); - const int64_t offset = request.Offset(); - auto value_holder = std::make_shared>(); - std::vector *value_ptr = nullptr; - if (local_char.StaticValue() != nullptr) { - *value_holder = to_bytevc(local_char.StaticValue()); - value_ptr = value_holder.get(); - } - ui_thread_handler_.Post([this, device_id, characteristic_id, offset, value_ptr, - value_holder, request, deferral] { - peripheral_callback_channel_->OnReadRequest( - device_id, characteristic_id, offset, value_ptr, - [request, deferral](const PeripheralReadRequestResult *result) { - if (result != nullptr) { - if (result->status() != nullptr) { - request.RespondWithProtocolError( - ToGattProtocolError(*result->status())); - deferral.Complete(); - return; + const auto characteristic_id = guid_to_uuid(local_char.Uuid()); + const auto device_id = + ParsePeripheralBluetoothClientId(args.Session().DeviceId().Id()); + const int64_t offset = request.Offset(); + auto value_holder = std::make_shared>(); + std::vector *value_ptr = nullptr; + if (local_char.StaticValue() != nullptr) { + *value_holder = to_bytevc(local_char.StaticValue()); + value_ptr = value_holder.get(); + } + ui_thread_handler_.Post([this, device_id, characteristic_id, offset, value_ptr, + value_holder, request, deferral] { + peripheral_callback_channel_->OnReadRequest( + device_id, characteristic_id, offset, value_ptr, + [request, deferral](const PeripheralReadRequestResult *result) { + if (result != nullptr) { + if (result->status() != nullptr) { + request.RespondWithProtocolError( + ToGattProtocolError(*result->status())); + deferral.Complete(); + return; + } + DataWriter writer; + writer.ByteOrder(ByteOrder::LittleEndian); + writer.WriteBuffer(from_bytevc(result->value())); + request.RespondWithValue(writer.DetachBuffer()); + } else { + request.RespondWithProtocolError(0x01); } - DataWriter writer; - writer.ByteOrder(ByteOrder::LittleEndian); - writer.WriteBuffer(from_bytevc(result->value())); - request.RespondWithValue(writer.DetachBuffer()); - } else { - request.RespondWithProtocolError(0x01); - } - deferral.Complete(); - }, - [request, deferral](const FlutterError &error) { - request.RespondWithProtocolError(0x0E); - deferral.Complete(); - }); - }); + deferral.Complete(); + }, + [request, deferral](const FlutterError &error) { + request.RespondWithProtocolError(0x0E); + deferral.Complete(); + }); + }); + } catch (...) { + deferral.Complete(); + } } fire_and_forget UniversalBlePlugin::PeripheralWriteRequestedAsync( GattLocalCharacteristic const &local_char, GattWriteRequestedEventArgs args) { auto deferral = args.GetDeferral(); - auto request = co_await args.GetRequestAsync(); - if (request == nullptr) { + try { + auto request = co_await args.GetRequestAsync(); + if (request == nullptr) { + deferral.Complete(); + co_return; + } + const auto characteristic_id = guid_to_uuid(local_char.Uuid()); + const auto device_id = + ParsePeripheralBluetoothClientId(args.Session().DeviceId().Id()); + const int64_t offset = request.Offset(); + auto value_holder = std::make_shared>(to_bytevc(request.Value())); + ui_thread_handler_.Post([this, device_id, characteristic_id, offset, + value_holder, request, deferral] { + peripheral_callback_channel_->OnWriteRequest( + device_id, characteristic_id, offset, value_holder.get(), + [request, deferral](const PeripheralWriteRequestResult *result) { + if (result != nullptr && result->status() != nullptr) { + request.RespondWithProtocolError( + ToGattProtocolError(*result->status())); + } else { + request.Respond(); + } + deferral.Complete(); + }, + [request, deferral](const FlutterError &error) { + request.RespondWithProtocolError(0x0E); + deferral.Complete(); + }); + }); + } catch (...) { deferral.Complete(); - co_return; } - const auto characteristic_id = guid_to_uuid(local_char.Uuid()); - const auto device_id = - ParsePeripheralBluetoothClientId(args.Session().DeviceId().Id()); - const int64_t offset = request.Offset(); - auto value_holder = std::make_shared>(to_bytevc(request.Value())); - ui_thread_handler_.Post([this, device_id, characteristic_id, offset, - value_holder, request, deferral] { - peripheral_callback_channel_->OnWriteRequest( - device_id, characteristic_id, offset, value_holder.get(), - [request, deferral](const PeripheralWriteRequestResult *result) { - if (result != nullptr && result->status() != nullptr) { - request.RespondWithProtocolError( - ToGattProtocolError(*result->status())); - } else { - request.Respond(); - } - deferral.Complete(); - }, - [request, deferral](const FlutterError &error) { - request.RespondWithProtocolError(0x0E); - deferral.Complete(); - }); - }); } void UniversalBlePlugin::PeripheralAdvertisementStatusChanged( From 69663595cd0915ef1177e060a192a445b0725570 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 20:00:28 +0100 Subject: [PATCH 06/23] Enhance BLE advertising by modifying manufacturer data format to include company ID followed by payload, ensuring compatibility with CoreBluetooth requirements. --- .../universal_ble/UniversalBlePeripheralPlugin.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 1df4081b..b96e253d 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -98,7 +98,14 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne advertisementData[CBAdvertisementDataLocalNameKey] = localName } if let manufacturerData { - advertisementData[CBAdvertisementDataManufacturerDataKey] = manufacturerData.data.data + // CoreBluetooth expects the full AD manufacturer field: company ID (LE uint16) + // followed by payload. Dart's `ManufacturerData` keeps id and payload separate. + let companyId = UInt16(truncatingIfNeeded: manufacturerData.manufacturerId) + var manufacturerField = Data() + manufacturerField.append(UInt8(companyId & 0x00ff)) + manufacturerField.append(UInt8((companyId >> 8) & 0x00ff)) + manufacturerField.append(manufacturerData.data.data) + advertisementData[CBAdvertisementDataManufacturerDataKey] = manufacturerField } peripheralManager.startAdvertising(advertisementData) } From 11c9837fcbc5a6921c5a7a1e78973500b5d4c7e9 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 21:03:43 +0100 Subject: [PATCH 07/23] feat(peripheral): add getSubscribedCentrals for HID subscription recovery Expose Host API to list GATT central device ids currently subscribed to a characteristic (Darwin/Android/Windows). Used by apps to restore in-memory state after process restart when subscription callbacks are not replayed. - Pigeon: UniversalBlePeripheralChannel.getSubscribedCentrals - Darwin: filter centralCharacteristicSubscriptions - Android: filter subscribedCharDevicesMap - Windows: GattLocalCharacteristic.SubscribedClients() - Dart: UniversalBlePeripheral.getSubscribedCentrals Made-with: Cursor --- .../universal_ble/UniversalBlePeripheral.g.kt | 273 ++++++++++-- .../UniversalBlePeripheralPlugin.kt | 10 + .../UniversalBlePeripheral.g.swift | 221 ++++++++-- .../UniversalBlePeripheralPlugin.swift | 9 + .../generated/universal_ble_peripheral.g.dart | 414 +++++++++--------- .../universal_ble_peripheral.dart | 5 + .../universal_ble_peripheral_pigeon.dart | 4 + ...sal_ble_peripheral_platform_interface.dart | 8 + pigeon/universal_ble_peripheral.dart | 4 + .../generated/universal_ble_peripheral.g.cpp | 402 +++++++++++++++-- .../generated/universal_ble_peripheral.g.h | 139 +++--- windows/src/universal_ble_plugin.cpp | 20 + windows/src/universal_ble_plugin.h | 2 + 13 files changed, 1137 insertions(+), 374 deletions(-) diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt index fd536512..a5be7b9a 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") @@ -15,15 +15,15 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer private object UniversalBlePeripheralPigeonUtils { - fun createConnectionError(channelName: String): PeripheralFlutterError { - return PeripheralFlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") } + fun createConnectionError(channelName: String): FlutterError { + return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") } fun wrapResult(result: Any?): List { return listOf(result) } fun wrapError(exception: Throwable): List { - return if (exception is PeripheralFlutterError) { + return if (exception is FlutterError) { listOf( exception.code, exception.message, @@ -37,36 +37,150 @@ private object UniversalBlePeripheralPigeonUtils { ) } } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is IntArray && b is IntArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is LongArray && b is LongArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && a.all { - (b as Map).contains(it.key) && - deepEquals(it.value, b[it.key]) + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } - + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } + } /** @@ -75,7 +189,7 @@ private object UniversalBlePeripheralPigeonUtils { * @property message The error message. * @property details The error details. Must be a datatype supported by the api codec. */ -class PeripheralFlutterError ( +class FlutterError ( val code: String, override val message: String? = null, val details: Any? = null @@ -116,15 +230,23 @@ data class PeripheralService ( ) } override fun equals(other: Any?): Boolean { - if (other !is PeripheralService) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as PeripheralService + return UniversalBlePeripheralPigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePeripheralPigeonUtils.deepEquals(this.primary, other.primary) && UniversalBlePeripheralPigeonUtils.deepEquals(this.characteristics, other.characteristics) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.primary) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.characteristics) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -156,15 +278,25 @@ data class PeripheralCharacteristic ( ) } override fun equals(other: Any?): Boolean { - if (other !is PeripheralCharacteristic) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as PeripheralCharacteristic + return UniversalBlePeripheralPigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePeripheralPigeonUtils.deepEquals(this.properties, other.properties) && UniversalBlePeripheralPigeonUtils.deepEquals(this.permissions, other.permissions) && UniversalBlePeripheralPigeonUtils.deepEquals(this.descriptors, other.descriptors) && UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.properties) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.permissions) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.descriptors) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -190,15 +322,23 @@ data class PeripheralDescriptor ( ) } override fun equals(other: Any?): Boolean { - if (other !is PeripheralDescriptor) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as PeripheralDescriptor + return UniversalBlePeripheralPigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) && UniversalBlePeripheralPigeonUtils.deepEquals(this.permissions, other.permissions) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.permissions) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -224,15 +364,23 @@ data class PeripheralReadRequestResult ( ) } override fun equals(other: Any?): Boolean { - if (other !is PeripheralReadRequestResult) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as PeripheralReadRequestResult + return UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) && UniversalBlePeripheralPigeonUtils.deepEquals(this.offset, other.offset) && UniversalBlePeripheralPigeonUtils.deepEquals(this.status, other.status) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.offset) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.status) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -258,15 +406,23 @@ data class PeripheralWriteRequestResult ( ) } override fun equals(other: Any?): Boolean { - if (other !is PeripheralWriteRequestResult) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as PeripheralWriteRequestResult + return UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) && UniversalBlePeripheralPigeonUtils.deepEquals(this.offset, other.offset) && UniversalBlePeripheralPigeonUtils.deepEquals(this.status, other.status) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.offset) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.status) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -289,15 +445,22 @@ data class PeripheralManufacturerData ( ) } override fun equals(other: Any?): Boolean { - if (other !is PeripheralManufacturerData) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePeripheralPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as PeripheralManufacturerData + return UniversalBlePeripheralPigeonUtils.deepEquals(this.manufacturerId, other.manufacturerId) && UniversalBlePeripheralPigeonUtils.deepEquals(this.data, other.data) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.manufacturerId) + result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.data) + return result + } } private open class UniversalBlePeripheralPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { @@ -387,6 +550,11 @@ interface UniversalBlePeripheralChannel { fun getServices(): List fun startAdvertising(services: List, localName: String?, timeout: Long?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Boolean) fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) + /** + * Returns peripheral-central device ids currently subscribed to [characteristicId] + * (e.g. HID report characteristic). Used to restore app state after restart. + */ + fun getSubscribedCentrals(characteristicId: String): List companion object { /** The codec used by UniversalBlePeripheralChannel. */ @@ -568,6 +736,23 @@ interface UniversalBlePeripheralChannel { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val characteristicIdArg = args[0] as String + val wrapped: List = try { + listOf(api.getSubscribedCentrals(characteristicIdArg)) + } catch (exception: Throwable) { + UniversalBlePeripheralPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } } } } @@ -587,7 +772,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { val output = it[0] as PeripheralReadRequestResult? callback(Result.success(output)) @@ -605,7 +790,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { val output = it[0] as PeripheralWriteRequestResult? callback(Result.success(output)) @@ -623,7 +808,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { callback(Result.success(Unit)) } @@ -640,7 +825,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(advertisingArg, errorArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { callback(Result.success(Unit)) } @@ -657,7 +842,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(stateArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { callback(Result.success(Unit)) } @@ -674,7 +859,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(serviceIdArg, errorArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { callback(Result.success(Unit)) } @@ -691,7 +876,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(deviceIdArg, mtuArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { callback(Result.success(Unit)) } @@ -708,7 +893,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(deviceIdArg, connectedArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { callback(Result.success(Unit)) } @@ -725,7 +910,7 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge channel.send(listOf(deviceIdArg, bondStateArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(PeripheralFlutterError(it[0] as String, it[1] as String, it[2] as String?))) + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { callback(Result.success(Unit)) } diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index 1c813a0e..d2b5ea68 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -214,6 +214,16 @@ class UniversalBlePeripheralPlugin( } } + override fun getSubscribedCentrals(characteristicId: String): List { + synchronized(subscribedCharDevicesMap) { + return subscribedCharDevicesMap.entries + .filter { (_, chars) -> + chars.any { it.equals(characteristicId, ignoreCase = true) } + } + .map { it.key } + } + } + private fun isBluetoothEnabled(): Boolean = bluetoothManager.adapter?.isEnabled ?: false diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift index 35c3e6c2..39562a53 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -11,6 +11,24 @@ import Foundation #error("Unsupported platform.") #endif +/// Error class for passing custom error details to Dart side. +final class PigeonError: Error { + let code: String + let message: String? + let details: Sendable? + + init(code: String, message: String?, details: Sendable?) { + self.code = code + self.message = message + self.details = details + } + + var localizedDescription: String { + return + "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + } +} + private func wrapResult(_ result: Any?) -> [Any?] { return [result] } @@ -32,7 +50,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } @@ -50,6 +68,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsUniversalBlePeripheral(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashUniversalBlePeripheral(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8000000000000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsUniversalBlePeripheral(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -60,59 +91,92 @@ func deepEqualsUniversalBlePeripheral(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsUniversalBlePeripheral(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsUniversalBlePeripheral(element, rhsArray[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 !deepEqualsUniversalBlePeripheral(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsUniversalBlePeripheral(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsUniversalBlePeripheral(lhsKey, rhsKey) { + if deepEqualsUniversalBlePeripheral(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsUniversalBlePeripheral(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + 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 deepHashUniversalBlePeripheral(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashUniversalBlePeripheral(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashUniversalBlePeripheral(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashUniversalBlePeripheral(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashUniversalBlePeripheral(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashUniversalBlePeripheral(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashUniversalBlePeripheral(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashUniversalBlePeripheral(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } - enum PeripheralBondState: Int { case bonding = 0 @@ -147,9 +211,17 @@ struct PeripheralService: Hashable { ] } static func == (lhs: PeripheralService, rhs: PeripheralService) -> Bool { - return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBlePeripheral(lhs.uuid, rhs.uuid) && deepEqualsUniversalBlePeripheral(lhs.primary, rhs.primary) && deepEqualsUniversalBlePeripheral(lhs.characteristics, rhs.characteristics) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + hasher.combine("PeripheralService") + deepHashUniversalBlePeripheral(value: uuid, hasher: &hasher) + deepHashUniversalBlePeripheral(value: primary, hasher: &hasher) + deepHashUniversalBlePeripheral(value: characteristics, hasher: &hasher) } } @@ -188,9 +260,19 @@ struct PeripheralCharacteristic: Hashable { ] } static func == (lhs: PeripheralCharacteristic, rhs: PeripheralCharacteristic) -> Bool { - return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBlePeripheral(lhs.uuid, rhs.uuid) && deepEqualsUniversalBlePeripheral(lhs.properties, rhs.properties) && deepEqualsUniversalBlePeripheral(lhs.permissions, rhs.permissions) && deepEqualsUniversalBlePeripheral(lhs.descriptors, rhs.descriptors) && deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + hasher.combine("PeripheralCharacteristic") + deepHashUniversalBlePeripheral(value: uuid, hasher: &hasher) + deepHashUniversalBlePeripheral(value: properties, hasher: &hasher) + deepHashUniversalBlePeripheral(value: permissions, hasher: &hasher) + deepHashUniversalBlePeripheral(value: descriptors, hasher: &hasher) + deepHashUniversalBlePeripheral(value: value, hasher: &hasher) } } @@ -221,9 +303,17 @@ struct PeripheralDescriptor: Hashable { ] } static func == (lhs: PeripheralDescriptor, rhs: PeripheralDescriptor) -> Bool { - return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBlePeripheral(lhs.uuid, rhs.uuid) && deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) && deepEqualsUniversalBlePeripheral(lhs.permissions, rhs.permissions) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + hasher.combine("PeripheralDescriptor") + deepHashUniversalBlePeripheral(value: uuid, hasher: &hasher) + deepHashUniversalBlePeripheral(value: value, hasher: &hasher) + deepHashUniversalBlePeripheral(value: permissions, hasher: &hasher) } } @@ -254,9 +344,17 @@ struct PeripheralReadRequestResult: Hashable { ] } static func == (lhs: PeripheralReadRequestResult, rhs: PeripheralReadRequestResult) -> Bool { - return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) && deepEqualsUniversalBlePeripheral(lhs.offset, rhs.offset) && deepEqualsUniversalBlePeripheral(lhs.status, rhs.status) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + hasher.combine("PeripheralReadRequestResult") + deepHashUniversalBlePeripheral(value: value, hasher: &hasher) + deepHashUniversalBlePeripheral(value: offset, hasher: &hasher) + deepHashUniversalBlePeripheral(value: status, hasher: &hasher) } } @@ -287,9 +385,17 @@ struct PeripheralWriteRequestResult: Hashable { ] } static func == (lhs: PeripheralWriteRequestResult, rhs: PeripheralWriteRequestResult) -> Bool { - return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) && deepEqualsUniversalBlePeripheral(lhs.offset, rhs.offset) && deepEqualsUniversalBlePeripheral(lhs.status, rhs.status) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + hasher.combine("PeripheralWriteRequestResult") + deepHashUniversalBlePeripheral(value: value, hasher: &hasher) + deepHashUniversalBlePeripheral(value: offset, hasher: &hasher) + deepHashUniversalBlePeripheral(value: status, hasher: &hasher) } } @@ -316,9 +422,16 @@ struct PeripheralManufacturerData: Hashable { ] } static func == (lhs: PeripheralManufacturerData, rhs: PeripheralManufacturerData) -> Bool { - return deepEqualsUniversalBlePeripheral(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBlePeripheral(lhs.manufacturerId, rhs.manufacturerId) && deepEqualsUniversalBlePeripheral(lhs.data, rhs.data) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBlePeripheral(value: toList(), hasher: &hasher) + hasher.combine("PeripheralManufacturerData") + deepHashUniversalBlePeripheral(value: manufacturerId, hasher: &hasher) + deepHashUniversalBlePeripheral(value: data, hasher: &hasher) } } @@ -404,6 +517,9 @@ protocol UniversalBlePeripheralChannel { func getServices() throws -> [String] func startAdvertising(services: [String], localName: String?, timeout: Int64?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Bool) throws func updateCharacteristic(characteristicId: String, value: FlutterStandardTypedData, deviceId: String?) throws + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + func getSubscribedCentrals(characteristicId: String) throws -> [String] } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -556,6 +672,23 @@ class UniversalBlePeripheralChannelSetup { } else { updateCharacteristicChannel.setMessageHandler(nil) } + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + let getSubscribedCentralsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getSubscribedCentralsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let characteristicIdArg = args[0] as! String + do { + let result = try api.getSubscribedCentrals(characteristicId: characteristicIdArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getSubscribedCentralsChannel.setMessageHandler(nil) + } } } /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index b96e253d..1c069b97 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -280,4 +280,13 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne centralCharacteristicSubscriptions.removeAll() centralsLock.unlock() } + + func getSubscribedCentrals(characteristicId: String) throws -> [String] { + let target = characteristicId.uppercased() + centralsLock.lock() + defer { centralsLock.unlock() } + return centralCharacteristicSubscriptions.compactMap { centralId, chars in + chars.contains(where: { $0.uppercased() == target }) ? centralId : nil + } + } } diff --git a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart index b6e935c2..7a79b91b 100644 --- a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart +++ b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: unused_import, unused_shown_name // ignore_for_file: type=lint @@ -10,9 +10,9 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; Object? _extractReplyValueOrThrow( - List? replyList, - String channelName, { - required bool isNullValid, + List? replyList, + String channelName, { + required bool isNullValid, }) { if (replyList == null) { throw PlatformException( @@ -34,8 +34,8 @@ Object? _extractReplyValueOrThrow( return replyList.firstOrNull; } -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { + +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -44,22 +44,69 @@ List wrapResponse( } return [error.code, error.message, error.details]; } - bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == 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 entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key])); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + + enum PeripheralBondState { bonding, bonded, @@ -88,16 +135,14 @@ class PeripheralService { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralService decode(Object result) { result as List; return PeripheralService( uuid: result[0]! as String, primary: result[1]! as bool, - characteristics: - (result[2]! as List).cast(), + characteristics: (result[2]! as List).cast(), ); } @@ -110,12 +155,12 @@ class PeripheralService { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(uuid, other.uuid) && _deepEquals(primary, other.primary) && _deepEquals(characteristics, other.characteristics); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PeripheralCharacteristic { @@ -148,8 +193,7 @@ class PeripheralCharacteristic { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralCharacteristic decode(Object result) { result as List; @@ -165,19 +209,18 @@ class PeripheralCharacteristic { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralCharacteristic || - other.runtimeType != runtimeType) { + if (other is! PeripheralCharacteristic || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(permissions, other.permissions) && _deepEquals(descriptors, other.descriptors) && _deepEquals(value, other.value); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PeripheralDescriptor { @@ -202,8 +245,7 @@ class PeripheralDescriptor { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralDescriptor decode(Object result) { result as List; @@ -223,12 +265,12 @@ class PeripheralDescriptor { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(uuid, other.uuid) && _deepEquals(value, other.value) && _deepEquals(permissions, other.permissions); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PeripheralReadRequestResult { @@ -253,8 +295,7 @@ class PeripheralReadRequestResult { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralReadRequestResult decode(Object result) { result as List; @@ -268,19 +309,18 @@ class PeripheralReadRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralReadRequestResult || - other.runtimeType != runtimeType) { + if (other is! PeripheralReadRequestResult || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PeripheralWriteRequestResult { @@ -305,8 +345,7 @@ class PeripheralWriteRequestResult { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralWriteRequestResult decode(Object result) { result as List; @@ -320,19 +359,18 @@ class PeripheralWriteRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralWriteRequestResult || - other.runtimeType != runtimeType) { + if (other is! PeripheralWriteRequestResult || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PeripheralManufacturerData { @@ -353,8 +391,7 @@ class PeripheralManufacturerData { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralManufacturerData decode(Object result) { result as List; @@ -367,21 +404,21 @@ class PeripheralManufacturerData { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralManufacturerData || - other.runtimeType != runtimeType) { + if (other is! PeripheralManufacturerData || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(manufacturerId, other.manufacturerId) && _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -389,25 +426,25 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is PeripheralBondState) { + } else if (value is PeripheralBondState) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is PeripheralService) { + } else if (value is PeripheralService) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else if (value is PeripheralCharacteristic) { + } else if (value is PeripheralCharacteristic) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is PeripheralDescriptor) { + } else if (value is PeripheralDescriptor) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is PeripheralReadRequestResult) { + } else if (value is PeripheralReadRequestResult) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is PeripheralWriteRequestResult) { + } else if (value is PeripheralWriteRequestResult) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is PeripheralManufacturerData) { + } else if (value is PeripheralManufacturerData) { buffer.putUint8(135); writeValue(buffer, value.encode()); } else { @@ -443,11 +480,9 @@ class UniversalBlePeripheralChannel { /// Constructor for [UniversalBlePeripheralChannel]. 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. - UniversalBlePeripheralChannel( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + UniversalBlePeripheralChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -455,8 +490,7 @@ class UniversalBlePeripheralChannel { final String pigeonVar_messageChannelSuffix; Future initialize() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -466,15 +500,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future isAdvertising() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -484,16 +518,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; return pigeonVar_replyValue as bool?; } Future isSupported() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -503,16 +537,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future stopAdvertising() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -522,53 +556,51 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future addService(PeripheralService service) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([service]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([service]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future removeService(String serviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([serviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([serviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future clearServices() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -578,15 +610,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future> getServices() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -596,75 +628,80 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return (pigeonVar_replyValue! as List).cast(); } - Future startAdvertising( - List services, - String? localName, - int? timeout, - PeripheralManufacturerData? manufacturerData, - bool addManufacturerDataInScanResponse) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; + Future startAdvertising(List services, String? localName, int? timeout, PeripheralManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([ - services, - localName, - timeout, - manufacturerData, - addManufacturerDataInScanResponse - ]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([services, localName, timeout, manufacturerData, addManufacturerDataInScanResponse]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } - Future updateCharacteristic( - String characteristicId, Uint8List value, String? deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; + Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([characteristicId, value, deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId, value, deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } + + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + Future> getSubscribedCentrals(String characteristicId) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, - isNullValid: true, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return (pigeonVar_replyValue! as List).cast(); } } abstract class UniversalBlePeripheralCallback { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - PeripheralReadRequestResult? onReadRequest( - String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - PeripheralWriteRequestResult? onWriteRequest( - String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralWriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - void onCharacteristicSubscriptionChange(String deviceId, - String characteristicId, bool isSubscribed, String? name); + void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); void onAdvertisingStatusUpdate(bool advertising, String? error); @@ -678,17 +715,11 @@ abstract class UniversalBlePeripheralCallback { void onBondStateChange(String deviceId, PeripheralBondState bondState); - static void setUp( - UniversalBlePeripheralCallback? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(UniversalBlePeripheralCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -700,22 +731,19 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralReadRequestResult? output = api.onReadRequest( - arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralReadRequestResult? output = api.onReadRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -727,22 +755,19 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralWriteRequestResult? output = api.onWriteRequest( - arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralWriteRequestResult? output = api.onWriteRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -754,22 +779,19 @@ abstract class UniversalBlePeripheralCallback { final bool arg_isSubscribed = args[2]! as bool; final String? arg_name = args[3] as String?; try { - api.onCharacteristicSubscriptionChange( - arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); + api.onCharacteristicSubscriptionChange(arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -783,17 +805,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -806,17 +826,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -830,17 +848,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -854,17 +870,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -878,17 +892,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -896,16 +908,14 @@ abstract class UniversalBlePeripheralCallback { pigeonVar_channel.setMessageHandler((Object? message) async { final List args = message! as List; final String arg_deviceId = args[0]! as String; - final PeripheralBondState arg_bondState = - args[1]! as PeripheralBondState; + final PeripheralBondState arg_bondState = args[1]! as PeripheralBondState; try { api.onBondStateChange(arg_deviceId, arg_bondState); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart index 66f3fd91..14869b5b 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -61,6 +61,11 @@ class UniversalBlePeripheral { deviceId: deviceId, ); + /// Returns central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore in-app state after restart. + static Future> getSubscribedCentrals(String characteristicId) => + _platform.getSubscribedCentrals(BleUuidParser.string(characteristicId)); + static set onAdvertisingStatusUpdate( OnPeripheralAdvertisingStatusUpdate? callback, ) { diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index 48188428..125fef7e 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -108,6 +108,10 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform ); } + @override + Future> getSubscribedCentrals(String characteristicId) => + _channel.getSubscribedCentrals(characteristicId); + @override void onAdvertisingStatusUpdate(bool advertising, String? error) { super.advertisingStatusUpdateCallback?.call(advertising, error); diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart index ac023d42..fc6068d6 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -75,6 +75,9 @@ abstract class UniversalBlePeripheralPlatform { String? deviceId, }); + /// Returns GATT central device ids currently subscribed to [characteristicId]. + Future> getSubscribedCentrals(String characteristicId); + /// Called when this platform implementation is being replaced. /// /// Default is no-op so existing custom implementations remain compatible. @@ -146,4 +149,9 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { }) async { throw _notSupported(); } + + @override + Future> getSubscribedCentrals(String characteristicId) async { + throw _notSupported(); + } } diff --git a/pigeon/universal_ble_peripheral.dart b/pigeon/universal_ble_peripheral.dart index ea63613f..501823dc 100644 --- a/pigeon/universal_ble_peripheral.dart +++ b/pigeon/universal_ble_peripheral.dart @@ -90,6 +90,10 @@ abstract class UniversalBlePeripheralChannel { Uint8List value, String? deviceId, ); + + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + List getSubscribedCentrals(String characteristicId); } @FlutterApi() diff --git a/windows/src/generated/universal_ble_peripheral.g.cpp b/windows/src/generated/universal_ble_peripheral.g.cpp index a396cb6a..1ae07130 100644 --- a/windows/src/generated/universal_ble_peripheral.g.cpp +++ b/windows/src/generated/universal_ble_peripheral.g.cpp @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS @@ -10,16 +10,18 @@ #include #include +#include +#include #include #include #include namespace universal_ble { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -28,6 +30,201 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +namespace { +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b); + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b) { + if (a.get() == b.get()) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 1; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result += ((PigeonInternalDeepHash(kv.first) * 31) ^ PigeonInternalDeepHash(kv.second)); + } + return result; +} + +size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + +} // namespace // PeripheralService PeripheralService::PeripheralService( @@ -82,6 +279,26 @@ PeripheralService PeripheralService::FromEncodableList(const EncodableList& list return decoded; } +bool PeripheralService::operator==(const PeripheralService& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(primary_, other.primary_) && PigeonInternalDeepEquals(characteristics_, other.characteristics_); +} + +bool PeripheralService::operator!=(const PeripheralService& other) const { + return !(*this == other); +} + +size_t PeripheralService::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(primary_); + result = result * 31 + PigeonInternalDeepHash(characteristics_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralService& v) { + return v.Hash(); +} + // PeripheralCharacteristic PeripheralCharacteristic::PeripheralCharacteristic( @@ -184,6 +401,28 @@ PeripheralCharacteristic PeripheralCharacteristic::FromEncodableList(const Encod return decoded; } +bool PeripheralCharacteristic::operator==(const PeripheralCharacteristic& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(properties_, other.properties_) && PigeonInternalDeepEquals(permissions_, other.permissions_) && PigeonInternalDeepEquals(descriptors_, other.descriptors_) && PigeonInternalDeepEquals(value_, other.value_); +} + +bool PeripheralCharacteristic::operator!=(const PeripheralCharacteristic& other) const { + return !(*this == other); +} + +size_t PeripheralCharacteristic::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(properties_); + result = result * 31 + PigeonInternalDeepHash(permissions_); + result = result * 31 + PigeonInternalDeepHash(descriptors_); + result = result * 31 + PigeonInternalDeepHash(value_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralCharacteristic& v) { + return v.Hash(); +} + // PeripheralDescriptor PeripheralDescriptor::PeripheralDescriptor(const std::string& uuid) @@ -255,6 +494,26 @@ PeripheralDescriptor PeripheralDescriptor::FromEncodableList(const EncodableList return decoded; } +bool PeripheralDescriptor::operator==(const PeripheralDescriptor& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(permissions_, other.permissions_); +} + +bool PeripheralDescriptor::operator!=(const PeripheralDescriptor& other) const { + return !(*this == other); +} + +size_t PeripheralDescriptor::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(value_); + result = result * 31 + PigeonInternalDeepHash(permissions_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralDescriptor& v) { + return v.Hash(); +} + // PeripheralReadRequestResult PeripheralReadRequestResult::PeripheralReadRequestResult(const std::vector& value) @@ -326,6 +585,26 @@ PeripheralReadRequestResult PeripheralReadRequestResult::FromEncodableList(const return decoded; } +bool PeripheralReadRequestResult::operator==(const PeripheralReadRequestResult& other) const { + return PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(offset_, other.offset_) && PigeonInternalDeepEquals(status_, other.status_); +} + +bool PeripheralReadRequestResult::operator!=(const PeripheralReadRequestResult& other) const { + return !(*this == other); +} + +size_t PeripheralReadRequestResult::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(value_); + result = result * 31 + PigeonInternalDeepHash(offset_); + result = result * 31 + PigeonInternalDeepHash(status_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralReadRequestResult& v) { + return v.Hash(); +} + // PeripheralWriteRequestResult PeripheralWriteRequestResult::PeripheralWriteRequestResult() {} @@ -403,6 +682,26 @@ PeripheralWriteRequestResult PeripheralWriteRequestResult::FromEncodableList(con return decoded; } +bool PeripheralWriteRequestResult::operator==(const PeripheralWriteRequestResult& other) const { + return PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(offset_, other.offset_) && PigeonInternalDeepEquals(status_, other.status_); +} + +bool PeripheralWriteRequestResult::operator!=(const PeripheralWriteRequestResult& other) const { + return !(*this == other); +} + +size_t PeripheralWriteRequestResult::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(value_); + result = result * 31 + PigeonInternalDeepHash(offset_); + result = result * 31 + PigeonInternalDeepHash(status_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralWriteRequestResult& v) { + return v.Hash(); +} + // PeripheralManufacturerData PeripheralManufacturerData::PeripheralManufacturerData( @@ -444,12 +743,31 @@ PeripheralManufacturerData PeripheralManufacturerData::FromEncodableList(const E return decoded; } +bool PeripheralManufacturerData::operator==(const PeripheralManufacturerData& other) const { + return PigeonInternalDeepEquals(manufacturer_id_, other.manufacturer_id_) && PigeonInternalDeepEquals(data_, other.data_); +} + +bool PeripheralManufacturerData::operator!=(const PeripheralManufacturerData& other) const { + return !(*this == other); +} + +size_t PeripheralManufacturerData::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(manufacturer_id_); + result = result * 31 + PigeonInternalDeepHash(data_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralManufacturerData& v) { + return v.Hash(); +} + PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( uint8_t type, - flutter::ByteStreamReader* stream) const { + ::flutter::ByteStreamReader* stream) const { switch (type) { case 129: { const auto& encodable_enum_arg = ReadValue(stream); @@ -475,13 +793,13 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( return CustomEncodableValue(PeripheralManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); } default: - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } } void PigeonInternalCodecSerializer::WriteValue( const EncodableValue& value, - flutter::ByteStreamWriter* stream) const { + ::flutter::ByteStreamWriter* stream) const { if (const CustomEncodableValue* custom_value = std::get_if(&value)) { if (custom_value->type() == typeid(PeripheralBondState)) { stream->WriteByte(129); @@ -519,30 +837,30 @@ void PigeonInternalCodecSerializer::WriteValue( return; } } - flutter::StandardCodecSerializer::WriteValue(value, stream); + ::flutter::StandardCodecSerializer::WriteValue(value, stream); } /// The codec used by UniversalBlePeripheralChannel. -const flutter::StandardMessageCodec& UniversalBlePeripheralChannel::GetCodec() { - return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +const ::flutter::StandardMessageCodec& UniversalBlePeripheralChannel::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. void UniversalBlePeripheralChannel::SetUp( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, UniversalBlePeripheralChannel* api) { UniversalBlePeripheralChannel::SetUp(binary_messenger, api, ""); } void UniversalBlePeripheralChannel::SetUp( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, UniversalBlePeripheralChannel* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { std::optional output = api->Initialize(); if (output.has_value()) { @@ -563,7 +881,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { ErrorOr> output = api->IsAdvertising(); if (output.has_error()) { @@ -589,7 +907,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { ErrorOr output = api->IsSupported(); if (output.has_error()) { @@ -610,7 +928,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { std::optional output = api->StopAdvertising(); if (output.has_value()) { @@ -631,7 +949,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_service_arg = args.at(0); @@ -659,7 +977,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_service_id_arg = args.at(0); @@ -687,7 +1005,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { std::optional output = api->ClearServices(); if (output.has_value()) { @@ -708,7 +1026,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { ErrorOr output = api->GetServices(); if (output.has_error()) { @@ -729,7 +1047,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_services_arg = args.at(0); @@ -769,7 +1087,7 @@ void UniversalBlePeripheralChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_characteristic_id_arg = args.at(0); @@ -802,6 +1120,34 @@ void UniversalBlePeripheralChannel::SetUp( channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_characteristic_id_arg = args.at(0); + if (encodable_characteristic_id_arg.IsNull()) { + reply(WrapError("characteristic_id_arg unexpectedly null.")); + return; + } + const auto& characteristic_id_arg = std::get(encodable_characteristic_id_arg); + ErrorOr output = api->GetSubscribedCentrals(characteristic_id_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } } EncodableValue UniversalBlePeripheralChannel::WrapError(std::string_view error_message) { @@ -821,18 +1167,18 @@ EncodableValue UniversalBlePeripheralChannel::WrapError(const FlutterError& erro } // Generated class from Pigeon that represents Flutter messages that can be called from C++. -UniversalBlePeripheralCallback::UniversalBlePeripheralCallback(flutter::BinaryMessenger* binary_messenger) +UniversalBlePeripheralCallback::UniversalBlePeripheralCallback(::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} UniversalBlePeripheralCallback::UniversalBlePeripheralCallback( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& UniversalBlePeripheralCallback::GetCodec() { - return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +const ::flutter::StandardMessageCodec& UniversalBlePeripheralCallback::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); } void UniversalBlePeripheralCallback::OnReadRequest( diff --git a/windows/src/generated/universal_ble_peripheral.g.h b/windows/src/generated/universal_ble_peripheral.g.h index 6a5a8660..32a7047b 100644 --- a/windows/src/generated/universal_ble_peripheral.g.h +++ b/windows/src/generated/universal_ble_peripheral.g.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_UNIVERSAL_BLE_PERIPHERAL_G_H_ @@ -23,17 +23,17 @@ class FlutterError { : code_(code) {} explicit FlutterError(const std::string& code, const std::string& message) : code_(code), message_(message) {} - explicit FlutterError(const std::string& code, const std::string& message, const flutter::EncodableValue& details) + explicit FlutterError(const std::string& code, const std::string& message, const ::flutter::EncodableValue& details) : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; template class ErrorOr { @@ -71,7 +71,7 @@ class PeripheralService { explicit PeripheralService( const std::string& uuid, bool primary, - const flutter::EncodableList& characteristics); + const ::flutter::EncodableList& characteristics); const std::string& uuid() const; void set_uuid(std::string_view value_arg); @@ -79,18 +79,22 @@ class PeripheralService { bool primary() const; void set_primary(bool value_arg); - const flutter::EncodableList& characteristics() const; - void set_characteristics(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& characteristics() const; + void set_characteristics(const ::flutter::EncodableList& value_arg); + bool operator==(const PeripheralService& other) const; + bool operator!=(const PeripheralService& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static PeripheralService FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static PeripheralService FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePeripheralChannel; friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::string uuid_; bool primary_; - flutter::EncodableList characteristics_; + ::flutter::EncodableList characteristics_; }; @@ -100,44 +104,48 @@ class PeripheralCharacteristic { // Constructs an object setting all non-nullable fields. explicit PeripheralCharacteristic( const std::string& uuid, - const flutter::EncodableList& properties, - const flutter::EncodableList& permissions); + const ::flutter::EncodableList& properties, + const ::flutter::EncodableList& permissions); // Constructs an object setting all fields. explicit PeripheralCharacteristic( const std::string& uuid, - const flutter::EncodableList& properties, - const flutter::EncodableList& permissions, - const flutter::EncodableList* descriptors, + const ::flutter::EncodableList& properties, + const ::flutter::EncodableList& permissions, + const ::flutter::EncodableList* descriptors, const std::vector* value); const std::string& uuid() const; void set_uuid(std::string_view value_arg); - const flutter::EncodableList& properties() const; - void set_properties(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& properties() const; + void set_properties(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& permissions() const; - void set_permissions(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& permissions() const; + void set_permissions(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList* descriptors() const; - void set_descriptors(const flutter::EncodableList* value_arg); - void set_descriptors(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* descriptors() const; + void set_descriptors(const ::flutter::EncodableList* value_arg); + void set_descriptors(const ::flutter::EncodableList& value_arg); const std::vector* value() const; void set_value(const std::vector* value_arg); void set_value(const std::vector& value_arg); + bool operator==(const PeripheralCharacteristic& other) const; + bool operator!=(const PeripheralCharacteristic& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static PeripheralCharacteristic FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static PeripheralCharacteristic FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePeripheralChannel; friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::string uuid_; - flutter::EncodableList properties_; - flutter::EncodableList permissions_; - std::optional descriptors_; + ::flutter::EncodableList properties_; + ::flutter::EncodableList permissions_; + std::optional<::flutter::EncodableList> descriptors_; std::optional> value_; }; @@ -152,7 +160,7 @@ class PeripheralDescriptor { explicit PeripheralDescriptor( const std::string& uuid, const std::vector* value, - const flutter::EncodableList* permissions); + const ::flutter::EncodableList* permissions); const std::string& uuid() const; void set_uuid(std::string_view value_arg); @@ -161,19 +169,23 @@ class PeripheralDescriptor { void set_value(const std::vector* value_arg); void set_value(const std::vector& value_arg); - const flutter::EncodableList* permissions() const; - void set_permissions(const flutter::EncodableList* value_arg); - void set_permissions(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* permissions() const; + void set_permissions(const ::flutter::EncodableList* value_arg); + void set_permissions(const ::flutter::EncodableList& value_arg); + bool operator==(const PeripheralDescriptor& other) const; + bool operator!=(const PeripheralDescriptor& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static PeripheralDescriptor FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static PeripheralDescriptor FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePeripheralChannel; friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::string uuid_; std::optional> value_; - std::optional permissions_; + std::optional<::flutter::EncodableList> permissions_; }; @@ -200,9 +212,13 @@ class PeripheralReadRequestResult { void set_status(const int64_t* value_arg); void set_status(int64_t value_arg); + bool operator==(const PeripheralReadRequestResult& other) const; + bool operator!=(const PeripheralReadRequestResult& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static PeripheralReadRequestResult FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static PeripheralReadRequestResult FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePeripheralChannel; friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; @@ -236,9 +252,13 @@ class PeripheralWriteRequestResult { void set_status(const int64_t* value_arg); void set_status(int64_t value_arg); + bool operator==(const PeripheralWriteRequestResult& other) const; + bool operator!=(const PeripheralWriteRequestResult& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static PeripheralWriteRequestResult FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static PeripheralWriteRequestResult FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePeripheralChannel; friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; @@ -262,9 +282,13 @@ class PeripheralManufacturerData { const std::vector& data() const; void set_data(const std::vector& value_arg); + bool operator==(const PeripheralManufacturerData& other) const; + bool operator!=(const PeripheralManufacturerData& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static PeripheralManufacturerData FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static PeripheralManufacturerData FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePeripheralChannel; friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; @@ -273,7 +297,7 @@ class PeripheralManufacturerData { }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { +class PigeonInternalCodecSerializer : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -282,12 +306,12 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { } void WriteValue( - const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; + const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( + ::flutter::EncodableValue ReadValueOfType( uint8_t type, - flutter::ByteStreamReader* stream) const override; + ::flutter::ByteStreamReader* stream) const override; }; // Generated interface from Pigeon that represents a handler of messages from Flutter. @@ -303,9 +327,9 @@ class UniversalBlePeripheralChannel { virtual std::optional AddService(const PeripheralService& service) = 0; virtual std::optional RemoveService(const std::string& service_id) = 0; virtual std::optional ClearServices() = 0; - virtual ErrorOr GetServices() = 0; + virtual ErrorOr<::flutter::EncodableList> GetServices() = 0; virtual std::optional StartAdvertising( - const flutter::EncodableList& services, + const ::flutter::EncodableList& services, const std::string* local_name, const int64_t* timeout, const PeripheralManufacturerData* manufacturer_data, @@ -314,30 +338,33 @@ class UniversalBlePeripheralChannel { const std::string& characteristic_id, const std::vector& value, const std::string* device_id) = 0; + // Returns peripheral-central device ids currently subscribed to [characteristicId] + // (e.g. HID report characteristic). Used to restore app state after restart. + virtual ErrorOr<::flutter::EncodableList> GetSubscribedCentrals(const std::string& characteristic_id) = 0; // The codec used by UniversalBlePeripheralChannel. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. static void SetUp( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, UniversalBlePeripheralChannel* api); static void SetUp( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, UniversalBlePeripheralChannel* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: UniversalBlePeripheralChannel() = default; }; // Generated class from Pigeon that represents Flutter messages that can be called from C++. class UniversalBlePeripheralCallback { public: - UniversalBlePeripheralCallback(flutter::BinaryMessenger* binary_messenger); + UniversalBlePeripheralCallback(::flutter::BinaryMessenger* binary_messenger); UniversalBlePeripheralCallback( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); void OnReadRequest( const std::string& device_id, const std::string& characteristic_id, @@ -389,7 +416,7 @@ class UniversalBlePeripheralCallback { std::function&& on_success, std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index da2c8415..d8582082 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -1690,6 +1690,26 @@ ErrorOr UniversalBlePlugin::GetServices() { return services; } +ErrorOr UniversalBlePlugin::GetSubscribedCentrals( + const std::string &characteristic_id) { + std::lock_guard lock(peripheral_mutex_); + flutter::EncodableList out; + auto *char_obj = FindPeripheralGattCharacteristicObject(characteristic_id); + if (char_obj == nullptr || char_obj->obj == nullptr) { + return out; + } + try { + auto clients = char_obj->obj.SubscribedClients(); + for (uint32_t i = 0; i < clients.Size(); ++i) { + auto client = clients.GetAt(i); + out.push_back(flutter::EncodableValue(ParsePeripheralBluetoothClientId( + client.Session().DeviceId().Id()))); + } + } catch (...) { + } + return out; +} + std::optional UniversalBlePlugin::StartAdvertising( const flutter::EncodableList &services, const std::string *local_name, const int64_t *timeout, diff --git a/windows/src/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h index e3b424e5..deb4ce79 100644 --- a/windows/src/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -298,6 +298,8 @@ class UniversalBlePlugin : public flutter::Plugin, std::optional UpdateCharacteristic( const std::string &characteristic_id, const std::vector &value, const std::string *device_id) override; + ErrorOr GetSubscribedCentrals( + const std::string &characteristic_id) override; }; } // namespace universal_ble From 4d75b6eb9c0a8e3c56337e22c428e837f764e7fb Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 21:07:03 +0100 Subject: [PATCH 08/23] Format files --- .../ble_characteristic_extension.dart | 2 +- lib/src/models/ble_capabilities.dart | 5 +- lib/src/models/ble_device.dart | 6 +- lib/src/models/ble_service.dart | 14 +- lib/src/models/ble_uuid_parser.dart | 3 +- lib/src/universal_ble.dart | 73 ++-- lib/src/universal_ble_exceptions.dart | 20 +- .../universal_ble_linux.dart | 138 ++++--- .../generated/universal_ble_peripheral.g.dart | 356 +++++++++++------- .../universal_ble_pigeon/universal_ble.g.dart | 28 +- .../universal_ble_pigeon_channel.dart | 35 +- lib/src/universal_ble_platform_interface.dart | 52 ++- 12 files changed, 391 insertions(+), 341 deletions(-) diff --git a/lib/src/extensions/ble_characteristic_extension.dart b/lib/src/extensions/ble_characteristic_extension.dart index f277ce63..6107abb2 100644 --- a/lib/src/extensions/ble_characteristic_extension.dart +++ b/lib/src/extensions/ble_characteristic_extension.dart @@ -85,7 +85,7 @@ class CharacteristicSubscription { final bool isSupported; CharacteristicSubscription(this._characteristic, this._property) - : isSupported = _characteristic.properties.contains(_property); + : isSupported = _characteristic.properties.contains(_property); /// Registers a listener for incoming data from the characteristic. StreamSubscription listen( diff --git a/lib/src/models/ble_capabilities.dart b/lib/src/models/ble_capabilities.dart index baa93e3d..f54a7ae6 100644 --- a/lib/src/models/ble_capabilities.dart +++ b/lib/src/models/ble_capabilities.dart @@ -22,11 +22,10 @@ class BleCapabilities { /// but it very unreliable, therefore we return false. static final triggersConfirmOnlyPairing = defaultTargetPlatform != TargetPlatform.windows && - defaultTargetPlatform != TargetPlatform.linux; + defaultTargetPlatform != TargetPlatform.linux; /// Returns true if pair()/unpair() are supported on the platform. - static bool hasSystemPairingApi = - !kIsWeb && + static bool hasSystemPairingApi = !kIsWeb && (defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.windows || defaultTargetPlatform == TargetPlatform.linux); diff --git a/lib/src/models/ble_device.dart b/lib/src/models/ble_device.dart index 464d7e8d..87aefbda 100644 --- a/lib/src/models/ble_device.dart +++ b/lib/src/models/ble_device.dart @@ -55,9 +55,9 @@ class BleDevice { this.manufacturerDataList = const [], Map serviceData = const {}, this.timestamp, - }) : serviceData = _validateServiceData(serviceData), - rawName = name, - name = name?.replaceAll(RegExp(r'[^ -~]'), '').trim(); + }) : serviceData = _validateServiceData(serviceData), + rawName = name, + name = name?.replaceAll(RegExp(r'[^ -~]'), '').trim(); DateTime? get timestampDateTime => timestamp != null ? DateTime.fromMillisecondsSinceEpoch(timestamp!) diff --git a/lib/src/models/ble_service.dart b/lib/src/models/ble_service.dart index ee179e29..4ab2f133 100644 --- a/lib/src/models/ble_service.dart +++ b/lib/src/models/ble_service.dart @@ -5,7 +5,7 @@ class BleService { List characteristics; BleService(String uuid, this.characteristics) - : uuid = BleUuidParser.string(uuid); + : uuid = BleUuidParser.string(uuid); @override String toString() { @@ -20,7 +20,7 @@ class BleCharacteristic { ({String deviceId, String serviceId})? metaData; BleCharacteristic(String uuid, this.properties, this.descriptors) - : uuid = BleUuidParser.string(uuid); + : uuid = BleUuidParser.string(uuid); BleCharacteristic.withMetaData({ required String deviceId, @@ -28,11 +28,11 @@ class BleCharacteristic { required String uuid, required this.properties, required this.descriptors, - }) : uuid = BleUuidParser.string(uuid), - metaData = ( - deviceId: deviceId, - serviceId: BleUuidParser.string(serviceId), - ); + }) : uuid = BleUuidParser.string(uuid), + metaData = ( + deviceId: deviceId, + serviceId: BleUuidParser.string(serviceId), + ); @override String toString() { diff --git a/lib/src/models/ble_uuid_parser.dart b/lib/src/models/ble_uuid_parser.dart index c157b7aa..8ab3ba10 100644 --- a/lib/src/models/ble_uuid_parser.dart +++ b/lib/src/models/ble_uuid_parser.dart @@ -20,8 +20,7 @@ class BleUuidParser { if (!uuid.contains("-")) { if (uuid.length != 32) throw const FormatException("Invalid UUID"); - uuid = - "${uuid.substring(0, 8)}-${uuid.substring(8, 12)}" + uuid = "${uuid.substring(0, 8)}-${uuid.substring(8, 12)}" "-${uuid.substring(12, 16)}-${uuid.substring(16, 20)}-${uuid.substring(20, 32)}"; } diff --git a/lib/src/universal_ble.dart b/lib/src/universal_ble.dart index 70627e61..91b71798 100644 --- a/lib/src/universal_ble.dart +++ b/lib/src/universal_ble.dart @@ -58,7 +58,8 @@ class UniversalBle { static Stream characteristicValueStream( String deviceId, String characteristicId, - ) => _platform.characteristicValueStream(deviceId, characteristicId); + ) => + _platform.characteristicValueStream(deviceId, characteristicId); /// Pairing state stream static Stream pairingStateStream(String deviceId) => @@ -155,9 +156,9 @@ class UniversalBle { _platform .connect(deviceId, connectionTimeout: timeout, autoConnect: autoConnect) .catchError((error) { - if (completer.isCompleted) return; - completer.completeError(ConnectionException(error)); - }); + if (completer.isCompleted) return; + completer.completeError(ConnectionException(error)); + }); if (!await completer.future.timeout(timeout)) { throw ConnectionException("Failed to connect"); @@ -183,14 +184,14 @@ class UniversalBle { await _bleCommandQueue .queueCommand( - () => _platform.disconnect(deviceId), - timeout: timeout, - deviceId: deviceId, - ) + () => _platform.disconnect(deviceId), + timeout: timeout, + deviceId: deviceId, + ) .catchError((error) { - if (completer.isCompleted) return; - completer.completeError(ConnectionException(error)); - }); + if (completer.isCompleted) return; + completer.completeError(ConnectionException(error)); + }); if (connectionState == BleConnectionState.disconnected || connectionState == BleConnectionState.disconnecting) { @@ -547,11 +548,9 @@ class UniversalBle { static set onAvailabilityChange(OnAvailabilityChange? onAvailabilityChange) { _platform.onAvailabilityChange = onAvailabilityChange; if (onAvailabilityChange != null) { - getBluetoothAvailabilityState() - .then((value) { - onAvailabilityChange(value); - }) - .onError((error, stackTrace) => null); + getBluetoothAvailabilityState().then((value) { + onAvailabilityChange(value); + }).onError((error, stackTrace) => null); } } @@ -619,32 +618,28 @@ class UniversalBle { } connectionSubscription = _platform - .bleConnectionUpdateStreamController - .stream + .bleConnectionUpdateStreamController.stream .where((e) => e.deviceId == deviceId) .listen( - (e) { - cancelSubscription(); - if (e.error != null) { - handleError(e.error); - } else { - if (!completer.isCompleted) { - completer.complete(e.isConnected); - } - } - }, - onError: handleError, - cancelOnError: true, - ); + (e) { + cancelSubscription(); + if (e.error != null) { + handleError(e.error); + } else { + if (!completer.isCompleted) { + completer.complete(e.isConnected); + } + } + }, + onError: handleError, + cancelOnError: true, + ); - completer.future - .timeout(timeout) - .then((_) { - cancelSubscription(); - }) - .catchError((_) { - cancelSubscription(); - }); + completer.future.timeout(timeout).then((_) { + cancelSubscription(); + }).catchError((_) { + cancelSubscription(); + }); return completer; } diff --git a/lib/src/universal_ble_exceptions.dart b/lib/src/universal_ble_exceptions.dart index 0ce8c82d..194284d7 100644 --- a/lib/src/universal_ble_exceptions.dart +++ b/lib/src/universal_ble_exceptions.dart @@ -42,11 +42,11 @@ class ConnectionException extends UniversalBleException { }); ConnectionException([dynamic error]) - : this._( - code: UniversalBleErrorParser.getCode(error), - message: _errorParser(error), - details: error, - ); + : this._( + code: UniversalBleErrorParser.getCode(error), + message: _errorParser(error), + details: error, + ); } /// Exception thrown when pairing-related errors occur @@ -59,11 +59,11 @@ class PairingException extends UniversalBleException { /// Legacy constructor for backward compatibility PairingException([dynamic error]) - : this._( - code: UniversalBleErrorParser.getCode(error), - message: _errorParser(error), - details: error, - ); + : this._( + code: UniversalBleErrorParser.getCode(error), + message: _errorParser(error), + details: error, + ); } /// Exception thrown when Web Bluetooth API is globally disabled diff --git a/lib/src/universal_ble_linux/universal_ble_linux.dart b/lib/src/universal_ble_linux/universal_ble_linux.dart index aa94693b..66a3398f 100644 --- a/lib/src/universal_ble_linux/universal_ble_linux.dart +++ b/lib/src/universal_ble_linux/universal_ble_linux.dart @@ -171,25 +171,23 @@ class UniversalBleLinux extends UniversalBlePlatform { ) async { final device = _findDeviceById(deviceId); if (device.gattServices.isEmpty && !device.servicesResolved) { - await device.propertiesChanged - .firstWhere((element) { - if (element.contains(BluezProperty.connected)) { - if (!device.connected) { - UniversalLogger.logInfo( - "DiscoverServicesFailed: Device disconnected", - ); - return true; - } - } - return element.contains(BluezProperty.servicesResolved); - }) - .timeout( - const Duration(seconds: 10), - onTimeout: () { - UniversalLogger.logInfo("DiscoverServicesFailed: Timeout"); - return []; - }, - ); + await device.propertiesChanged.firstWhere((element) { + if (element.contains(BluezProperty.connected)) { + if (!device.connected) { + UniversalLogger.logInfo( + "DiscoverServicesFailed: Device disconnected", + ); + return true; + } + } + return element.contains(BluezProperty.servicesResolved); + }).timeout( + const Duration(seconds: 10), + onTimeout: () { + UniversalLogger.logInfo("DiscoverServicesFailed: Timeout"); + return []; + }, + ); } // Few ble devices requires delay to perform operations after discovering services @@ -220,8 +218,8 @@ class UniversalBleLinux extends UniversalBlePlatform { properties: properties, descriptors: withDescriptors ? e.descriptors - .map((e) => BleDescriptor(e.uuid.toString())) - .toList() + .map((e) => BleDescriptor(e.uuid.toString())) + .toList() : [], ); }).toList(); @@ -237,13 +235,13 @@ class UniversalBleLinux extends UniversalBlePlatform { ) { final device = _findDeviceById(deviceId); final s = device.gattServices.cast().firstWhere( - (s) => s?.uuid.toString() == service, - orElse: () => null, - ); + (s) => s?.uuid.toString() == service, + orElse: () => null, + ); final c = s?.characteristics.cast().firstWhere( - (c) => c?.uuid.toString() == characteristic, - orElse: () => null, - ); + (c) => c?.uuid.toString() == characteristic, + orElse: () => null, + ); if (c == null) { throw UniversalBleException( @@ -281,30 +279,29 @@ class UniversalBleLinux extends UniversalBlePlatform { _characteristicPropertiesSubscriptions[characteristicKey]?.cancel(); } - _characteristicPropertiesSubscriptions[characteristicKey] = char - .propertiesChanged - .listen((List properties) { - for (String property in properties) { - switch (property) { - case BluezProperty.value: - UniversalLogger.logVerbose( - "NOTIFY <- $deviceId $service $characteristic len=${char.value.length} data=${char.value}", - withTimestamp: true, - ); - updateCharacteristicValue( - deviceId, - characteristic, - Uint8List.fromList(char.value), - DateTime.now().millisecondsSinceEpoch, - ); - break; - default: - UniversalLogger.logInfo( - "UnhandledCharValuePropertyChange: $property", - ); - } - } - }); + _characteristicPropertiesSubscriptions[characteristicKey] = + char.propertiesChanged.listen((List properties) { + for (String property in properties) { + switch (property) { + case BluezProperty.value: + UniversalLogger.logVerbose( + "NOTIFY <- $deviceId $service $characteristic len=${char.value.length} data=${char.value}", + withTimestamp: true, + ); + updateCharacteristicValue( + deviceId, + characteristic, + Uint8List.fromList(char.value), + DateTime.now().millisecondsSinceEpoch, + ); + break; + default: + UniversalLogger.logInfo( + "UnhandledCharValuePropertyChange: $property", + ); + } + } + }); } else { if (char.notifying) await char.stopNotify(); _characteristicPropertiesSubscriptions @@ -446,9 +443,8 @@ class UniversalBleLinux extends UniversalBlePlatform { @override Future> getSystemDevices(List? withServices) async { await _ensureInitialized(); - List devices = _client.devices - .where((device) => device.connected) - .toList(); + List devices = + _client.devices.where((device) => device.connected).toList(); if (withServices != null && withServices.isNotEmpty) { devices = devices.where((device) { if (device.servicesResolved) { @@ -491,9 +487,9 @@ class UniversalBleLinux extends UniversalBlePlatform { BlueZDevice? _getDeviceById(String deviceId) { return _devices[deviceId] ?? _client.devices.cast().firstWhere( - (device) => device?.address == deviceId, - orElse: () => null, - ); + (device) => device?.address == deviceId, + orElse: () => null, + ); } Future _ensureInitialized() async { @@ -577,23 +573,21 @@ class UniversalBleLinux extends UniversalBlePlatform { _devices[device.address] = device; // Setup advertisements Listener - _deviceAdvertisementSubscriptions[device.address] ??= device - .propertiesChanged - .where((e) { - return e.contains(BluezProperty.rssi) || - e.contains(BluezProperty.manufacturerData) || - e.contains(BluezProperty.uuids) || - e.contains(BluezProperty.serviceData); - }) - .listen((_) { - if (_bleFilter.shouldAcceptDevice(bleDevice)) { - updateScanResult(device.toBleDevice()); - } - }); + _deviceAdvertisementSubscriptions[device.address] ??= + device.propertiesChanged.where((e) { + return e.contains(BluezProperty.rssi) || + e.contains(BluezProperty.manufacturerData) || + e.contains(BluezProperty.uuids) || + e.contains(BluezProperty.serviceData); + }).listen((_) { + if (_bleFilter.shouldAcceptDevice(bleDevice)) { + updateScanResult(device.toBleDevice()); + } + }); // Setup update listener - _deviceUpdateStreamSubscriptions[device - .address] ??= device.propertiesChanged.listen((properties) { + _deviceUpdateStreamSubscriptions[device.address] ??= + device.propertiesChanged.listen((properties) { for (final property in properties) { switch (property) { // Connection/Pair updates diff --git a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart index 7a79b91b..49e3c054 100644 --- a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart +++ b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart @@ -10,9 +10,9 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; Object? _extractReplyValueOrThrow( - List? replyList, - String channelName, { - required bool isNullValid, + List? replyList, + String channelName, { + required bool isNullValid, }) { if (replyList == null) { throw PlatformException( @@ -34,8 +34,8 @@ Object? _extractReplyValueOrThrow( return replyList.firstOrNull; } - -List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -44,6 +44,7 @@ List wrapResponse({Object? result, PlatformException? error, bool empty } return [error.code, error.message, error.details]; } + bool _deepEquals(Object? a, Object? b) { if (identical(a, b)) { return true; @@ -106,7 +107,6 @@ int _deepHash(Object? value) { return value.hashCode; } - enum PeripheralBondState { bonding, bonded, @@ -135,14 +135,16 @@ class PeripheralService { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralService decode(Object result) { result as List; return PeripheralService( uuid: result[0]! as String, primary: result[1]! as bool, - characteristics: (result[2]! as List).cast(), + characteristics: + (result[2]! as List).cast(), ); } @@ -155,7 +157,9 @@ class PeripheralService { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(primary, other.primary) && _deepEquals(characteristics, other.characteristics); + return _deepEquals(uuid, other.uuid) && + _deepEquals(primary, other.primary) && + _deepEquals(characteristics, other.characteristics); } @override @@ -193,7 +197,8 @@ class PeripheralCharacteristic { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralCharacteristic decode(Object result) { result as List; @@ -209,13 +214,18 @@ class PeripheralCharacteristic { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralCharacteristic || other.runtimeType != runtimeType) { + if (other is! PeripheralCharacteristic || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(permissions, other.permissions) && _deepEquals(descriptors, other.descriptors) && _deepEquals(value, other.value); + return _deepEquals(uuid, other.uuid) && + _deepEquals(properties, other.properties) && + _deepEquals(permissions, other.permissions) && + _deepEquals(descriptors, other.descriptors) && + _deepEquals(value, other.value); } @override @@ -245,7 +255,8 @@ class PeripheralDescriptor { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralDescriptor decode(Object result) { result as List; @@ -265,7 +276,9 @@ class PeripheralDescriptor { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(value, other.value) && _deepEquals(permissions, other.permissions); + return _deepEquals(uuid, other.uuid) && + _deepEquals(value, other.value) && + _deepEquals(permissions, other.permissions); } @override @@ -295,7 +308,8 @@ class PeripheralReadRequestResult { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralReadRequestResult decode(Object result) { result as List; @@ -309,13 +323,16 @@ class PeripheralReadRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralReadRequestResult || other.runtimeType != runtimeType) { + if (other is! PeripheralReadRequestResult || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); + return _deepEquals(value, other.value) && + _deepEquals(offset, other.offset) && + _deepEquals(status, other.status); } @override @@ -345,7 +362,8 @@ class PeripheralWriteRequestResult { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralWriteRequestResult decode(Object result) { result as List; @@ -359,13 +377,16 @@ class PeripheralWriteRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralWriteRequestResult || other.runtimeType != runtimeType) { + if (other is! PeripheralWriteRequestResult || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); + return _deepEquals(value, other.value) && + _deepEquals(offset, other.offset) && + _deepEquals(status, other.status); } @override @@ -391,7 +412,8 @@ class PeripheralManufacturerData { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralManufacturerData decode(Object result) { result as List; @@ -404,13 +426,15 @@ class PeripheralManufacturerData { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralManufacturerData || other.runtimeType != runtimeType) { + if (other is! PeripheralManufacturerData || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(manufacturerId, other.manufacturerId) && _deepEquals(data, other.data); + return _deepEquals(manufacturerId, other.manufacturerId) && + _deepEquals(data, other.data); } @override @@ -418,7 +442,6 @@ class PeripheralManufacturerData { int get hashCode => _deepHash([runtimeType, ..._toList()]); } - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -426,25 +449,25 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is PeripheralBondState) { + } else if (value is PeripheralBondState) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is PeripheralService) { + } else if (value is PeripheralService) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else if (value is PeripheralCharacteristic) { + } else if (value is PeripheralCharacteristic) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is PeripheralDescriptor) { + } else if (value is PeripheralDescriptor) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is PeripheralReadRequestResult) { + } else if (value is PeripheralReadRequestResult) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is PeripheralWriteRequestResult) { + } else if (value is PeripheralWriteRequestResult) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is PeripheralManufacturerData) { + } else if (value is PeripheralManufacturerData) { buffer.putUint8(135); writeValue(buffer, value.encode()); } else { @@ -480,9 +503,11 @@ class UniversalBlePeripheralChannel { /// Constructor for [UniversalBlePeripheralChannel]. 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. - UniversalBlePeripheralChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + UniversalBlePeripheralChannel( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -490,7 +515,8 @@ class UniversalBlePeripheralChannel { final String pigeonVar_messageChannelSuffix; Future initialize() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -500,15 +526,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future isAdvertising() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -518,16 +544,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); return pigeonVar_replyValue as bool?; } Future isSupported() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -537,16 +563,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future stopAdvertising() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -556,51 +582,53 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future addService(PeripheralService service) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([service]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([service]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future removeService(String serviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([serviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([serviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future clearServices() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -610,15 +638,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future> getServices() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -628,68 +656,82 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return (pigeonVar_replyValue! as List).cast(); } - Future startAdvertising(List services, String? localName, int? timeout, PeripheralManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; + Future startAdvertising( + List services, + String? localName, + int? timeout, + PeripheralManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([services, localName, timeout, manufacturerData, addManufacturerDataInScanResponse]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([ + services, + localName, + timeout, + manufacturerData, + addManufacturerDataInScanResponse + ]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; + Future updateCharacteristic( + String characteristicId, Uint8List value, String? deviceId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId, value, deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([characteristicId, value, deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns peripheral-central device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. Future> getSubscribedCentrals(String characteristicId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([characteristicId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return (pigeonVar_replyValue! as List).cast(); } } @@ -697,11 +739,14 @@ class UniversalBlePeripheralChannel { abstract class UniversalBlePeripheralCallback { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - PeripheralReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralReadRequestResult? onReadRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); - PeripheralWriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralWriteRequestResult? onWriteRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); - void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); + void onCharacteristicSubscriptionChange(String deviceId, + String characteristicId, bool isSubscribed, String? name); void onAdvertisingStatusUpdate(bool advertising, String? error); @@ -715,11 +760,17 @@ abstract class UniversalBlePeripheralCallback { void onBondStateChange(String deviceId, PeripheralBondState bondState); - static void setUp(UniversalBlePeripheralCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp( + UniversalBlePeripheralCallback? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -731,19 +782,22 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralReadRequestResult? output = api.onReadRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralReadRequestResult? output = api.onReadRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -755,19 +809,22 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralWriteRequestResult? output = api.onWriteRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralWriteRequestResult? output = api.onWriteRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -779,19 +836,22 @@ abstract class UniversalBlePeripheralCallback { final bool arg_isSubscribed = args[2]! as bool; final String? arg_name = args[3] as String?; try { - api.onCharacteristicSubscriptionChange(arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); + api.onCharacteristicSubscriptionChange( + arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -805,15 +865,17 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -826,15 +888,17 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -848,15 +912,17 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -870,15 +936,17 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -892,15 +960,17 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -908,14 +978,16 @@ abstract class UniversalBlePeripheralCallback { pigeonVar_channel.setMessageHandler((Object? message) async { final List args = message! as List; final String arg_deviceId = args[0]! as String; - final PeripheralBondState arg_bondState = args[1]! as PeripheralBondState; + final PeripheralBondState arg_bondState = + args[1]! as PeripheralBondState; try { api.onBondStateChange(arg_deviceId, arg_bondState); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index 9e023e03..5cb37c3e 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -169,10 +169,10 @@ class UniversalBleScanResult { name: result[1] as String?, isPaired: result[2] as bool?, rssi: result[3] as int?, - manufacturerDataList: (result[4] as List?) - ?.cast(), - serviceData: (result[5] as Map?) - ?.cast(), + manufacturerDataList: + (result[4] as List?)?.cast(), + serviceData: + (result[5] as Map?)?.cast(), services: (result[6] as List?)?.cast(), timestamp: result[7] as int?, ); @@ -214,8 +214,8 @@ class UniversalBleService { result as List; return UniversalBleService( uuid: result[0]! as String, - characteristics: (result[1] as List?) - ?.cast(), + characteristics: + (result[1] as List?)?.cast(), ); } @@ -262,8 +262,8 @@ class UniversalBleCharacteristic { return UniversalBleCharacteristic( uuid: result[0]! as String, properties: (result[1] as List?)!.cast(), - descriptors: (result[2] as List?)! - .cast(), + descriptors: + (result[2] as List?)!.cast(), ); } @@ -641,10 +641,9 @@ class UniversalBlePlatformChannel { UniversalBlePlatformChannel({ BinaryMessenger? binaryMessenger, String messageChannelSuffix = '', - }) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty - ? '.$messageChannelSuffix' - : ''; + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -1330,9 +1329,8 @@ abstract class UniversalBleCallbackChannel { BinaryMessenger? binaryMessenger, String messageChannelSuffix = '', }) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty - ? '.$messageChannelSuffix' - : ''; + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', diff --git a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart index eb464191..df1b0798 100644 --- a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart +++ b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart @@ -75,9 +75,10 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { String deviceId, { Duration? connectionTimeout, bool autoConnect = false, - }) => _executeWithErrorHandling( - () => _channel.connect(deviceId, autoConnect: autoConnect), - ); + }) => + _executeWithErrorHandling( + () => _channel.connect(deviceId, autoConnect: autoConnect), + ); @override Future disconnect(String deviceId) => @@ -90,8 +91,8 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { ) async { List universalBleServices = await _executeWithErrorHandling( - () => _channel.discoverServices(deviceId, withDescriptors), - ); + () => _channel.discoverServices(deviceId, withDescriptors), + ); return List.from( universalBleServices .where((e) => e != null) @@ -206,8 +207,8 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { @override Future setLogLevel(BleLogLevel logLevel) => _executeWithErrorHandling( - () => _channel.setLogLevel(logLevel.toUniversalBleLogLevel()), - ); + () => _channel.setLogLevel(logLevel.toUniversalBleLogLevel()), + ); /// To set listeners void _setupListeners() { @@ -310,7 +311,8 @@ class _UniversalBleCallbackHandler extends UniversalBleCallbackChannel { String characteristicId, Uint8List value, int? timestamp, - ) => valueChanged(deviceId, characteristicId, value, timestamp); + ) => + valueChanged(deviceId, characteristicId, value, timestamp); @override void onPairStateChange(String deviceId, bool isPaired, String? error) => @@ -327,8 +329,7 @@ extension _UniversalBleScanResultExtension on UniversalBleScanResult { isSystemDevice: isSystemDevice, services: services?.map(BleUuidParser.string).toList() ?? [], timestamp: timestamp, - manufacturerDataList: - manufacturerDataList + manufacturerDataList: manufacturerDataList ?.map((e) => ManufacturerData(e.companyIdentifier, e.data)) .toList() ?? [], @@ -361,13 +362,13 @@ extension _ScanFilterExtension on ScanFilter? { extension _BleLogLevelExtension on BleLogLevel { UniversalBleLogLevel toUniversalBleLogLevel() => switch (this) { - BleLogLevel.none => UniversalBleLogLevel.none, - BleLogLevel.error => UniversalBleLogLevel.error, - BleLogLevel.warning => UniversalBleLogLevel.warning, - BleLogLevel.info => UniversalBleLogLevel.info, - BleLogLevel.debug => UniversalBleLogLevel.debug, - BleLogLevel.verbose => UniversalBleLogLevel.verbose, - }; + BleLogLevel.none => UniversalBleLogLevel.none, + BleLogLevel.error => UniversalBleLogLevel.error, + BleLogLevel.warning => UniversalBleLogLevel.warning, + BleLogLevel.info => UniversalBleLogLevel.info, + BleLogLevel.debug => UniversalBleLogLevel.debug, + BleLogLevel.verbose => UniversalBleLogLevel.verbose, + }; } extension _PlatformConfigExtension on PlatformConfig? { diff --git a/lib/src/universal_ble_platform_interface.dart b/lib/src/universal_ble_platform_interface.dart index d2c75b92..23907440 100644 --- a/lib/src/universal_ble_platform_interface.dart +++ b/lib/src/universal_ble_platform_interface.dart @@ -16,15 +16,11 @@ abstract class UniversalBlePlatform { final _scanStreamController = UniversalBleStreamController(); - final bleConnectionUpdateStreamController = - UniversalBleStreamController< - ({String deviceId, bool isConnected, String? error}) - >(); + final bleConnectionUpdateStreamController = UniversalBleStreamController< + ({String deviceId, bool isConnected, String? error})>(); - final _valueStreamController = - UniversalBleStreamController< - ({String deviceId, String characteristicId, Uint8List value}) - >(); + final _valueStreamController = UniversalBleStreamController< + ({String deviceId, String characteristicId, Uint8List value})>(); final _pairStateStreamController = UniversalBleStreamController<({String deviceId, bool isPaired})>(); @@ -32,8 +28,8 @@ abstract class UniversalBlePlatform { /// Send latest availability state upon subscribing late final _availabilityStreamController = UniversalBleStreamController( - initialEvent: getBluetoothAvailabilityState, - ); + initialEvent: getBluetoothAvailabilityState, + ); Future getBluetoothAvailabilityState(); @@ -133,18 +129,15 @@ abstract class UniversalBlePlatform { String characteristicId, ) { characteristicId = BleUuidParser.string(characteristicId); - return _valueStreamController.stream - .where((e) { - return e.deviceId == deviceId && - e.characteristicId == characteristicId; - }) - .map((e) => e.value); + return _valueStreamController.stream.where((e) { + return e.deviceId == deviceId && e.characteristicId == characteristicId; + }).map((e) => e.value); } - Stream pairingStateStream(String deviceId) => _pairStateStreamController - .stream - .where((e) => e.deviceId == deviceId) - .map((e) => e.isPaired); + Stream pairingStateStream(String deviceId) => + _pairStateStreamController.stream + .where((e) => e.deviceId == deviceId) + .map((e) => e.isPaired); /// Update Handlers void updateScanResult(BleDevice bleDevice) { @@ -209,16 +202,15 @@ abstract class UniversalBlePlatform { } // Callback types -typedef OnConnectionChange = - void Function(String deviceId, bool isConnected, String? error); - -typedef OnValueChange = - void Function( - String deviceId, - String characteristicId, - Uint8List value, - int? timestamp, - ); +typedef OnConnectionChange = void Function( + String deviceId, bool isConnected, String? error); + +typedef OnValueChange = void Function( + String deviceId, + String characteristicId, + Uint8List value, + int? timestamp, +); typedef OnScanResult = void Function(BleDevice scanResult); From 034a6719dca093a2313cd41c45e88f9dd6f82976 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 21:22:43 +0100 Subject: [PATCH 09/23] feat(peripheral): forward BleDescriptor value to native GATT BleDescriptor gains optional initial value (e.g. HID Report Reference 0x2908). UniversalBlePeripheralMapper passes it through to PeripheralDescriptor so Android/Darwin can expose static descriptor bytes for HID clients. Made-with: Cursor --- lib/src/models/ble_service.dart | 13 +++++++--- .../universal_ble_peripheral_mapper.dart | 2 +- test/universal_ble_peripheral_test.dart | 26 +++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/src/models/ble_service.dart b/lib/src/models/ble_service.dart index 4ab2f133..c4c41083 100644 --- a/lib/src/models/ble_service.dart +++ b/lib/src/models/ble_service.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:universal_ble/universal_ble.dart'; class BleService { @@ -55,19 +57,22 @@ class BleCharacteristic { class BleDescriptor { String uuid; - BleDescriptor(String uuid) : uuid = BleUuidParser.string(uuid); + /// Initial attribute value for this descriptor (e.g. HID Report Reference 0x2908). + Uint8List? value; + + BleDescriptor(String uuid, {this.value}) : uuid = BleUuidParser.string(uuid); @override - String toString() => 'BleDescriptor{uuid: $uuid}'; + String toString() => 'BleDescriptor{uuid: $uuid, value: $value}'; @override bool operator ==(Object other) { if (other is! BleDescriptor) return false; - return other.uuid == uuid; + return other.uuid == uuid && other.value == value; } @override - int get hashCode => uuid.hashCode; + int get hashCode => Object.hash(uuid, value); } enum CharacteristicProperty { diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart index 562b0b62..fc7cc954 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart @@ -21,7 +21,7 @@ class UniversalBlePeripheralMapper { .map( (d) => pigeon.PeripheralDescriptor( uuid: BleUuidParser.string(d.uuid), - value: null, + value: d.value, permissions: const [], ), ) diff --git a/test/universal_ble_peripheral_test.dart b/test/universal_ble_peripheral_test.dart index 14b144fd..6569218f 100644 --- a/test/universal_ble_peripheral_test.dart +++ b/test/universal_ble_peripheral_test.dart @@ -73,6 +73,32 @@ void main() { descriptors!.single.uuid, BleUuidParser.string('2902'), ); + expect(descriptors.single.value, isNull); + }); + + test('mapper forwards descriptor initial value to pigeon', () { + final service = BleService('1812', [ + BleCharacteristic( + '2a4d', + [CharacteristicProperty.notify], + [ + BleDescriptor( + '2908', + value: Uint8List.fromList([0x00, 0x01]), + ), + ], + ), + ]); + + final mapped = UniversalBlePeripheralMapper.toPigeonService( + service, + primary: true, + ); + + expect( + mapped.characteristics.single.descriptors!.single.value, + Uint8List.fromList([0x00, 0x01]), + ); }); test('mapper converts manufacturer data to pigeon type', () { From de30588b42698080c3d84c4e9ad4f709366beeef Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Fri, 27 Mar 2026 21:43:58 +0100 Subject: [PATCH 10/23] fix(darwin): avoid duplicate PigeonError in universal_ble pod Set SwiftOptions(includeErrorClass: false) for universal_ble_peripheral pigeon so UniversalBlePeripheral.g.swift shares PigeonError from UniversalBle.g.swift within the same module. Made-with: Cursor --- .../UniversalBlePeripheral.g.swift | 18 - .../generated/universal_ble_peripheral.g.dart | 356 +++++++----------- pigeon/universal_ble_peripheral.dart | 2 + 3 files changed, 144 insertions(+), 232 deletions(-) diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift index 39562a53..0906742b 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift @@ -11,24 +11,6 @@ import Foundation #error("Unsupported platform.") #endif -/// Error class for passing custom error details to Dart side. -final class PigeonError: Error { - let code: String - let message: String? - let details: Sendable? - - init(code: String, message: String?, details: Sendable?) { - self.code = code - self.message = message - self.details = details - } - - var localizedDescription: String { - return - "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" - } -} - private func wrapResult(_ result: Any?) -> [Any?] { return [result] } diff --git a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart index 49e3c054..7a79b91b 100644 --- a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart +++ b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart @@ -10,9 +10,9 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; Object? _extractReplyValueOrThrow( - List? replyList, - String channelName, { - required bool isNullValid, + List? replyList, + String channelName, { + required bool isNullValid, }) { if (replyList == null) { throw PlatformException( @@ -34,8 +34,8 @@ Object? _extractReplyValueOrThrow( return replyList.firstOrNull; } -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { + +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -44,7 +44,6 @@ List wrapResponse( } return [error.code, error.message, error.details]; } - bool _deepEquals(Object? a, Object? b) { if (identical(a, b)) { return true; @@ -107,6 +106,7 @@ int _deepHash(Object? value) { return value.hashCode; } + enum PeripheralBondState { bonding, bonded, @@ -135,16 +135,14 @@ class PeripheralService { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralService decode(Object result) { result as List; return PeripheralService( uuid: result[0]! as String, primary: result[1]! as bool, - characteristics: - (result[2]! as List).cast(), + characteristics: (result[2]! as List).cast(), ); } @@ -157,9 +155,7 @@ class PeripheralService { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(primary, other.primary) && - _deepEquals(characteristics, other.characteristics); + return _deepEquals(uuid, other.uuid) && _deepEquals(primary, other.primary) && _deepEquals(characteristics, other.characteristics); } @override @@ -197,8 +193,7 @@ class PeripheralCharacteristic { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralCharacteristic decode(Object result) { result as List; @@ -214,18 +209,13 @@ class PeripheralCharacteristic { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralCharacteristic || - other.runtimeType != runtimeType) { + if (other is! PeripheralCharacteristic || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(properties, other.properties) && - _deepEquals(permissions, other.permissions) && - _deepEquals(descriptors, other.descriptors) && - _deepEquals(value, other.value); + return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(permissions, other.permissions) && _deepEquals(descriptors, other.descriptors) && _deepEquals(value, other.value); } @override @@ -255,8 +245,7 @@ class PeripheralDescriptor { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralDescriptor decode(Object result) { result as List; @@ -276,9 +265,7 @@ class PeripheralDescriptor { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(value, other.value) && - _deepEquals(permissions, other.permissions); + return _deepEquals(uuid, other.uuid) && _deepEquals(value, other.value) && _deepEquals(permissions, other.permissions); } @override @@ -308,8 +295,7 @@ class PeripheralReadRequestResult { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralReadRequestResult decode(Object result) { result as List; @@ -323,16 +309,13 @@ class PeripheralReadRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralReadRequestResult || - other.runtimeType != runtimeType) { + if (other is! PeripheralReadRequestResult || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && - _deepEquals(offset, other.offset) && - _deepEquals(status, other.status); + return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); } @override @@ -362,8 +345,7 @@ class PeripheralWriteRequestResult { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralWriteRequestResult decode(Object result) { result as List; @@ -377,16 +359,13 @@ class PeripheralWriteRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralWriteRequestResult || - other.runtimeType != runtimeType) { + if (other is! PeripheralWriteRequestResult || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && - _deepEquals(offset, other.offset) && - _deepEquals(status, other.status); + return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); } @override @@ -412,8 +391,7 @@ class PeripheralManufacturerData { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralManufacturerData decode(Object result) { result as List; @@ -426,15 +404,13 @@ class PeripheralManufacturerData { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralManufacturerData || - other.runtimeType != runtimeType) { + if (other is! PeripheralManufacturerData || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(manufacturerId, other.manufacturerId) && - _deepEquals(data, other.data); + return _deepEquals(manufacturerId, other.manufacturerId) && _deepEquals(data, other.data); } @override @@ -442,6 +418,7 @@ class PeripheralManufacturerData { int get hashCode => _deepHash([runtimeType, ..._toList()]); } + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -449,25 +426,25 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is PeripheralBondState) { + } else if (value is PeripheralBondState) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is PeripheralService) { + } else if (value is PeripheralService) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else if (value is PeripheralCharacteristic) { + } else if (value is PeripheralCharacteristic) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is PeripheralDescriptor) { + } else if (value is PeripheralDescriptor) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is PeripheralReadRequestResult) { + } else if (value is PeripheralReadRequestResult) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is PeripheralWriteRequestResult) { + } else if (value is PeripheralWriteRequestResult) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is PeripheralManufacturerData) { + } else if (value is PeripheralManufacturerData) { buffer.putUint8(135); writeValue(buffer, value.encode()); } else { @@ -503,11 +480,9 @@ class UniversalBlePeripheralChannel { /// Constructor for [UniversalBlePeripheralChannel]. 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. - UniversalBlePeripheralChannel( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + UniversalBlePeripheralChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -515,8 +490,7 @@ class UniversalBlePeripheralChannel { final String pigeonVar_messageChannelSuffix; Future initialize() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -526,15 +500,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future isAdvertising() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -544,16 +518,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; return pigeonVar_replyValue as bool?; } Future isSupported() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -563,16 +537,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future stopAdvertising() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -582,53 +556,51 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future addService(PeripheralService service) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([service]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([service]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future removeService(String serviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([serviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([serviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future clearServices() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -638,15 +610,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future> getServices() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -656,82 +628,68 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return (pigeonVar_replyValue! as List).cast(); } - Future startAdvertising( - List services, - String? localName, - int? timeout, - PeripheralManufacturerData? manufacturerData, - bool addManufacturerDataInScanResponse) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; + Future startAdvertising(List services, String? localName, int? timeout, PeripheralManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([ - services, - localName, - timeout, - manufacturerData, - addManufacturerDataInScanResponse - ]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([services, localName, timeout, manufacturerData, addManufacturerDataInScanResponse]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } - Future updateCharacteristic( - String characteristicId, Uint8List value, String? deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; + Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([characteristicId, value, deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId, value, deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } /// Returns peripheral-central device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. Future> getSubscribedCentrals(String characteristicId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([characteristicId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return (pigeonVar_replyValue! as List).cast(); } } @@ -739,14 +697,11 @@ class UniversalBlePeripheralChannel { abstract class UniversalBlePeripheralCallback { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - PeripheralReadRequestResult? onReadRequest( - String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - PeripheralWriteRequestResult? onWriteRequest( - String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralWriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - void onCharacteristicSubscriptionChange(String deviceId, - String characteristicId, bool isSubscribed, String? name); + void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); void onAdvertisingStatusUpdate(bool advertising, String? error); @@ -760,17 +715,11 @@ abstract class UniversalBlePeripheralCallback { void onBondStateChange(String deviceId, PeripheralBondState bondState); - static void setUp( - UniversalBlePeripheralCallback? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(UniversalBlePeripheralCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -782,22 +731,19 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralReadRequestResult? output = api.onReadRequest( - arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralReadRequestResult? output = api.onReadRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -809,22 +755,19 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralWriteRequestResult? output = api.onWriteRequest( - arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralWriteRequestResult? output = api.onWriteRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -836,22 +779,19 @@ abstract class UniversalBlePeripheralCallback { final bool arg_isSubscribed = args[2]! as bool; final String? arg_name = args[3] as String?; try { - api.onCharacteristicSubscriptionChange( - arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); + api.onCharacteristicSubscriptionChange(arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -865,17 +805,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -888,17 +826,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -912,17 +848,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -936,17 +870,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -960,17 +892,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -978,16 +908,14 @@ abstract class UniversalBlePeripheralCallback { pigeonVar_channel.setMessageHandler((Object? message) async { final List args = message! as List; final String arg_deviceId = args[0]! as String; - final PeripheralBondState arg_bondState = - args[1]! as PeripheralBondState; + final PeripheralBondState arg_bondState = args[1]! as PeripheralBondState; try { api.onBondStateChange(arg_deviceId, arg_bondState); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/pigeon/universal_ble_peripheral.dart b/pigeon/universal_ble_peripheral.dart index 501823dc..cf2879a5 100644 --- a/pigeon/universal_ble_peripheral.dart +++ b/pigeon/universal_ble_peripheral.dart @@ -10,6 +10,8 @@ import 'package:pigeon/pigeon.dart'; 'android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt', swiftOut: 'darwin/Classes/UniversalBlePeripheral.g.swift', kotlinOptions: KotlinOptions(package: 'com.navideck.universal_ble'), + // Same CocoaPod target as UniversalBle.g.swift; omit duplicate PigeonError. + swiftOptions: SwiftOptions(includeErrorClass: false), cppOptions: CppOptions(namespace: 'universal_ble'), cppHeaderOut: 'windows/src/generated/universal_ble_peripheral.g.h', cppSourceOut: 'windows/src/generated/universal_ble_peripheral.g.cpp', From 6d7090843471b1f565eccd33aa6990fdf95e7bcf Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 11:53:39 +0200 Subject: [PATCH 11/23] Remove redundant APIs --- README.md | 22 ++++---- .../universal_ble/UniversalBlePeripheral.g.kt | 34 ------------ .../UniversalBlePeripheralExtensions.kt | 8 --- .../UniversalBlePeripheralPlugin.kt | 22 +------- .../UniversalBlePeripheral.g.swift | 38 -------------- .../UniversalBlePeripheralPlugin.swift | 4 -- .../generated/universal_ble_peripheral.g.dart | 47 ----------------- .../universal_ble_peripheral.dart | 8 --- .../universal_ble_peripheral_mapper.dart | 8 --- .../universal_ble_peripheral_pigeon.dart | 14 ----- ...sal_ble_peripheral_platform_interface.dart | 9 ---- pigeon/universal_ble_peripheral.dart | 2 - .../generated/universal_ble_peripheral.g.cpp | 52 ------------------- .../generated/universal_ble_peripheral.g.h | 9 ---- 14 files changed, 12 insertions(+), 265 deletions(-) diff --git a/README.md b/README.md index 6667dc30..50de1d23 100644 --- a/README.md +++ b/README.md @@ -65,17 +65,17 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | API | Android | iOS | macOS | Windows | Linux | Web | | :--------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | -| initialize | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| isSupported | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| isAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| addService | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| removeService | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| clearServices | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| getServices | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| startAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| stopAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| updateCharacteristic | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | -| peripheral callbacks\* | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ | +| initialize | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| isSupported | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| isAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| addService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| removeService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| clearServices | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getServices | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| startAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| stopAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| updateCharacteristic | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| peripheral callbacks\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | \* callbacks include advertising state, read/write requests, subscription changes, and related peripheral events. diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt index a5be7b9a..8d098c1b 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt @@ -834,23 +834,6 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge } } } - fun onBleStateChange(stateArg: Boolean, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(stateArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } fun onServiceAdded(serviceIdArg: String, errorArg: String?, callback: (Result) -> Unit) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" @@ -902,21 +885,4 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge } } } - fun onBondStateChange(deviceIdArg: String, bondStateArg: PeripheralBondState, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, bondStateArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } } diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt index 293ac7d0..86e96ba3 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralExtensions.kt @@ -1,7 +1,6 @@ package com.navideck.universal_ble import android.app.Activity -import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattDescriptor import android.bluetooth.BluetoothGattService @@ -157,10 +156,3 @@ private fun Int.toPermissionBits(): Int = when (this) { 3 -> BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED else -> 0 } - -fun Int.toPeripheralBondState(): PeripheralBondState = when (this) { - BluetoothDevice.BOND_BONDING -> PeripheralBondState.BONDING - BluetoothDevice.BOND_BONDED -> PeripheralBondState.BONDED - BluetoothDevice.BOND_NONE -> PeripheralBondState.NONE - else -> PeripheralBondState.NONE -} diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index d2b5ea68..54ca4484 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -80,8 +80,7 @@ class UniversalBlePeripheralPlugin( ?: throw UnsupportedOperationException("gattServer is null, check Bluetooth is ON.") if (!receiverRegistered) { - val intentFilter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) - intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED) + val intentFilter = IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { applicationContext.registerReceiver( broadcastReceiver, @@ -94,8 +93,6 @@ class UniversalBlePeripheralPlugin( } receiverRegistered = true } - - callback.onBleStateChange(isBluetoothEnabled()) {} } override fun isAdvertising(): Boolean? = advertising @@ -449,16 +446,6 @@ class UniversalBlePeripheralPlugin( private val broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { - BluetoothAdapter.ACTION_STATE_CHANGED -> { - val state = intent.getIntExtra( - BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR, - ) - if (state == BluetoothAdapter.STATE_OFF) { - handler.post { callback.onBleStateChange(false) {} } - } else if (state == BluetoothAdapter.STATE_ON) { - handler.post { callback.onBleStateChange(true) {} } - } - } BluetoothDevice.ACTION_BOND_STATE_CHANGED -> { val state = intent.getIntExtra( BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR, @@ -469,13 +456,6 @@ class UniversalBlePeripheralPlugin( @Suppress("DEPRECATION") intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) } - handler.post { - callback.onBondStateChange( - device?.address ?: "", - state.toPeripheralBondState(), - ) {} - } - val waitingForConnection = synchronized(listOfDevicesWaitingForBond) { listOfDevicesWaitingForBond.contains(device?.address) } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift index 0906742b..ace8449f 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift @@ -679,11 +679,9 @@ protocol UniversalBlePeripheralCallbackProtocol { func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) - func onBleStateChange(state stateArg: Bool, completion: @escaping (Result) -> Void) func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) - func onBondStateChange(deviceId deviceIdArg: String, bondState bondStateArg: PeripheralBondState, completion: @escaping (Result) -> Void) } class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { private let binaryMessenger: FlutterBinaryMessenger @@ -769,24 +767,6 @@ class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { } } } - func onBleStateChange(state stateArg: Bool, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([stateArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - completion(.success(())) - } - } - } func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) { let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded\(messageChannelSuffix)" let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) @@ -841,22 +821,4 @@ class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { } } } - func onBondStateChange(deviceId deviceIdArg: String, bondState bondStateArg: PeripheralBondState, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, bondStateArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - completion(.success(())) - } - } - } } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 1c069b97..67e8d2bd 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -142,10 +142,6 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne ) { _ in } } - nonisolated func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { - callbackChannel.onBleStateChange(state: peripheral.state == .poweredOn) { _ in } - } - nonisolated func peripheralManager( _: CBPeripheralManager, didAdd service: CBService, diff --git a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart index 7a79b91b..cd77bb28 100644 --- a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart +++ b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart @@ -705,16 +705,12 @@ abstract class UniversalBlePeripheralCallback { void onAdvertisingStatusUpdate(bool advertising, String? error); - void onBleStateChange(bool state); - void onServiceAdded(String serviceId, String? error); void onMtuChange(String deviceId, int mtu); void onConnectionStateChange(String deviceId, bool connected); - void onBondStateChange(String deviceId, PeripheralBondState bondState); - static void setUp(UniversalBlePeripheralCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { @@ -811,27 +807,6 @@ abstract class UniversalBlePeripheralCallback { }); } } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final bool arg_state = args[0]! as bool; - try { - api.onBleStateChange(arg_state); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } { final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', pigeonChannelCodec, @@ -898,27 +873,5 @@ abstract class UniversalBlePeripheralCallback { }); } } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final String arg_deviceId = args[0]! as String; - final PeripheralBondState arg_bondState = args[1]! as PeripheralBondState; - try { - api.onBondStateChange(arg_deviceId, arg_bondState); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } } } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart index 14869b5b..1b8f72db 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -72,14 +72,6 @@ class UniversalBlePeripheral { _platform.advertisingStatusUpdateCallback = callback; } - static set onBleStateChange(OnPeripheralBleStateChange? callback) { - _platform.bleStateChangeCallback = callback; - } - - static set onBondStateChange(OnPeripheralBondStateChange? callback) { - _platform.bondStateChangeCallback = callback; - } - static set onSubscriptionChange( OnPeripheralCharacteristicSubscriptionChange? callback, ) { diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart index fc7cc954..9b9e6891 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart @@ -42,12 +42,4 @@ class UniversalBlePeripheralMapper { data: manufacturerData.payload, ); } - - static PeripheralBondState fromPigeonBondState(pigeon.PeripheralBondState s) { - return switch (s) { - pigeon.PeripheralBondState.bonding => PeripheralBondState.bonding, - pigeon.PeripheralBondState.bonded => PeripheralBondState.bonded, - pigeon.PeripheralBondState.none => PeripheralBondState.none, - }; - } } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index 125fef7e..afa5bd0b 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -117,20 +117,6 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform super.advertisingStatusUpdateCallback?.call(advertising, error); } - @override - void onBleStateChange(bool state) { - super.bleStateChangeCallback?.call(state); - } - - @override - void onBondStateChange( - String deviceId, pigeon.PeripheralBondState bondState) { - super.bondStateChangeCallback?.call( - deviceId, - UniversalBlePeripheralMapper.fromPigeonBondState(bondState), - ); - } - @override void onCharacteristicSubscriptionChange( String deviceId, diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart index fc6068d6..fd8634ba 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -4,11 +4,6 @@ import 'package:universal_ble/universal_ble.dart'; typedef OnPeripheralAdvertisingStatusUpdate = void Function( bool advertising, String? error); -typedef OnPeripheralBleStateChange = void Function(bool enabled); -typedef OnPeripheralBondStateChange = void Function( - String deviceId, - PeripheralBondState state, -); typedef OnPeripheralCharacteristicSubscriptionChange = void Function( String deviceId, String characteristicId, @@ -35,12 +30,8 @@ typedef OnPeripheralWriteRequest = BleWriteRequestResult? Function( ); typedef OnPeripheralMtuChange = void Function(String deviceId, int mtu); -enum PeripheralBondState { bonding, bonded, none } - abstract class UniversalBlePeripheralPlatform { OnPeripheralAdvertisingStatusUpdate? advertisingStatusUpdateCallback; - OnPeripheralBleStateChange? bleStateChangeCallback; - OnPeripheralBondStateChange? bondStateChangeCallback; OnPeripheralCharacteristicSubscriptionChange? subscriptionChangeCallback; OnPeripheralConnectionStateChange? connectionStateChangeCallback; OnPeripheralReadRequest? readRequestCallback; diff --git a/pigeon/universal_ble_peripheral.dart b/pigeon/universal_ble_peripheral.dart index cf2879a5..1c013baf 100644 --- a/pigeon/universal_ble_peripheral.dart +++ b/pigeon/universal_ble_peripheral.dart @@ -121,9 +121,7 @@ abstract class UniversalBlePeripheralCallback { String? name, ); void onAdvertisingStatusUpdate(bool advertising, String? error); - void onBleStateChange(bool state); void onServiceAdded(String serviceId, String? error); void onMtuChange(String deviceId, int mtu); void onConnectionStateChange(String deviceId, bool connected); - void onBondStateChange(String deviceId, PeripheralBondState bondState); } diff --git a/windows/src/generated/universal_ble_peripheral.g.cpp b/windows/src/generated/universal_ble_peripheral.g.cpp index 1ae07130..ce9a23cb 100644 --- a/windows/src/generated/universal_ble_peripheral.g.cpp +++ b/windows/src/generated/universal_ble_peripheral.g.cpp @@ -1303,31 +1303,6 @@ void UniversalBlePeripheralCallback::OnAdvertisingStatusUpdate( }); } -void UniversalBlePeripheralCallback::OnBleStateChange( - bool state_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBleStateChange" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(state_arg), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - on_success(); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - void UniversalBlePeripheralCallback::OnServiceAdded( const std::string& service_id_arg, const std::string* error_arg, @@ -1409,31 +1384,4 @@ void UniversalBlePeripheralCallback::OnConnectionStateChange( }); } -void UniversalBlePeripheralCallback::OnBondStateChange( - const std::string& device_id_arg, - const PeripheralBondState& bond_state_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onBondStateChange" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(device_id_arg), - CustomEncodableValue(bond_state_arg), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - on_success(); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - } // namespace universal_ble diff --git a/windows/src/generated/universal_ble_peripheral.g.h b/windows/src/generated/universal_ble_peripheral.g.h index 32a7047b..c0b79a1a 100644 --- a/windows/src/generated/universal_ble_peripheral.g.h +++ b/windows/src/generated/universal_ble_peripheral.g.h @@ -391,10 +391,6 @@ class UniversalBlePeripheralCallback { const std::string* error, std::function&& on_success, std::function&& on_error); - void OnBleStateChange( - bool state, - std::function&& on_success, - std::function&& on_error); void OnServiceAdded( const std::string& service_id, const std::string* error, @@ -410,11 +406,6 @@ class UniversalBlePeripheralCallback { bool connected, std::function&& on_success, std::function&& on_error); - void OnBondStateChange( - const std::string& device_id, - const PeripheralBondState& bond_state, - std::function&& on_success, - std::function&& on_error); private: ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; From 996216849ca814b83953151265800e2000456b67 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 11:56:33 +0200 Subject: [PATCH 12/23] Unify pigeon --- .../navideck/universal_ble/UniversalBle.g.kt | 931 ++++++- .../universal_ble/UniversalBlePeripheral.g.kt | 888 ------ build_pigeon.sh | 2 - .../universal_ble/UniversalBle.g.swift | 837 +++++- .../UniversalBlePeripheral.g.swift | 824 ------ .../generated/universal_ble_peripheral.g.dart | 877 ------ .../universal_ble_peripheral_mapper.dart | 2 +- .../universal_ble_peripheral_pigeon.dart | 2 +- .../universal_ble_pigeon/universal_ble.g.dart | 2133 ++++++++++----- pigeon/universal_ble.dart | 109 + pigeon/universal_ble_peripheral.dart | 127 - windows/CMakeLists.txt | 2 - windows/src/generated/universal_ble.g.cpp | 2369 ++++++++++++++--- windows/src/generated/universal_ble.g.h | 560 +++- .../generated/universal_ble_peripheral.g.cpp | 1387 ---------- .../generated/universal_ble_peripheral.g.h | 415 --- windows/src/universal_ble_plugin.cpp | 1 - windows/src/universal_ble_plugin.h | 1 - 18 files changed, 5603 insertions(+), 5864 deletions(-) delete mode 100644 android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt delete mode 100644 darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift delete mode 100644 lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart delete mode 100644 pigeon/universal_ble_peripheral.dart delete mode 100644 windows/src/generated/universal_ble_peripheral.g.cpp delete mode 100644 windows/src/generated/universal_ble_peripheral.g.h diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt index 21188097..0e4dc7db 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.1.4), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") @@ -37,36 +37,150 @@ private object UniversalBlePigeonUtils { ) } } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is IntArray && b is IntArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is LongArray && b is LongArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && a.all { - (b as Map).contains(it.key) && - deepEquals(it.value, b[it.key]) + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } - + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } + } /** @@ -219,15 +333,28 @@ data class UniversalBleScanResult ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalBleScanResult) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as UniversalBleScanResult + return UniversalBlePigeonUtils.deepEquals(this.deviceId, other.deviceId) && UniversalBlePigeonUtils.deepEquals(this.name, other.name) && UniversalBlePigeonUtils.deepEquals(this.isPaired, other.isPaired) && UniversalBlePigeonUtils.deepEquals(this.rssi, other.rssi) && UniversalBlePigeonUtils.deepEquals(this.manufacturerDataList, other.manufacturerDataList) && UniversalBlePigeonUtils.deepEquals(this.serviceData, other.serviceData) && UniversalBlePigeonUtils.deepEquals(this.services, other.services) && UniversalBlePigeonUtils.deepEquals(this.timestamp, other.timestamp) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.deviceId) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.name) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.isPaired) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.rssi) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.manufacturerDataList) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.serviceData) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.services) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.timestamp) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -250,15 +377,22 @@ data class UniversalBleService ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalBleService) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as UniversalBleService + return UniversalBlePigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePigeonUtils.deepEquals(this.characteristics, other.characteristics) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.characteristics) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -284,15 +418,23 @@ data class UniversalBleCharacteristic ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalBleCharacteristic) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as UniversalBleCharacteristic + return UniversalBlePigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePigeonUtils.deepEquals(this.properties, other.properties) && UniversalBlePigeonUtils.deepEquals(this.descriptors, other.descriptors) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.properties) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.descriptors) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -312,15 +454,21 @@ data class UniversalBleDescriptor ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalBleDescriptor) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as UniversalBleDescriptor + return UniversalBlePigeonUtils.deepEquals(this.uuid, other.uuid) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.uuid) + return result + } } /** @@ -355,15 +503,23 @@ data class AndroidOptions ( ) } override fun equals(other: Any?): Boolean { - if (other !is AndroidOptions) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as AndroidOptions + return UniversalBlePigeonUtils.deepEquals(this.requestLocationPermission, other.requestLocationPermission) && UniversalBlePigeonUtils.deepEquals(this.scanMode, other.scanMode) && UniversalBlePigeonUtils.deepEquals(this.reportDelayMillis, other.reportDelayMillis) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.requestLocationPermission) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.scanMode) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.reportDelayMillis) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -383,15 +539,21 @@ data class UniversalScanConfig ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalScanConfig) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as UniversalScanConfig + return UniversalBlePigeonUtils.deepEquals(this.android, other.android) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.android) + return result + } } /** @@ -421,15 +583,23 @@ data class UniversalScanFilter ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalScanFilter) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as UniversalScanFilter + return UniversalBlePigeonUtils.deepEquals(this.withServices, other.withServices) && UniversalBlePigeonUtils.deepEquals(this.withNamePrefix, other.withNamePrefix) && UniversalBlePigeonUtils.deepEquals(this.withManufacturerData, other.withManufacturerData) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.withServices) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.withNamePrefix) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.withManufacturerData) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -455,15 +625,23 @@ data class UniversalManufacturerDataFilter ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalManufacturerDataFilter) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as UniversalManufacturerDataFilter + return UniversalBlePigeonUtils.deepEquals(this.companyIdentifier, other.companyIdentifier) && UniversalBlePigeonUtils.deepEquals(this.data, other.data) && UniversalBlePigeonUtils.deepEquals(this.mask, other.mask) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.companyIdentifier) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.data) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.mask) + return result + } } /** Generated class from Pigeon that represents data sent in messages. */ @@ -486,15 +664,278 @@ data class UniversalManufacturerData ( ) } override fun equals(other: Any?): Boolean { - if (other !is UniversalManufacturerData) { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as UniversalManufacturerData + return UniversalBlePigeonUtils.deepEquals(this.companyIdentifier, other.companyIdentifier) && UniversalBlePigeonUtils.deepEquals(this.data, other.data) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.companyIdentifier) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.data) + return result + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralService ( + val uuid: String, + val primary: Boolean, + val characteristics: List +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralService { + val uuid = pigeonVar_list[0] as String + val primary = pigeonVar_list[1] as Boolean + val characteristics = pigeonVar_list[2] as List + return PeripheralService(uuid, primary, characteristics) + } + } + fun toList(): List { + return listOf( + uuid, + primary, + characteristics, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as PeripheralService + return UniversalBlePigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePigeonUtils.deepEquals(this.primary, other.primary) && UniversalBlePigeonUtils.deepEquals(this.characteristics, other.characteristics) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.primary) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.characteristics) + return result + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralCharacteristic ( + val uuid: String, + val properties: List, + val permissions: List, + val descriptors: List? = null, + val value: ByteArray? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralCharacteristic { + val uuid = pigeonVar_list[0] as String + val properties = pigeonVar_list[1] as List + val permissions = pigeonVar_list[2] as List + val descriptors = pigeonVar_list[3] as List? + val value = pigeonVar_list[4] as ByteArray? + return PeripheralCharacteristic(uuid, properties, permissions, descriptors, value) + } + } + fun toList(): List { + return listOf( + uuid, + properties, + permissions, + descriptors, + value, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as PeripheralCharacteristic + return UniversalBlePigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePigeonUtils.deepEquals(this.properties, other.properties) && UniversalBlePigeonUtils.deepEquals(this.permissions, other.permissions) && UniversalBlePigeonUtils.deepEquals(this.descriptors, other.descriptors) && UniversalBlePigeonUtils.deepEquals(this.value, other.value) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.properties) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.permissions) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.descriptors) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.value) + return result + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralDescriptor ( + val uuid: String, + val value: ByteArray? = null, + val permissions: List? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralDescriptor { + val uuid = pigeonVar_list[0] as String + val value = pigeonVar_list[1] as ByteArray? + val permissions = pigeonVar_list[2] as List? + return PeripheralDescriptor(uuid, value, permissions) + } + } + fun toList(): List { + return listOf( + uuid, + value, + permissions, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as PeripheralDescriptor + return UniversalBlePigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePigeonUtils.deepEquals(this.value, other.value) && UniversalBlePigeonUtils.deepEquals(this.permissions, other.permissions) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.uuid) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.value) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.permissions) + return result + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralReadRequestResult ( + val value: ByteArray, + val offset: Long? = null, + val status: Long? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralReadRequestResult { + val value = pigeonVar_list[0] as ByteArray + val offset = pigeonVar_list[1] as Long? + val status = pigeonVar_list[2] as Long? + return PeripheralReadRequestResult(value, offset, status) + } + } + fun toList(): List { + return listOf( + value, + offset, + status, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as PeripheralReadRequestResult + return UniversalBlePigeonUtils.deepEquals(this.value, other.value) && UniversalBlePigeonUtils.deepEquals(this.offset, other.offset) && UniversalBlePigeonUtils.deepEquals(this.status, other.status) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.value) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.offset) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.status) + return result + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralWriteRequestResult ( + val value: ByteArray? = null, + val offset: Long? = null, + val status: Long? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralWriteRequestResult { + val value = pigeonVar_list[0] as ByteArray? + val offset = pigeonVar_list[1] as Long? + val status = pigeonVar_list[2] as Long? + return PeripheralWriteRequestResult(value, offset, status) + } + } + fun toList(): List { + return listOf( + value, + offset, + status, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as PeripheralWriteRequestResult + return UniversalBlePigeonUtils.deepEquals(this.value, other.value) && UniversalBlePigeonUtils.deepEquals(this.offset, other.offset) && UniversalBlePigeonUtils.deepEquals(this.status, other.status) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.value) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.offset) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.status) + return result + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeripheralManufacturerData ( + val manufacturerId: Long, + val data: ByteArray +) + { + companion object { + fun fromList(pigeonVar_list: List): PeripheralManufacturerData { + val manufacturerId = pigeonVar_list[0] as Long + val data = pigeonVar_list[1] as ByteArray + return PeripheralManufacturerData(manufacturerId, data) + } + } + fun toList(): List { + return listOf( + manufacturerId, + data, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return UniversalBlePigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as PeripheralManufacturerData + return UniversalBlePigeonUtils.deepEquals(this.manufacturerId, other.manufacturerId) && UniversalBlePigeonUtils.deepEquals(this.data, other.data) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.manufacturerId) + result = 31 * result + UniversalBlePigeonUtils.deepHash(this.data) + return result + } } private open class UniversalBlePigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { @@ -559,6 +1000,36 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() { UniversalManufacturerData.fromList(it) } } + 141.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralService.fromList(it) + } + } + 142.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralCharacteristic.fromList(it) + } + } + 143.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralDescriptor.fromList(it) + } + } + 144.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralReadRequestResult.fromList(it) + } + } + 145.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralWriteRequestResult.fromList(it) + } + } + 146.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeripheralManufacturerData.fromList(it) + } + } else -> super.readValueOfType(type, buffer) } } @@ -612,6 +1083,30 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() { stream.write(140) writeValue(stream, value.toList()) } + is PeripheralService -> { + stream.write(141) + writeValue(stream, value.toList()) + } + is PeripheralCharacteristic -> { + stream.write(142) + writeValue(stream, value.toList()) + } + is PeripheralDescriptor -> { + stream.write(143) + writeValue(stream, value.toList()) + } + is PeripheralReadRequestResult -> { + stream.write(144) + writeValue(stream, value.toList()) + } + is PeripheralWriteRequestResult -> { + stream.write(145) + writeValue(stream, value.toList()) + } + is PeripheralManufacturerData -> { + stream.write(146) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } @@ -1197,3 +1692,359 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger, } } } +/** + * Flutter -> Native (peripheral) + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ +interface UniversalBlePeripheralChannel { + fun initialize() + fun isAdvertising(): Boolean? + fun isSupported(): Boolean + fun stopAdvertising() + fun addService(service: PeripheralService) + fun removeService(serviceId: String) + fun clearServices() + fun getServices(): List + fun startAdvertising(services: List, localName: String?, timeout: Long?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Boolean) + fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) + /** + * Returns peripheral-central device ids currently subscribed to [characteristicId] + * (e.g. HID report characteristic). Used to restore app state after restart. + */ + fun getSubscribedCentrals(characteristicId: String): List + + companion object { + /** The codec used by UniversalBlePeripheralChannel. */ + val codec: MessageCodec by lazy { + UniversalBlePigeonCodec() + } + /** Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.initialize() + listOf(null) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.isAdvertising()) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.isSupported()) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.stopAdvertising() + listOf(null) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val serviceArg = args[0] as PeripheralService + val wrapped: List = try { + api.addService(serviceArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val serviceIdArg = args[0] as String + val wrapped: List = try { + api.removeService(serviceIdArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.clearServices() + listOf(null) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.getServices()) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val servicesArg = args[0] as List + val localNameArg = args[1] as String? + val timeoutArg = args[2] as Long? + val manufacturerDataArg = args[3] as PeripheralManufacturerData? + val addManufacturerDataInScanResponseArg = args[4] as Boolean + val wrapped: List = try { + api.startAdvertising(servicesArg, localNameArg, timeoutArg, manufacturerDataArg, addManufacturerDataInScanResponseArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val characteristicIdArg = args[0] as String + val valueArg = args[1] as ByteArray + val deviceIdArg = args[2] as String? + val wrapped: List = try { + api.updateCharacteristic(characteristicIdArg, valueArg, deviceIdArg) + listOf(null) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val characteristicIdArg = args[0] as String + val wrapped: List = try { + listOf(api.getSubscribedCentrals(characteristicIdArg)) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +/** + * Native -> Flutter (peripheral) + * + * Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. + */ +class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by UniversalBlePeripheralCallback. */ + val codec: MessageCodec by lazy { + UniversalBlePigeonCodec() + } + } + fun onReadRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + val output = it[0] as PeripheralReadRequestResult? + callback(Result.success(output)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } + fun onWriteRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + val output = it[0] as PeripheralWriteRequestResult? + callback(Result.success(output)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } + fun onCharacteristicSubscriptionChange(deviceIdArg: String, characteristicIdArg: String, isSubscribedArg: Boolean, nameArg: String?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } + fun onAdvertisingStatusUpdate(advertisingArg: Boolean, errorArg: String?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(advertisingArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } + fun onServiceAdded(serviceIdArg: String, errorArg: String?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(serviceIdArg, errorArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } + fun onMtuChange(deviceIdArg: String, mtuArg: Long, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, mtuArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } + fun onConnectionStateChange(deviceIdArg: String, connectedArg: Boolean, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, connectedArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } +} diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt deleted file mode 100644 index 8d098c1b..00000000 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt +++ /dev/null @@ -1,888 +0,0 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. -// See also: https://pub.dev/packages/pigeon -@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") - -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 UniversalBlePeripheralPigeonUtils { - - fun createConnectionError(channelName: String): FlutterError { - return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") } - - fun wrapResult(result: Any?): List { - return listOf(result) - } - - fun wrapError(exception: Throwable): List { - return if (exception is FlutterError) { - listOf( - exception.code, - exception.message, - exception.details - ) - } else { - listOf( - exception.javaClass.simpleName, - exception.toString(), - "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) - ) - } - } - fun doubleEquals(a: Double, b: Double): Boolean { - // Normalize -0.0 to 0.0 and handle NaN equality. - return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) - } - - fun floatEquals(a: Float, b: Float): Boolean { - // Normalize -0.0 to 0.0 and handle NaN equality. - return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) - } - - fun doubleHash(d: Double): Int { - // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. - val normalized = if (d == 0.0) 0.0 else d - val bits = java.lang.Double.doubleToLongBits(normalized) - return (bits xor (bits ushr 32)).toInt() - } - - fun floatHash(f: Float): Int { - // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. - val normalized = if (f == 0.0f) 0.0f else f - return java.lang.Float.floatToIntBits(normalized) - } - - fun deepEquals(a: Any?, b: Any?): Boolean { - if (a === b) { - return true - } - if (a == null || b == null) { - return false - } - 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) { - if (a.size != b.size) return false - for (i in a.indices) { - if (!doubleEquals(a[i], b[i])) return false - } - return true - } - if (a is FloatArray && b is FloatArray) { - if (a.size != b.size) return false - for (i in a.indices) { - if (!floatEquals(a[i], b[i])) return false - } - return true - } - if (a is Array<*> && b is Array<*>) { - if (a.size != b.size) return false - for (i in a.indices) { - if (!deepEquals(a[i], b[i])) return false - } - return true - } - if (a is List<*> && b is List<*>) { - if (a.size != b.size) return false - val iterA = a.iterator() - val iterB = b.iterator() - while (iterA.hasNext() && iterB.hasNext()) { - if (!deepEquals(iterA.next(), iterB.next())) return false - } - return true - } - if (a is Map<*, *> && b is Map<*, *>) { - if (a.size != b.size) return false - for (entry in a) { - val key = entry.key - var found = false - for (bEntry in b) { - if (deepEquals(key, bEntry.key)) { - if (deepEquals(entry.value, bEntry.value)) { - found = true - break - } else { - return false - } - } - } - if (!found) return false - } - return true - } - if (a is Double && b is Double) { - return doubleEquals(a, b) - } - if (a is Float && b is Float) { - return floatEquals(a, b) - } - return a == b - } - - fun deepHash(value: Any?): Int { - return when (value) { - null -> 0 - is ByteArray -> value.contentHashCode() - is IntArray -> value.contentHashCode() - is LongArray -> value.contentHashCode() - is DoubleArray -> { - var result = 1 - for (item in value) { - result = 31 * result + doubleHash(item) - } - result - } - is FloatArray -> { - var result = 1 - for (item in value) { - result = 31 * result + floatHash(item) - } - result - } - is Array<*> -> { - var result = 1 - for (item in value) { - result = 31 * result + deepHash(item) - } - result - } - is List<*> -> { - var result = 1 - for (item in value) { - result = 31 * result + deepHash(item) - } - result - } - is Map<*, *> -> { - var result = 0 - for (entry in value) { - result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) - } - result - } - is Double -> doubleHash(value) - is Float -> floatHash(value) - else -> value.hashCode() - } - } - -} - -/** - * Error class for passing custom error details to Flutter via a thrown PlatformException. - * @property code The error code. - * @property message The error message. - * @property details The error details. Must be a datatype supported by the api codec. - */ -class FlutterError ( - val code: String, - override val message: String? = null, - val details: Any? = null -) : Throwable() - -enum class PeripheralBondState(val raw: Int) { - BONDING(0), - BONDED(1), - NONE(2); - - companion object { - fun ofRaw(raw: Int): PeripheralBondState? { - return values().firstOrNull { it.raw == raw } - } - } -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class PeripheralService ( - val uuid: String, - val primary: Boolean, - val characteristics: List -) - { - companion object { - fun fromList(pigeonVar_list: List): PeripheralService { - val uuid = pigeonVar_list[0] as String - val primary = pigeonVar_list[1] as Boolean - val characteristics = pigeonVar_list[2] as List - return PeripheralService(uuid, primary, characteristics) - } - } - fun toList(): List { - return listOf( - uuid, - primary, - characteristics, - ) - } - override fun equals(other: Any?): Boolean { - if (other == null || other.javaClass != javaClass) { - return false - } - if (this === other) { - return true - } - val other = other as PeripheralService - return UniversalBlePeripheralPigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePeripheralPigeonUtils.deepEquals(this.primary, other.primary) && UniversalBlePeripheralPigeonUtils.deepEquals(this.characteristics, other.characteristics) - } - - override fun hashCode(): Int { - var result = javaClass.hashCode() - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.uuid) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.primary) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.characteristics) - return result - } -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class PeripheralCharacteristic ( - val uuid: String, - val properties: List, - val permissions: List, - val descriptors: List? = null, - val value: ByteArray? = null -) - { - companion object { - fun fromList(pigeonVar_list: List): PeripheralCharacteristic { - val uuid = pigeonVar_list[0] as String - val properties = pigeonVar_list[1] as List - val permissions = pigeonVar_list[2] as List - val descriptors = pigeonVar_list[3] as List? - val value = pigeonVar_list[4] as ByteArray? - return PeripheralCharacteristic(uuid, properties, permissions, descriptors, value) - } - } - fun toList(): List { - return listOf( - uuid, - properties, - permissions, - descriptors, - value, - ) - } - override fun equals(other: Any?): Boolean { - if (other == null || other.javaClass != javaClass) { - return false - } - if (this === other) { - return true - } - val other = other as PeripheralCharacteristic - return UniversalBlePeripheralPigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePeripheralPigeonUtils.deepEquals(this.properties, other.properties) && UniversalBlePeripheralPigeonUtils.deepEquals(this.permissions, other.permissions) && UniversalBlePeripheralPigeonUtils.deepEquals(this.descriptors, other.descriptors) && UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) - } - - override fun hashCode(): Int { - var result = javaClass.hashCode() - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.uuid) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.properties) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.permissions) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.descriptors) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) - return result - } -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class PeripheralDescriptor ( - val uuid: String, - val value: ByteArray? = null, - val permissions: List? = null -) - { - companion object { - fun fromList(pigeonVar_list: List): PeripheralDescriptor { - val uuid = pigeonVar_list[0] as String - val value = pigeonVar_list[1] as ByteArray? - val permissions = pigeonVar_list[2] as List? - return PeripheralDescriptor(uuid, value, permissions) - } - } - fun toList(): List { - return listOf( - uuid, - value, - permissions, - ) - } - override fun equals(other: Any?): Boolean { - if (other == null || other.javaClass != javaClass) { - return false - } - if (this === other) { - return true - } - val other = other as PeripheralDescriptor - return UniversalBlePeripheralPigeonUtils.deepEquals(this.uuid, other.uuid) && UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) && UniversalBlePeripheralPigeonUtils.deepEquals(this.permissions, other.permissions) - } - - override fun hashCode(): Int { - var result = javaClass.hashCode() - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.uuid) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.permissions) - return result - } -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class PeripheralReadRequestResult ( - val value: ByteArray, - val offset: Long? = null, - val status: Long? = null -) - { - companion object { - fun fromList(pigeonVar_list: List): PeripheralReadRequestResult { - val value = pigeonVar_list[0] as ByteArray - val offset = pigeonVar_list[1] as Long? - val status = pigeonVar_list[2] as Long? - return PeripheralReadRequestResult(value, offset, status) - } - } - fun toList(): List { - return listOf( - value, - offset, - status, - ) - } - override fun equals(other: Any?): Boolean { - if (other == null || other.javaClass != javaClass) { - return false - } - if (this === other) { - return true - } - val other = other as PeripheralReadRequestResult - return UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) && UniversalBlePeripheralPigeonUtils.deepEquals(this.offset, other.offset) && UniversalBlePeripheralPigeonUtils.deepEquals(this.status, other.status) - } - - override fun hashCode(): Int { - var result = javaClass.hashCode() - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.offset) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.status) - return result - } -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class PeripheralWriteRequestResult ( - val value: ByteArray? = null, - val offset: Long? = null, - val status: Long? = null -) - { - companion object { - fun fromList(pigeonVar_list: List): PeripheralWriteRequestResult { - val value = pigeonVar_list[0] as ByteArray? - val offset = pigeonVar_list[1] as Long? - val status = pigeonVar_list[2] as Long? - return PeripheralWriteRequestResult(value, offset, status) - } - } - fun toList(): List { - return listOf( - value, - offset, - status, - ) - } - override fun equals(other: Any?): Boolean { - if (other == null || other.javaClass != javaClass) { - return false - } - if (this === other) { - return true - } - val other = other as PeripheralWriteRequestResult - return UniversalBlePeripheralPigeonUtils.deepEquals(this.value, other.value) && UniversalBlePeripheralPigeonUtils.deepEquals(this.offset, other.offset) && UniversalBlePeripheralPigeonUtils.deepEquals(this.status, other.status) - } - - override fun hashCode(): Int { - var result = javaClass.hashCode() - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.value) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.offset) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.status) - return result - } -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class PeripheralManufacturerData ( - val manufacturerId: Long, - val data: ByteArray -) - { - companion object { - fun fromList(pigeonVar_list: List): PeripheralManufacturerData { - val manufacturerId = pigeonVar_list[0] as Long - val data = pigeonVar_list[1] as ByteArray - return PeripheralManufacturerData(manufacturerId, data) - } - } - fun toList(): List { - return listOf( - manufacturerId, - data, - ) - } - override fun equals(other: Any?): Boolean { - if (other == null || other.javaClass != javaClass) { - return false - } - if (this === other) { - return true - } - val other = other as PeripheralManufacturerData - return UniversalBlePeripheralPigeonUtils.deepEquals(this.manufacturerId, other.manufacturerId) && UniversalBlePeripheralPigeonUtils.deepEquals(this.data, other.data) - } - - override fun hashCode(): Int { - var result = javaClass.hashCode() - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.manufacturerId) - result = 31 * result + UniversalBlePeripheralPigeonUtils.deepHash(this.data) - return result - } -} -private open class UniversalBlePeripheralPigeonCodec : StandardMessageCodec() { - override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { - return when (type) { - 129.toByte() -> { - return (readValue(buffer) as Long?)?.let { - PeripheralBondState.ofRaw(it.toInt()) - } - } - 130.toByte() -> { - return (readValue(buffer) as? List)?.let { - PeripheralService.fromList(it) - } - } - 131.toByte() -> { - return (readValue(buffer) as? List)?.let { - PeripheralCharacteristic.fromList(it) - } - } - 132.toByte() -> { - return (readValue(buffer) as? List)?.let { - PeripheralDescriptor.fromList(it) - } - } - 133.toByte() -> { - return (readValue(buffer) as? List)?.let { - PeripheralReadRequestResult.fromList(it) - } - } - 134.toByte() -> { - return (readValue(buffer) as? List)?.let { - PeripheralWriteRequestResult.fromList(it) - } - } - 135.toByte() -> { - return (readValue(buffer) as? List)?.let { - PeripheralManufacturerData.fromList(it) - } - } - else -> super.readValueOfType(type, buffer) - } - } - override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { - when (value) { - is PeripheralBondState -> { - stream.write(129) - writeValue(stream, value.raw.toLong()) - } - is PeripheralService -> { - stream.write(130) - writeValue(stream, value.toList()) - } - is PeripheralCharacteristic -> { - stream.write(131) - writeValue(stream, value.toList()) - } - is PeripheralDescriptor -> { - stream.write(132) - writeValue(stream, value.toList()) - } - is PeripheralReadRequestResult -> { - stream.write(133) - writeValue(stream, value.toList()) - } - is PeripheralWriteRequestResult -> { - stream.write(134) - writeValue(stream, value.toList()) - } - is PeripheralManufacturerData -> { - stream.write(135) - writeValue(stream, value.toList()) - } - else -> super.writeValue(stream, value) - } - } -} - -/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ -interface UniversalBlePeripheralChannel { - fun initialize() - fun isAdvertising(): Boolean? - fun isSupported(): Boolean - fun stopAdvertising() - fun addService(service: PeripheralService) - fun removeService(serviceId: String) - fun clearServices() - fun getServices(): List - fun startAdvertising(services: List, localName: String?, timeout: Long?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Boolean) - fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) - /** - * Returns peripheral-central device ids currently subscribed to [characteristicId] - * (e.g. HID report characteristic). Used to restore app state after restart. - */ - fun getSubscribedCentrals(characteristicId: String): List - - companion object { - /** The codec used by UniversalBlePeripheralChannel. */ - val codec: MessageCodec by lazy { - UniversalBlePeripheralPigeonCodec() - } - /** Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. */ - @JvmOverloads - fun setUp(binaryMessenger: BinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - api.initialize() - listOf(null) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - listOf(api.isAdvertising()) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - listOf(api.isSupported()) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - api.stopAdvertising() - listOf(null) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val serviceArg = args[0] as PeripheralService - val wrapped: List = try { - api.addService(serviceArg) - listOf(null) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val serviceIdArg = args[0] as String - val wrapped: List = try { - api.removeService(serviceIdArg) - listOf(null) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - api.clearServices() - listOf(null) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - listOf(api.getServices()) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val servicesArg = args[0] as List - val localNameArg = args[1] as String? - val timeoutArg = args[2] as Long? - val manufacturerDataArg = args[3] as PeripheralManufacturerData? - val addManufacturerDataInScanResponseArg = args[4] as Boolean - val wrapped: List = try { - api.startAdvertising(servicesArg, localNameArg, timeoutArg, manufacturerDataArg, addManufacturerDataInScanResponseArg) - listOf(null) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val characteristicIdArg = args[0] as String - val valueArg = args[1] as ByteArray - val deviceIdArg = args[2] as String? - val wrapped: List = try { - api.updateCharacteristic(characteristicIdArg, valueArg, deviceIdArg) - listOf(null) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val characteristicIdArg = args[0] as String - val wrapped: List = try { - listOf(api.getSubscribedCentrals(characteristicIdArg)) - } catch (exception: Throwable) { - UniversalBlePeripheralPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - } - } -} -/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ -class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { - companion object { - /** The codec used by UniversalBlePeripheralCallback. */ - val codec: MessageCodec by lazy { - UniversalBlePeripheralPigeonCodec() - } - } - fun onReadRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - val output = it[0] as PeripheralReadRequestResult? - callback(Result.success(output)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } - fun onWriteRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - val output = it[0] as PeripheralWriteRequestResult? - callback(Result.success(output)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } - fun onCharacteristicSubscriptionChange(deviceIdArg: String, characteristicIdArg: String, isSubscribedArg: Boolean, nameArg: String?, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } - fun onAdvertisingStatusUpdate(advertisingArg: Boolean, errorArg: String?, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(advertisingArg, errorArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } - fun onServiceAdded(serviceIdArg: String, errorArg: String?, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(serviceIdArg, errorArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } - fun onMtuChange(deviceIdArg: String, mtuArg: Long, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, mtuArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } - fun onConnectionStateChange(deviceIdArg: String, connectedArg: Boolean, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, connectedArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(UniversalBlePeripheralPigeonUtils.createConnectionError(channelName))) - } - } - } -} diff --git a/build_pigeon.sh b/build_pigeon.sh index c3a8aeb3..3dbe7ba9 100755 --- a/build_pigeon.sh +++ b/build_pigeon.sh @@ -2,12 +2,10 @@ echo "Building pigeon..." dart run pigeon --input pigeon/universal_ble.dart -dart run pigeon --input pigeon/universal_ble_peripheral.dart echo "Pigeon built successfully" echo "Formatting generated files..." dart format lib/src/universal_ble_pigeon/universal_ble.g.dart -dart format lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart echo "Generated files formatted successfully" echo "Done" \ No newline at end of file diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift index dc40b39f..6132c78f 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.1.4), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -50,7 +50,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } @@ -68,6 +68,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsUniversalBle(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashUniversalBle(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8000000000000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsUniversalBle(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -78,59 +91,92 @@ func deepEqualsUniversalBle(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - 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]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsUniversalBle(element, rhsArray[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]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsUniversalBle(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsUniversalBle(lhsKey, rhsKey) { + if deepEqualsUniversalBle(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsUniversalBle(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + 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) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashUniversalBle(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashUniversalBle(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashUniversalBle(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashUniversalBle(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashUniversalBle(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return - } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) + } else { + hasher.combine(0) } - - return hasher.combine(String(describing: value)) } - enum UniversalBleLogLevel: Int { case none = 0 @@ -261,9 +307,22 @@ struct UniversalBleScanResult: Hashable { ] } static func == (lhs: UniversalBleScanResult, rhs: UniversalBleScanResult) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.deviceId, rhs.deviceId) && deepEqualsUniversalBle(lhs.name, rhs.name) && deepEqualsUniversalBle(lhs.isPaired, rhs.isPaired) && deepEqualsUniversalBle(lhs.rssi, rhs.rssi) && deepEqualsUniversalBle(lhs.manufacturerDataList, rhs.manufacturerDataList) && deepEqualsUniversalBle(lhs.serviceData, rhs.serviceData) && deepEqualsUniversalBle(lhs.services, rhs.services) && deepEqualsUniversalBle(lhs.timestamp, rhs.timestamp) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalBleScanResult") + deepHashUniversalBle(value: deviceId, hasher: &hasher) + deepHashUniversalBle(value: name, hasher: &hasher) + deepHashUniversalBle(value: isPaired, hasher: &hasher) + deepHashUniversalBle(value: rssi, hasher: &hasher) + deepHashUniversalBle(value: manufacturerDataList, hasher: &hasher) + deepHashUniversalBle(value: serviceData, hasher: &hasher) + deepHashUniversalBle(value: services, hasher: &hasher) + deepHashUniversalBle(value: timestamp, hasher: &hasher) } } @@ -290,9 +349,16 @@ struct UniversalBleService: Hashable { ] } static func == (lhs: UniversalBleService, rhs: UniversalBleService) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.uuid, rhs.uuid) && deepEqualsUniversalBle(lhs.characteristics, rhs.characteristics) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalBleService") + deepHashUniversalBle(value: uuid, hasher: &hasher) + deepHashUniversalBle(value: characteristics, hasher: &hasher) } } @@ -323,9 +389,17 @@ struct UniversalBleCharacteristic: Hashable { ] } static func == (lhs: UniversalBleCharacteristic, rhs: UniversalBleCharacteristic) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.uuid, rhs.uuid) && deepEqualsUniversalBle(lhs.properties, rhs.properties) && deepEqualsUniversalBle(lhs.descriptors, rhs.descriptors) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalBleCharacteristic") + deepHashUniversalBle(value: uuid, hasher: &hasher) + deepHashUniversalBle(value: properties, hasher: &hasher) + deepHashUniversalBle(value: descriptors, hasher: &hasher) } } @@ -348,9 +422,15 @@ struct UniversalBleDescriptor: Hashable { ] } static func == (lhs: UniversalBleDescriptor, rhs: UniversalBleDescriptor) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.uuid, rhs.uuid) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalBleDescriptor") + deepHashUniversalBle(value: uuid, hasher: &hasher) } } @@ -388,9 +468,17 @@ struct AndroidOptions: Hashable { ] } static func == (lhs: AndroidOptions, rhs: AndroidOptions) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.requestLocationPermission, rhs.requestLocationPermission) && deepEqualsUniversalBle(lhs.scanMode, rhs.scanMode) && deepEqualsUniversalBle(lhs.reportDelayMillis, rhs.reportDelayMillis) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("AndroidOptions") + deepHashUniversalBle(value: requestLocationPermission, hasher: &hasher) + deepHashUniversalBle(value: scanMode, hasher: &hasher) + deepHashUniversalBle(value: reportDelayMillis, hasher: &hasher) } } @@ -413,9 +501,15 @@ struct UniversalScanConfig: Hashable { ] } static func == (lhs: UniversalScanConfig, rhs: UniversalScanConfig) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.android, rhs.android) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalScanConfig") + deepHashUniversalBle(value: android, hasher: &hasher) } } @@ -448,9 +542,17 @@ struct UniversalScanFilter: Hashable { ] } static func == (lhs: UniversalScanFilter, rhs: UniversalScanFilter) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.withServices, rhs.withServices) && deepEqualsUniversalBle(lhs.withNamePrefix, rhs.withNamePrefix) && deepEqualsUniversalBle(lhs.withManufacturerData, rhs.withManufacturerData) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalScanFilter") + deepHashUniversalBle(value: withServices, hasher: &hasher) + deepHashUniversalBle(value: withNamePrefix, hasher: &hasher) + deepHashUniversalBle(value: withManufacturerData, hasher: &hasher) } } @@ -481,9 +583,17 @@ struct UniversalManufacturerDataFilter: Hashable { ] } static func == (lhs: UniversalManufacturerDataFilter, rhs: UniversalManufacturerDataFilter) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.companyIdentifier, rhs.companyIdentifier) && deepEqualsUniversalBle(lhs.data, rhs.data) && deepEqualsUniversalBle(lhs.mask, rhs.mask) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalManufacturerDataFilter") + deepHashUniversalBle(value: companyIdentifier, hasher: &hasher) + deepHashUniversalBle(value: data, hasher: &hasher) + deepHashUniversalBle(value: mask, hasher: &hasher) } } @@ -510,9 +620,267 @@ struct UniversalManufacturerData: Hashable { ] } static func == (lhs: UniversalManufacturerData, rhs: UniversalManufacturerData) -> Bool { - return deepEqualsUniversalBle(lhs.toList(), rhs.toList()) } + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.companyIdentifier, rhs.companyIdentifier) && deepEqualsUniversalBle(lhs.data, rhs.data) + } + func hash(into hasher: inout Hasher) { - deepHashUniversalBle(value: toList(), hasher: &hasher) + hasher.combine("UniversalManufacturerData") + deepHashUniversalBle(value: companyIdentifier, hasher: &hasher) + deepHashUniversalBle(value: data, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralService: Hashable { + var uuid: String + var primary: Bool + var characteristics: [PeripheralCharacteristic] + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralService? { + let uuid = pigeonVar_list[0] as! String + let primary = pigeonVar_list[1] as! Bool + let characteristics = pigeonVar_list[2] as! [PeripheralCharacteristic] + + return PeripheralService( + uuid: uuid, + primary: primary, + characteristics: characteristics + ) + } + func toList() -> [Any?] { + return [ + uuid, + primary, + characteristics, + ] + } + static func == (lhs: PeripheralService, rhs: PeripheralService) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.uuid, rhs.uuid) && deepEqualsUniversalBle(lhs.primary, rhs.primary) && deepEqualsUniversalBle(lhs.characteristics, rhs.characteristics) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("PeripheralService") + deepHashUniversalBle(value: uuid, hasher: &hasher) + deepHashUniversalBle(value: primary, hasher: &hasher) + deepHashUniversalBle(value: characteristics, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralCharacteristic: Hashable { + var uuid: String + var properties: [Int64] + var permissions: [Int64] + var descriptors: [PeripheralDescriptor]? = nil + var value: FlutterStandardTypedData? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralCharacteristic? { + let uuid = pigeonVar_list[0] as! String + let properties = pigeonVar_list[1] as! [Int64] + let permissions = pigeonVar_list[2] as! [Int64] + let descriptors: [PeripheralDescriptor]? = nilOrValue(pigeonVar_list[3]) + let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[4]) + + return PeripheralCharacteristic( + uuid: uuid, + properties: properties, + permissions: permissions, + descriptors: descriptors, + value: value + ) + } + func toList() -> [Any?] { + return [ + uuid, + properties, + permissions, + descriptors, + value, + ] + } + static func == (lhs: PeripheralCharacteristic, rhs: PeripheralCharacteristic) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.uuid, rhs.uuid) && deepEqualsUniversalBle(lhs.properties, rhs.properties) && deepEqualsUniversalBle(lhs.permissions, rhs.permissions) && deepEqualsUniversalBle(lhs.descriptors, rhs.descriptors) && deepEqualsUniversalBle(lhs.value, rhs.value) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("PeripheralCharacteristic") + deepHashUniversalBle(value: uuid, hasher: &hasher) + deepHashUniversalBle(value: properties, hasher: &hasher) + deepHashUniversalBle(value: permissions, hasher: &hasher) + deepHashUniversalBle(value: descriptors, hasher: &hasher) + deepHashUniversalBle(value: value, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralDescriptor: Hashable { + var uuid: String + var value: FlutterStandardTypedData? = nil + var permissions: [Int64]? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralDescriptor? { + let uuid = pigeonVar_list[0] as! String + let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[1]) + let permissions: [Int64]? = nilOrValue(pigeonVar_list[2]) + + return PeripheralDescriptor( + uuid: uuid, + value: value, + permissions: permissions + ) + } + func toList() -> [Any?] { + return [ + uuid, + value, + permissions, + ] + } + static func == (lhs: PeripheralDescriptor, rhs: PeripheralDescriptor) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.uuid, rhs.uuid) && deepEqualsUniversalBle(lhs.value, rhs.value) && deepEqualsUniversalBle(lhs.permissions, rhs.permissions) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("PeripheralDescriptor") + deepHashUniversalBle(value: uuid, hasher: &hasher) + deepHashUniversalBle(value: value, hasher: &hasher) + deepHashUniversalBle(value: permissions, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralReadRequestResult: Hashable { + var value: FlutterStandardTypedData + var offset: Int64? = nil + var status: Int64? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralReadRequestResult? { + let value = pigeonVar_list[0] as! FlutterStandardTypedData + let offset: Int64? = nilOrValue(pigeonVar_list[1]) + let status: Int64? = nilOrValue(pigeonVar_list[2]) + + return PeripheralReadRequestResult( + value: value, + offset: offset, + status: status + ) + } + func toList() -> [Any?] { + return [ + value, + offset, + status, + ] + } + static func == (lhs: PeripheralReadRequestResult, rhs: PeripheralReadRequestResult) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.value, rhs.value) && deepEqualsUniversalBle(lhs.offset, rhs.offset) && deepEqualsUniversalBle(lhs.status, rhs.status) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("PeripheralReadRequestResult") + deepHashUniversalBle(value: value, hasher: &hasher) + deepHashUniversalBle(value: offset, hasher: &hasher) + deepHashUniversalBle(value: status, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralWriteRequestResult: Hashable { + var value: FlutterStandardTypedData? = nil + var offset: Int64? = nil + var status: Int64? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralWriteRequestResult? { + let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[0]) + let offset: Int64? = nilOrValue(pigeonVar_list[1]) + let status: Int64? = nilOrValue(pigeonVar_list[2]) + + return PeripheralWriteRequestResult( + value: value, + offset: offset, + status: status + ) + } + func toList() -> [Any?] { + return [ + value, + offset, + status, + ] + } + static func == (lhs: PeripheralWriteRequestResult, rhs: PeripheralWriteRequestResult) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.value, rhs.value) && deepEqualsUniversalBle(lhs.offset, rhs.offset) && deepEqualsUniversalBle(lhs.status, rhs.status) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("PeripheralWriteRequestResult") + deepHashUniversalBle(value: value, hasher: &hasher) + deepHashUniversalBle(value: offset, hasher: &hasher) + deepHashUniversalBle(value: status, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeripheralManufacturerData: Hashable { + var manufacturerId: Int64 + var data: FlutterStandardTypedData + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralManufacturerData? { + let manufacturerId = pigeonVar_list[0] as! Int64 + let data = pigeonVar_list[1] as! FlutterStandardTypedData + + return PeripheralManufacturerData( + manufacturerId: manufacturerId, + data: data + ) + } + func toList() -> [Any?] { + return [ + manufacturerId, + data, + ] + } + static func == (lhs: PeripheralManufacturerData, rhs: PeripheralManufacturerData) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsUniversalBle(lhs.manufacturerId, rhs.manufacturerId) && deepEqualsUniversalBle(lhs.data, rhs.data) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("PeripheralManufacturerData") + deepHashUniversalBle(value: manufacturerId, hasher: &hasher) + deepHashUniversalBle(value: data, hasher: &hasher) } } @@ -555,6 +923,18 @@ private class UniversalBlePigeonCodecReader: FlutterStandardReader { return UniversalManufacturerDataFilter.fromList(self.readValue() as! [Any?]) case 140: return UniversalManufacturerData.fromList(self.readValue() as! [Any?]) + case 141: + return PeripheralService.fromList(self.readValue() as! [Any?]) + case 142: + return PeripheralCharacteristic.fromList(self.readValue() as! [Any?]) + case 143: + return PeripheralDescriptor.fromList(self.readValue() as! [Any?]) + case 144: + return PeripheralReadRequestResult.fromList(self.readValue() as! [Any?]) + case 145: + return PeripheralWriteRequestResult.fromList(self.readValue() as! [Any?]) + case 146: + return PeripheralManufacturerData.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) } @@ -599,6 +979,24 @@ private class UniversalBlePigeonCodecWriter: FlutterStandardWriter { } else if let value = value as? UniversalManufacturerData { super.writeByte(140) super.writeValue(value.toList()) + } else if let value = value as? PeripheralService { + super.writeByte(141) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralCharacteristic { + super.writeByte(142) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralDescriptor { + super.writeByte(143) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralReadRequestResult { + super.writeByte(144) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralWriteRequestResult { + super.writeByte(145) + super.writeValue(value.toList()) + } else if let value = value as? PeripheralManufacturerData { + super.writeByte(146) + super.writeValue(value.toList()) } else { super.writeValue(value) } @@ -1145,3 +1543,342 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol { } } } +/// Flutter -> Native (peripheral) +/// +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol UniversalBlePeripheralChannel { + func initialize() throws + func isAdvertising() throws -> Bool? + func isSupported() throws -> Bool + func stopAdvertising() throws + func addService(service: PeripheralService) throws + func removeService(serviceId: String) throws + func clearServices() throws + func getServices() throws -> [String] + func startAdvertising(services: [String], localName: String?, timeout: Int64?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Bool) throws + func updateCharacteristic(characteristicId: String, value: FlutterStandardTypedData, deviceId: String?) throws + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + func getSubscribedCentrals(characteristicId: String) throws -> [String] +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class UniversalBlePeripheralChannelSetup { + static var codec: FlutterStandardMessageCodec { UniversalBlePigeonCodec.shared } + /// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let initializeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + initializeChannel.setMessageHandler { _, reply in + do { + try api.initialize() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + initializeChannel.setMessageHandler(nil) + } + let isAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + isAdvertisingChannel.setMessageHandler { _, reply in + do { + let result = try api.isAdvertising() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + isAdvertisingChannel.setMessageHandler(nil) + } + let isSupportedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + isSupportedChannel.setMessageHandler { _, reply in + do { + let result = try api.isSupported() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + isSupportedChannel.setMessageHandler(nil) + } + let stopAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + stopAdvertisingChannel.setMessageHandler { _, reply in + do { + try api.stopAdvertising() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + stopAdvertisingChannel.setMessageHandler(nil) + } + let addServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addServiceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let serviceArg = args[0] as! PeripheralService + do { + try api.addService(service: serviceArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + addServiceChannel.setMessageHandler(nil) + } + let removeServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeServiceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let serviceIdArg = args[0] as! String + do { + try api.removeService(serviceId: serviceIdArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + removeServiceChannel.setMessageHandler(nil) + } + let clearServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + clearServicesChannel.setMessageHandler { _, reply in + do { + try api.clearServices() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + clearServicesChannel.setMessageHandler(nil) + } + let getServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getServicesChannel.setMessageHandler { _, reply in + do { + let result = try api.getServices() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getServicesChannel.setMessageHandler(nil) + } + let startAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + startAdvertisingChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let servicesArg = args[0] as! [String] + let localNameArg: String? = nilOrValue(args[1]) + let timeoutArg: Int64? = nilOrValue(args[2]) + let manufacturerDataArg: PeripheralManufacturerData? = nilOrValue(args[3]) + let addManufacturerDataInScanResponseArg = args[4] as! Bool + do { + try api.startAdvertising(services: servicesArg, localName: localNameArg, timeout: timeoutArg, manufacturerData: manufacturerDataArg, addManufacturerDataInScanResponse: addManufacturerDataInScanResponseArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + startAdvertisingChannel.setMessageHandler(nil) + } + let updateCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + updateCharacteristicChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let characteristicIdArg = args[0] as! String + let valueArg = args[1] as! FlutterStandardTypedData + let deviceIdArg: String? = nilOrValue(args[2]) + do { + try api.updateCharacteristic(characteristicId: characteristicIdArg, value: valueArg, deviceId: deviceIdArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + updateCharacteristicChannel.setMessageHandler(nil) + } + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + let getSubscribedCentralsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getSubscribedCentralsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let characteristicIdArg = args[0] as! String + do { + let result = try api.getSubscribedCentrals(characteristicId: characteristicIdArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getSubscribedCentralsChannel.setMessageHandler(nil) + } + } +} +/// Native -> Flutter (peripheral) +/// +/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. +protocol UniversalBlePeripheralCallbackProtocol { + func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) + func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) + func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) + func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) + func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) + func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) + func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) +} +class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { + private let binaryMessenger: FlutterBinaryMessenger + private let messageChannelSuffix: String + init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { + self.binaryMessenger = binaryMessenger + self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + } + var codec: UniversalBlePigeonCodec { + return UniversalBlePigeonCodec.shared + } + func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + let result: PeripheralReadRequestResult? = nilOrValue(listResponse[0]) + completion(.success(result)) + } + } + } + func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + let result: PeripheralWriteRequestResult? = nilOrValue(listResponse[0]) + completion(.success(result)) + } + } + } + func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([advertisingArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([serviceIdArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, mtuArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } + func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, connectedArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(())) + } + } + } +} diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift deleted file mode 100644 index ace8449f..00000000 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheral.g.swift +++ /dev/null @@ -1,824 +0,0 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. -// See also: https://pub.dev/packages/pigeon - -import Foundation - -#if os(iOS) - import Flutter -#elseif os(macOS) - import FlutterMacOS -#else - #error("Unsupported platform.") -#endif - -private func wrapResult(_ result: Any?) -> [Any?] { - return [result] -} - -private func wrapError(_ error: Any) -> [Any?] { - if let pigeonError = error as? PigeonError { - return [ - pigeonError.code, - pigeonError.message, - pigeonError.details, - ] - } - if let flutterError = error as? FlutterError { - return [ - flutterError.code, - flutterError.message, - flutterError.details, - ] - } - return [ - "\(error)", - "\(Swift.type(of: error))", - "Stacktrace: \(Thread.callStackSymbols)", - ] -} - -private func createConnectionError(withChannelName channelName: String) -> PigeonError { - return PigeonError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "") -} - -private func isNullish(_ value: Any?) -> Bool { - return value is NSNull || value == nil -} - -private func nilOrValue(_ value: Any?) -> T? { - if value is NSNull { return nil } - return value as! T? -} - -private func doubleEqualsUniversalBlePeripheral(_ lhs: Double, _ rhs: Double) -> Bool { - return (lhs.isNaN && rhs.isNaN) || lhs == rhs -} - -private func doubleHashUniversalBlePeripheral(_ value: Double, _ hasher: inout Hasher) { - if value.isNaN { - hasher.combine(0x7FF8000000000000) - } else { - // Normalize -0.0 to 0.0 - hasher.combine(value == 0 ? 0 : value) - } -} - -func deepEqualsUniversalBlePeripheral(_ 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 (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: - return true - - case is (Void, Void): - return true - - case (let lhsArray, let rhsArray) as ([Any?], [Any?]): - guard lhsArray.count == rhsArray.count else { return false } - for (index, element) in lhsArray.enumerated() { - if !deepEqualsUniversalBlePeripheral(element, rhsArray[index]) { - return false - } - } - return true - - case (let lhsArray, let rhsArray) as ([Double], [Double]): - guard lhsArray.count == rhsArray.count else { return false } - for (index, element) in lhsArray.enumerated() { - if !doubleEqualsUniversalBlePeripheral(element, rhsArray[index]) { - return false - } - } - return true - - case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard lhsDictionary.count == rhsDictionary.count else { return false } - for (lhsKey, lhsValue) in lhsDictionary { - var found = false - for (rhsKey, rhsValue) in rhsDictionary { - if deepEqualsUniversalBlePeripheral(lhsKey, rhsKey) { - if deepEqualsUniversalBlePeripheral(lhsValue, rhsValue) { - found = true - break - } else { - return false - } - } - } - if !found { return false } - } - return true - - case (let lhs as Double, let rhs as Double): - return doubleEqualsUniversalBlePeripheral(lhs, rhs) - - case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): - return lhsHashable == rhsHashable - - default: - return false - } -} - -func deepHashUniversalBlePeripheral(value: Any?, hasher: inout Hasher) { - let cleanValue = nilOrValue(value) as Any? - if let cleanValue = cleanValue { - if let doubleValue = cleanValue as? Double { - doubleHashUniversalBlePeripheral(doubleValue, &hasher) - } else if let valueList = cleanValue as? [Any?] { - for item in valueList { - deepHashUniversalBlePeripheral(value: item, hasher: &hasher) - } - } else if let valueList = cleanValue as? [Double] { - for item in valueList { - doubleHashUniversalBlePeripheral(item, &hasher) - } - } else if let valueDict = cleanValue as? [AnyHashable: Any?] { - var result = 0 - for (key, value) in valueDict { - var entryKeyHasher = Hasher() - deepHashUniversalBlePeripheral(value: key, hasher: &entryKeyHasher) - var entryValueHasher = Hasher() - deepHashUniversalBlePeripheral(value: value, hasher: &entryValueHasher) - result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) - } - hasher.combine(result) - } else if let hashableValue = cleanValue as? AnyHashable { - hasher.combine(hashableValue) - } else { - hasher.combine(String(describing: cleanValue)) - } - } else { - hasher.combine(0) - } -} - - -enum PeripheralBondState: Int { - case bonding = 0 - case bonded = 1 - case none = 2 -} - -/// Generated class from Pigeon that represents data sent in messages. -struct PeripheralService: Hashable { - var uuid: String - var primary: Bool - var characteristics: [PeripheralCharacteristic] - - - // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralService? { - let uuid = pigeonVar_list[0] as! String - let primary = pigeonVar_list[1] as! Bool - let characteristics = pigeonVar_list[2] as! [PeripheralCharacteristic] - - return PeripheralService( - uuid: uuid, - primary: primary, - characteristics: characteristics - ) - } - func toList() -> [Any?] { - return [ - uuid, - primary, - characteristics, - ] - } - static func == (lhs: PeripheralService, rhs: PeripheralService) -> Bool { - if Swift.type(of: lhs) != Swift.type(of: rhs) { - return false - } - return deepEqualsUniversalBlePeripheral(lhs.uuid, rhs.uuid) && deepEqualsUniversalBlePeripheral(lhs.primary, rhs.primary) && deepEqualsUniversalBlePeripheral(lhs.characteristics, rhs.characteristics) - } - - func hash(into hasher: inout Hasher) { - hasher.combine("PeripheralService") - deepHashUniversalBlePeripheral(value: uuid, hasher: &hasher) - deepHashUniversalBlePeripheral(value: primary, hasher: &hasher) - deepHashUniversalBlePeripheral(value: characteristics, hasher: &hasher) - } -} - -/// Generated class from Pigeon that represents data sent in messages. -struct PeripheralCharacteristic: Hashable { - var uuid: String - var properties: [Int64] - var permissions: [Int64] - var descriptors: [PeripheralDescriptor]? = nil - var value: FlutterStandardTypedData? = nil - - - // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralCharacteristic? { - let uuid = pigeonVar_list[0] as! String - let properties = pigeonVar_list[1] as! [Int64] - let permissions = pigeonVar_list[2] as! [Int64] - let descriptors: [PeripheralDescriptor]? = nilOrValue(pigeonVar_list[3]) - let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[4]) - - return PeripheralCharacteristic( - uuid: uuid, - properties: properties, - permissions: permissions, - descriptors: descriptors, - value: value - ) - } - func toList() -> [Any?] { - return [ - uuid, - properties, - permissions, - descriptors, - value, - ] - } - static func == (lhs: PeripheralCharacteristic, rhs: PeripheralCharacteristic) -> Bool { - if Swift.type(of: lhs) != Swift.type(of: rhs) { - return false - } - return deepEqualsUniversalBlePeripheral(lhs.uuid, rhs.uuid) && deepEqualsUniversalBlePeripheral(lhs.properties, rhs.properties) && deepEqualsUniversalBlePeripheral(lhs.permissions, rhs.permissions) && deepEqualsUniversalBlePeripheral(lhs.descriptors, rhs.descriptors) && deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) - } - - func hash(into hasher: inout Hasher) { - hasher.combine("PeripheralCharacteristic") - deepHashUniversalBlePeripheral(value: uuid, hasher: &hasher) - deepHashUniversalBlePeripheral(value: properties, hasher: &hasher) - deepHashUniversalBlePeripheral(value: permissions, hasher: &hasher) - deepHashUniversalBlePeripheral(value: descriptors, hasher: &hasher) - deepHashUniversalBlePeripheral(value: value, hasher: &hasher) - } -} - -/// Generated class from Pigeon that represents data sent in messages. -struct PeripheralDescriptor: Hashable { - var uuid: String - var value: FlutterStandardTypedData? = nil - var permissions: [Int64]? = nil - - - // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralDescriptor? { - let uuid = pigeonVar_list[0] as! String - let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[1]) - let permissions: [Int64]? = nilOrValue(pigeonVar_list[2]) - - return PeripheralDescriptor( - uuid: uuid, - value: value, - permissions: permissions - ) - } - func toList() -> [Any?] { - return [ - uuid, - value, - permissions, - ] - } - static func == (lhs: PeripheralDescriptor, rhs: PeripheralDescriptor) -> Bool { - if Swift.type(of: lhs) != Swift.type(of: rhs) { - return false - } - return deepEqualsUniversalBlePeripheral(lhs.uuid, rhs.uuid) && deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) && deepEqualsUniversalBlePeripheral(lhs.permissions, rhs.permissions) - } - - func hash(into hasher: inout Hasher) { - hasher.combine("PeripheralDescriptor") - deepHashUniversalBlePeripheral(value: uuid, hasher: &hasher) - deepHashUniversalBlePeripheral(value: value, hasher: &hasher) - deepHashUniversalBlePeripheral(value: permissions, hasher: &hasher) - } -} - -/// Generated class from Pigeon that represents data sent in messages. -struct PeripheralReadRequestResult: Hashable { - var value: FlutterStandardTypedData - var offset: Int64? = nil - var status: Int64? = nil - - - // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralReadRequestResult? { - let value = pigeonVar_list[0] as! FlutterStandardTypedData - let offset: Int64? = nilOrValue(pigeonVar_list[1]) - let status: Int64? = nilOrValue(pigeonVar_list[2]) - - return PeripheralReadRequestResult( - value: value, - offset: offset, - status: status - ) - } - func toList() -> [Any?] { - return [ - value, - offset, - status, - ] - } - static func == (lhs: PeripheralReadRequestResult, rhs: PeripheralReadRequestResult) -> Bool { - if Swift.type(of: lhs) != Swift.type(of: rhs) { - return false - } - return deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) && deepEqualsUniversalBlePeripheral(lhs.offset, rhs.offset) && deepEqualsUniversalBlePeripheral(lhs.status, rhs.status) - } - - func hash(into hasher: inout Hasher) { - hasher.combine("PeripheralReadRequestResult") - deepHashUniversalBlePeripheral(value: value, hasher: &hasher) - deepHashUniversalBlePeripheral(value: offset, hasher: &hasher) - deepHashUniversalBlePeripheral(value: status, hasher: &hasher) - } -} - -/// Generated class from Pigeon that represents data sent in messages. -struct PeripheralWriteRequestResult: Hashable { - var value: FlutterStandardTypedData? = nil - var offset: Int64? = nil - var status: Int64? = nil - - - // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralWriteRequestResult? { - let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[0]) - let offset: Int64? = nilOrValue(pigeonVar_list[1]) - let status: Int64? = nilOrValue(pigeonVar_list[2]) - - return PeripheralWriteRequestResult( - value: value, - offset: offset, - status: status - ) - } - func toList() -> [Any?] { - return [ - value, - offset, - status, - ] - } - static func == (lhs: PeripheralWriteRequestResult, rhs: PeripheralWriteRequestResult) -> Bool { - if Swift.type(of: lhs) != Swift.type(of: rhs) { - return false - } - return deepEqualsUniversalBlePeripheral(lhs.value, rhs.value) && deepEqualsUniversalBlePeripheral(lhs.offset, rhs.offset) && deepEqualsUniversalBlePeripheral(lhs.status, rhs.status) - } - - func hash(into hasher: inout Hasher) { - hasher.combine("PeripheralWriteRequestResult") - deepHashUniversalBlePeripheral(value: value, hasher: &hasher) - deepHashUniversalBlePeripheral(value: offset, hasher: &hasher) - deepHashUniversalBlePeripheral(value: status, hasher: &hasher) - } -} - -/// Generated class from Pigeon that represents data sent in messages. -struct PeripheralManufacturerData: Hashable { - var manufacturerId: Int64 - var data: FlutterStandardTypedData - - - // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> PeripheralManufacturerData? { - let manufacturerId = pigeonVar_list[0] as! Int64 - let data = pigeonVar_list[1] as! FlutterStandardTypedData - - return PeripheralManufacturerData( - manufacturerId: manufacturerId, - data: data - ) - } - func toList() -> [Any?] { - return [ - manufacturerId, - data, - ] - } - static func == (lhs: PeripheralManufacturerData, rhs: PeripheralManufacturerData) -> Bool { - if Swift.type(of: lhs) != Swift.type(of: rhs) { - return false - } - return deepEqualsUniversalBlePeripheral(lhs.manufacturerId, rhs.manufacturerId) && deepEqualsUniversalBlePeripheral(lhs.data, rhs.data) - } - - func hash(into hasher: inout Hasher) { - hasher.combine("PeripheralManufacturerData") - deepHashUniversalBlePeripheral(value: manufacturerId, hasher: &hasher) - deepHashUniversalBlePeripheral(value: data, hasher: &hasher) - } -} - -private class UniversalBlePeripheralPigeonCodecReader: FlutterStandardReader { - override func readValue(ofType type: UInt8) -> Any? { - switch type { - case 129: - let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) - if let enumResultAsInt = enumResultAsInt { - return PeripheralBondState(rawValue: enumResultAsInt) - } - return nil - case 130: - return PeripheralService.fromList(self.readValue() as! [Any?]) - case 131: - return PeripheralCharacteristic.fromList(self.readValue() as! [Any?]) - case 132: - return PeripheralDescriptor.fromList(self.readValue() as! [Any?]) - case 133: - return PeripheralReadRequestResult.fromList(self.readValue() as! [Any?]) - case 134: - return PeripheralWriteRequestResult.fromList(self.readValue() as! [Any?]) - case 135: - return PeripheralManufacturerData.fromList(self.readValue() as! [Any?]) - default: - return super.readValue(ofType: type) - } - } -} - -private class UniversalBlePeripheralPigeonCodecWriter: FlutterStandardWriter { - override func writeValue(_ value: Any) { - if let value = value as? PeripheralBondState { - super.writeByte(129) - super.writeValue(value.rawValue) - } else if let value = value as? PeripheralService { - super.writeByte(130) - super.writeValue(value.toList()) - } else if let value = value as? PeripheralCharacteristic { - super.writeByte(131) - super.writeValue(value.toList()) - } else if let value = value as? PeripheralDescriptor { - super.writeByte(132) - super.writeValue(value.toList()) - } else if let value = value as? PeripheralReadRequestResult { - super.writeByte(133) - super.writeValue(value.toList()) - } else if let value = value as? PeripheralWriteRequestResult { - super.writeByte(134) - super.writeValue(value.toList()) - } else if let value = value as? PeripheralManufacturerData { - super.writeByte(135) - super.writeValue(value.toList()) - } else { - super.writeValue(value) - } - } -} - -private class UniversalBlePeripheralPigeonCodecReaderWriter: FlutterStandardReaderWriter { - override func reader(with data: Data) -> FlutterStandardReader { - return UniversalBlePeripheralPigeonCodecReader(data: data) - } - - override func writer(with data: NSMutableData) -> FlutterStandardWriter { - return UniversalBlePeripheralPigeonCodecWriter(data: data) - } -} - -class UniversalBlePeripheralPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { - static let shared = UniversalBlePeripheralPigeonCodec(readerWriter: UniversalBlePeripheralPigeonCodecReaderWriter()) -} - -/// Generated protocol from Pigeon that represents a handler of messages from Flutter. -protocol UniversalBlePeripheralChannel { - func initialize() throws - func isAdvertising() throws -> Bool? - func isSupported() throws -> Bool - func stopAdvertising() throws - func addService(service: PeripheralService) throws - func removeService(serviceId: String) throws - func clearServices() throws - func getServices() throws -> [String] - func startAdvertising(services: [String], localName: String?, timeout: Int64?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Bool) throws - func updateCharacteristic(characteristicId: String, value: FlutterStandardTypedData, deviceId: String?) throws - /// Returns peripheral-central device ids currently subscribed to [characteristicId] - /// (e.g. HID report characteristic). Used to restore app state after restart. - func getSubscribedCentrals(characteristicId: String) throws -> [String] -} - -/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. -class UniversalBlePeripheralChannelSetup { - static var codec: FlutterStandardMessageCodec { UniversalBlePeripheralPigeonCodec.shared } - /// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. - static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { - let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" - let initializeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - initializeChannel.setMessageHandler { _, reply in - do { - try api.initialize() - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - initializeChannel.setMessageHandler(nil) - } - let isAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - isAdvertisingChannel.setMessageHandler { _, reply in - do { - let result = try api.isAdvertising() - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - isAdvertisingChannel.setMessageHandler(nil) - } - let isSupportedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - isSupportedChannel.setMessageHandler { _, reply in - do { - let result = try api.isSupported() - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - isSupportedChannel.setMessageHandler(nil) - } - let stopAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - stopAdvertisingChannel.setMessageHandler { _, reply in - do { - try api.stopAdvertising() - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - stopAdvertisingChannel.setMessageHandler(nil) - } - let addServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - addServiceChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let serviceArg = args[0] as! PeripheralService - do { - try api.addService(service: serviceArg) - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - addServiceChannel.setMessageHandler(nil) - } - let removeServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - removeServiceChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let serviceIdArg = args[0] as! String - do { - try api.removeService(serviceId: serviceIdArg) - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - removeServiceChannel.setMessageHandler(nil) - } - let clearServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - clearServicesChannel.setMessageHandler { _, reply in - do { - try api.clearServices() - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - clearServicesChannel.setMessageHandler(nil) - } - let getServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - getServicesChannel.setMessageHandler { _, reply in - do { - let result = try api.getServices() - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - getServicesChannel.setMessageHandler(nil) - } - let startAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - startAdvertisingChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let servicesArg = args[0] as! [String] - let localNameArg: String? = nilOrValue(args[1]) - let timeoutArg: Int64? = nilOrValue(args[2]) - let manufacturerDataArg: PeripheralManufacturerData? = nilOrValue(args[3]) - let addManufacturerDataInScanResponseArg = args[4] as! Bool - do { - try api.startAdvertising(services: servicesArg, localName: localNameArg, timeout: timeoutArg, manufacturerData: manufacturerDataArg, addManufacturerDataInScanResponse: addManufacturerDataInScanResponseArg) - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - startAdvertisingChannel.setMessageHandler(nil) - } - let updateCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - updateCharacteristicChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let characteristicIdArg = args[0] as! String - let valueArg = args[1] as! FlutterStandardTypedData - let deviceIdArg: String? = nilOrValue(args[2]) - do { - try api.updateCharacteristic(characteristicId: characteristicIdArg, value: valueArg, deviceId: deviceIdArg) - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - updateCharacteristicChannel.setMessageHandler(nil) - } - /// Returns peripheral-central device ids currently subscribed to [characteristicId] - /// (e.g. HID report characteristic). Used to restore app state after restart. - let getSubscribedCentralsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - getSubscribedCentralsChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let characteristicIdArg = args[0] as! String - do { - let result = try api.getSubscribedCentrals(characteristicId: characteristicIdArg) - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - getSubscribedCentralsChannel.setMessageHandler(nil) - } - } -} -/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. -protocol UniversalBlePeripheralCallbackProtocol { - func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) - func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) - func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) - func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) - func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) - func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) - func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) -} -class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { - private let binaryMessenger: FlutterBinaryMessenger - private let messageChannelSuffix: String - init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { - self.binaryMessenger = binaryMessenger - self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" - } - var codec: UniversalBlePeripheralPigeonCodec { - return UniversalBlePeripheralPigeonCodec.shared - } - func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - let result: PeripheralReadRequestResult? = nilOrValue(listResponse[0]) - completion(.success(result)) - } - } - } - func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - let result: PeripheralWriteRequestResult? = nilOrValue(listResponse[0]) - completion(.success(result)) - } - } - } - func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - completion(.success(())) - } - } - } - func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([advertisingArg, errorArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - completion(.success(())) - } - } - } - func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([serviceIdArg, errorArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - completion(.success(())) - } - } - } - func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, mtuArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - completion(.success(())) - } - } - } - func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, connectedArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - completion(.success(())) - } - } - } -} diff --git a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart b/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart deleted file mode 100644 index cd77bb28..00000000 --- a/lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart +++ /dev/null @@ -1,877 +0,0 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. -// See also: https://pub.dev/packages/pigeon -// ignore_for_file: unused_import, unused_shown_name -// ignore_for_file: type=lint - -import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List; - -import 'package:flutter/services.dart'; -import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; - -Object? _extractReplyValueOrThrow( - List? replyList, - String channelName, { - required bool isNullValid, -}) { - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } - return replyList.firstOrNull; -} - - -List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { - if (empty) { - return []; - } - if (error == null) { - return [result]; - } - return [error.code, error.message, error.details]; -} -bool _deepEquals(Object? a, Object? b) { - if (identical(a, b)) { - return true; - } - if (a is double && b is double) { - if (a.isNaN && b.isNaN) { - return true; - } - return a == 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) { - if (a.length != b.length) { - return false; - } - for (final MapEntry entryA in a.entries) { - bool found = false; - for (final MapEntry entryB in b.entries) { - if (_deepEquals(entryA.key, entryB.key)) { - if (_deepEquals(entryA.value, entryB.value)) { - found = true; - break; - } else { - return false; - } - } - } - if (!found) { - return false; - } - } - return true; - } - return a == b; -} - -int _deepHash(Object? value) { - if (value is List) { - return Object.hashAll(value.map(_deepHash)); - } - if (value is Map) { - int result = 0; - for (final MapEntry entry in value.entries) { - result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); - } - return result; - } - if (value is double && value.isNaN) { - // Normalize NaN to a consistent hash. - return 0x7FF8000000000000.hashCode; - } - if (value is double && value == 0.0) { - // Normalize -0.0 to 0.0 so they have the same hash code. - return 0.0.hashCode; - } - return value.hashCode; -} - - -enum PeripheralBondState { - bonding, - bonded, - none, -} - -class PeripheralService { - PeripheralService({ - required this.uuid, - required this.primary, - required this.characteristics, - }); - - String uuid; - - bool primary; - - List characteristics; - - List _toList() { - return [ - uuid, - primary, - characteristics, - ]; - } - - Object encode() { - return _toList(); } - - static PeripheralService decode(Object result) { - result as List; - return PeripheralService( - uuid: result[0]! as String, - primary: result[1]! as bool, - characteristics: (result[2]! as List).cast(), - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! PeripheralService || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(uuid, other.uuid) && _deepEquals(primary, other.primary) && _deepEquals(characteristics, other.characteristics); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _deepHash([runtimeType, ..._toList()]); -} - -class PeripheralCharacteristic { - PeripheralCharacteristic({ - required this.uuid, - required this.properties, - required this.permissions, - this.descriptors, - this.value, - }); - - String uuid; - - List properties; - - List permissions; - - List? descriptors; - - Uint8List? value; - - List _toList() { - return [ - uuid, - properties, - permissions, - descriptors, - value, - ]; - } - - Object encode() { - return _toList(); } - - static PeripheralCharacteristic decode(Object result) { - result as List; - return PeripheralCharacteristic( - uuid: result[0]! as String, - properties: (result[1]! as List).cast(), - permissions: (result[2]! as List).cast(), - descriptors: (result[3] as List?)?.cast(), - value: result[4] as Uint8List?, - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! PeripheralCharacteristic || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(permissions, other.permissions) && _deepEquals(descriptors, other.descriptors) && _deepEquals(value, other.value); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _deepHash([runtimeType, ..._toList()]); -} - -class PeripheralDescriptor { - PeripheralDescriptor({ - required this.uuid, - this.value, - this.permissions, - }); - - String uuid; - - Uint8List? value; - - List? permissions; - - List _toList() { - return [ - uuid, - value, - permissions, - ]; - } - - Object encode() { - return _toList(); } - - static PeripheralDescriptor decode(Object result) { - result as List; - return PeripheralDescriptor( - uuid: result[0]! as String, - value: result[1] as Uint8List?, - permissions: (result[2] as List?)?.cast(), - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! PeripheralDescriptor || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(uuid, other.uuid) && _deepEquals(value, other.value) && _deepEquals(permissions, other.permissions); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _deepHash([runtimeType, ..._toList()]); -} - -class PeripheralReadRequestResult { - PeripheralReadRequestResult({ - required this.value, - this.offset, - this.status, - }); - - Uint8List value; - - int? offset; - - int? status; - - List _toList() { - return [ - value, - offset, - status, - ]; - } - - Object encode() { - return _toList(); } - - static PeripheralReadRequestResult decode(Object result) { - result as List; - return PeripheralReadRequestResult( - value: result[0]! as Uint8List, - offset: result[1] as int?, - status: result[2] as int?, - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! PeripheralReadRequestResult || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _deepHash([runtimeType, ..._toList()]); -} - -class PeripheralWriteRequestResult { - PeripheralWriteRequestResult({ - this.value, - this.offset, - this.status, - }); - - Uint8List? value; - - int? offset; - - int? status; - - List _toList() { - return [ - value, - offset, - status, - ]; - } - - Object encode() { - return _toList(); } - - static PeripheralWriteRequestResult decode(Object result) { - result as List; - return PeripheralWriteRequestResult( - value: result[0] as Uint8List?, - offset: result[1] as int?, - status: result[2] as int?, - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! PeripheralWriteRequestResult || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _deepHash([runtimeType, ..._toList()]); -} - -class PeripheralManufacturerData { - PeripheralManufacturerData({ - required this.manufacturerId, - required this.data, - }); - - int manufacturerId; - - Uint8List data; - - List _toList() { - return [ - manufacturerId, - data, - ]; - } - - Object encode() { - return _toList(); } - - static PeripheralManufacturerData decode(Object result) { - result as List; - return PeripheralManufacturerData( - manufacturerId: result[0]! as int, - data: result[1]! as Uint8List, - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! PeripheralManufacturerData || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(manufacturerId, other.manufacturerId) && _deepEquals(data, other.data); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _deepHash([runtimeType, ..._toList()]); -} - - -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is PeripheralBondState) { - buffer.putUint8(129); - writeValue(buffer, value.index); - } else if (value is PeripheralService) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); - } else if (value is PeripheralCharacteristic) { - buffer.putUint8(131); - writeValue(buffer, value.encode()); - } else if (value is PeripheralDescriptor) { - buffer.putUint8(132); - writeValue(buffer, value.encode()); - } else if (value is PeripheralReadRequestResult) { - buffer.putUint8(133); - writeValue(buffer, value.encode()); - } else if (value is PeripheralWriteRequestResult) { - buffer.putUint8(134); - writeValue(buffer, value.encode()); - } else if (value is PeripheralManufacturerData) { - buffer.putUint8(135); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - final value = readValue(buffer) as int?; - return value == null ? null : PeripheralBondState.values[value]; - case 130: - return PeripheralService.decode(readValue(buffer)!); - case 131: - return PeripheralCharacteristic.decode(readValue(buffer)!); - case 132: - return PeripheralDescriptor.decode(readValue(buffer)!); - case 133: - return PeripheralReadRequestResult.decode(readValue(buffer)!); - case 134: - return PeripheralWriteRequestResult.decode(readValue(buffer)!); - case 135: - return PeripheralManufacturerData.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); - } - } -} - -class UniversalBlePeripheralChannel { - /// Constructor for [UniversalBlePeripheralChannel]. 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. - UniversalBlePeripheralChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) - : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - final BinaryMessenger? pigeonVar_binaryMessenger; - - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - final String pigeonVar_messageChannelSuffix; - - Future initialize() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - } - - Future isAdvertising() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - return pigeonVar_replyValue as bool?; - } - - Future isSupported() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; - return pigeonVar_replyValue! as bool; - } - - Future stopAdvertising() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - } - - Future addService(PeripheralService service) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([service]); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - } - - Future removeService(String serviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([serviceId]); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - } - - Future clearServices() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - } - - Future> getServices() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; - return (pigeonVar_replyValue! as List).cast(); - } - - Future startAdvertising(List services, String? localName, int? timeout, PeripheralManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([services, localName, timeout, manufacturerData, addManufacturerDataInScanResponse]); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - } - - Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId, value, deviceId]); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; - } - - /// Returns peripheral-central device ids currently subscribed to [characteristicId] - /// (e.g. HID report characteristic). Used to restore app state after restart. - Future> getSubscribedCentrals(String characteristicId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId]); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; - return (pigeonVar_replyValue! as List).cast(); - } -} - -abstract class UniversalBlePeripheralCallback { - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - PeripheralReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - - PeripheralWriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - - void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); - - void onAdvertisingStatusUpdate(bool advertising, String? error); - - void onServiceAdded(String serviceId, String? error); - - void onMtuChange(String deviceId, int mtu); - - void onConnectionStateChange(String deviceId, bool connected); - - static void setUp(UniversalBlePeripheralCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final String arg_deviceId = args[0]! as String; - final String arg_characteristicId = args[1]! as String; - final int arg_offset = args[2]! as int; - final Uint8List? arg_value = args[3] as Uint8List?; - try { - final PeripheralReadRequestResult? output = api.onReadRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); - return wrapResponse(result: output); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final String arg_deviceId = args[0]! as String; - final String arg_characteristicId = args[1]! as String; - final int arg_offset = args[2]! as int; - final Uint8List? arg_value = args[3] as Uint8List?; - try { - final PeripheralWriteRequestResult? output = api.onWriteRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); - return wrapResponse(result: output); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final String arg_deviceId = args[0]! as String; - final String arg_characteristicId = args[1]! as String; - final bool arg_isSubscribed = args[2]! as bool; - final String? arg_name = args[3] as String?; - try { - api.onCharacteristicSubscriptionChange(arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final bool arg_advertising = args[0]! as bool; - final String? arg_error = args[1] as String?; - try { - api.onAdvertisingStatusUpdate(arg_advertising, arg_error); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final String arg_serviceId = args[0]! as String; - final String? arg_error = args[1] as String?; - try { - api.onServiceAdded(arg_serviceId, arg_error); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final String arg_deviceId = args[0]! as String; - final int arg_mtu = args[1]! as int; - try { - api.onMtuChange(arg_deviceId, arg_mtu); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - { - final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - final List args = message! as List; - final String arg_deviceId = args[0]! as String; - final bool arg_connected = args[1]! as bool; - try { - api.onConnectionStateChange(arg_deviceId, arg_connected); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - } -} diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart index 9b9e6891..231eeb6f 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart @@ -1,4 +1,4 @@ -import 'package:universal_ble/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart' +import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart' as pigeon; import 'package:universal_ble/universal_ble.dart'; diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index afa5bd0b..371b135b 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -1,6 +1,6 @@ import 'dart:async'; import 'package:flutter/services.dart'; -import 'package:universal_ble/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart' +import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart' as pigeon; import 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart'; import 'package:universal_ble/universal_ble.dart'; diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index 5cb37c3e..57a8fa12 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -1,25 +1,41 @@ -// Autogenerated from Pigeon (v26.1.4), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), 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, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'dart:typed_data' show Float64List, Int32List, Int64List; -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; } -List wrapResponse({ - Object? result, - PlatformException? error, - bool empty = false, -}) { +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -30,27 +46,83 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == 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]), - ); + 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 entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } -enum UniversalBleLogLevel { none, error, warning, info, debug, verbose } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + +enum UniversalBleLogLevel { + none, + error, + warning, + info, + debug, + verbose, +} /// Scan config -enum AndroidScanMode { balanced, lowLatency, lowPower, opportunistic } +enum AndroidScanMode { + balanced, + lowLatency, + lowPower, + opportunistic, +} /// Unified error codes for all platforms enum UniversalBleErrorCode { @@ -187,23 +259,36 @@ class UniversalBleScanResult { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(deviceId, other.deviceId) && + _deepEquals(name, other.name) && + _deepEquals(isPaired, other.isPaired) && + _deepEquals(rssi, other.rssi) && + _deepEquals(manufacturerDataList, other.manufacturerDataList) && + _deepEquals(serviceData, other.serviceData) && + _deepEquals(services, other.services) && + _deepEquals(timestamp, other.timestamp); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class UniversalBleService { - UniversalBleService({required this.uuid, this.characteristics}); + UniversalBleService({ + required this.uuid, + this.characteristics, + }); String uuid; List? characteristics; List _toList() { - return [uuid, characteristics]; + return [ + uuid, + characteristics, + ]; } Object encode() { @@ -228,12 +313,13 @@ class UniversalBleService { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(uuid, other.uuid) && + _deepEquals(characteristics, other.characteristics); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class UniversalBleCharacteristic { @@ -250,7 +336,11 @@ class UniversalBleCharacteristic { List descriptors; List _toList() { - return [uuid, properties, descriptors]; + return [ + uuid, + properties, + descriptors, + ]; } Object encode() { @@ -261,9 +351,8 @@ class UniversalBleCharacteristic { result as List; return UniversalBleCharacteristic( uuid: result[0]! as String, - properties: (result[1] as List?)!.cast(), - descriptors: - (result[2] as List?)!.cast(), + properties: (result[1]! as List).cast(), + descriptors: (result[2]! as List).cast(), ); } @@ -277,21 +366,27 @@ class UniversalBleCharacteristic { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(uuid, other.uuid) && + _deepEquals(properties, other.properties) && + _deepEquals(descriptors, other.descriptors); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class UniversalBleDescriptor { - UniversalBleDescriptor({required this.uuid}); + UniversalBleDescriptor({ + required this.uuid, + }); String uuid; List _toList() { - return [uuid]; + return [ + uuid, + ]; } Object encode() { @@ -300,7 +395,9 @@ class UniversalBleDescriptor { static UniversalBleDescriptor decode(Object result) { result as List; - return UniversalBleDescriptor(uuid: result[0]! as String); + return UniversalBleDescriptor( + uuid: result[0]! as String, + ); } @override @@ -312,12 +409,12 @@ class UniversalBleDescriptor { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(uuid, other.uuid); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// Android options to scan devices @@ -340,7 +437,11 @@ class AndroidOptions { int? reportDelayMillis; List _toList() { - return [requestLocationPermission, scanMode, reportDelayMillis]; + return [ + requestLocationPermission, + scanMode, + reportDelayMillis, + ]; } Object encode() { @@ -365,21 +466,28 @@ class AndroidOptions { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals( + requestLocationPermission, other.requestLocationPermission) && + _deepEquals(scanMode, other.scanMode) && + _deepEquals(reportDelayMillis, other.reportDelayMillis); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class UniversalScanConfig { - UniversalScanConfig({this.android}); + UniversalScanConfig({ + this.android, + }); AndroidOptions? android; List _toList() { - return [android]; + return [ + android, + ]; } Object encode() { @@ -388,7 +496,9 @@ class UniversalScanConfig { static UniversalScanConfig decode(Object result) { result as List; - return UniversalScanConfig(android: result[0] as AndroidOptions?); + return UniversalScanConfig( + android: result[0] as AndroidOptions?, + ); } @override @@ -400,12 +510,12 @@ class UniversalScanConfig { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(android, other.android); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// Scan Filters @@ -423,7 +533,11 @@ class UniversalScanFilter { List withManufacturerData; List _toList() { - return [withServices, withNamePrefix, withManufacturerData]; + return [ + withServices, + withNamePrefix, + withManufacturerData, + ]; } Object encode() { @@ -433,10 +547,10 @@ class UniversalScanFilter { static UniversalScanFilter decode(Object result) { result as List; return UniversalScanFilter( - withServices: (result[0] as List?)!.cast(), - withNamePrefix: (result[1] as List?)!.cast(), - withManufacturerData: (result[2] as List?)! - .cast(), + withServices: (result[0]! as List).cast(), + withNamePrefix: (result[1]! as List).cast(), + withManufacturerData: + (result[2]! as List).cast(), ); } @@ -449,12 +563,14 @@ class UniversalScanFilter { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(withServices, other.withServices) && + _deepEquals(withNamePrefix, other.withNamePrefix) && + _deepEquals(withManufacturerData, other.withManufacturerData); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class UniversalManufacturerDataFilter { @@ -471,7 +587,11 @@ class UniversalManufacturerDataFilter { Uint8List? mask; List _toList() { - return [companyIdentifier, data, mask]; + return [ + companyIdentifier, + data, + mask, + ]; } Object encode() { @@ -497,12 +617,14 @@ class UniversalManufacturerDataFilter { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(companyIdentifier, other.companyIdentifier) && + _deepEquals(data, other.data) && + _deepEquals(mask, other.mask); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class UniversalManufacturerData { @@ -516,7 +638,10 @@ class UniversalManufacturerData { Uint8List data; List _toList() { - return [companyIdentifier, data]; + return [ + companyIdentifier, + data, + ]; } Object encode() { @@ -541,225 +666,550 @@ class UniversalManufacturerData { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(companyIdentifier, other.companyIdentifier) && + _deepEquals(data, other.data); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is UniversalBleLogLevel) { - buffer.putUint8(129); - writeValue(buffer, value.index); - } else if (value is AndroidScanMode) { - buffer.putUint8(130); - writeValue(buffer, value.index); - } else if (value is UniversalBleErrorCode) { - buffer.putUint8(131); - writeValue(buffer, value.index); - } else if (value is UniversalBleScanResult) { - buffer.putUint8(132); - writeValue(buffer, value.encode()); - } else if (value is UniversalBleService) { - buffer.putUint8(133); - writeValue(buffer, value.encode()); - } else if (value is UniversalBleCharacteristic) { - buffer.putUint8(134); - writeValue(buffer, value.encode()); - } else if (value is UniversalBleDescriptor) { - buffer.putUint8(135); - writeValue(buffer, value.encode()); - } else if (value is AndroidOptions) { - buffer.putUint8(136); - writeValue(buffer, value.encode()); - } else if (value is UniversalScanConfig) { - buffer.putUint8(137); - writeValue(buffer, value.encode()); - } else if (value is UniversalScanFilter) { - buffer.putUint8(138); - writeValue(buffer, value.encode()); - } else if (value is UniversalManufacturerDataFilter) { - buffer.putUint8(139); - writeValue(buffer, value.encode()); - } else if (value is UniversalManufacturerData) { - buffer.putUint8(140); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } +class PeripheralService { + PeripheralService({ + required this.uuid, + required this.primary, + required this.characteristics, + }); + + String uuid; + + bool primary; + + List characteristics; + + List _toList() { + return [ + uuid, + primary, + characteristics, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralService decode(Object result) { + result as List; + return PeripheralService( + uuid: result[0]! as String, + primary: result[1]! as bool, + characteristics: + (result[2]! as List).cast(), + ); } @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - final value = readValue(buffer) as int?; - return value == null ? null : UniversalBleLogLevel.values[value]; - case 130: - final value = readValue(buffer) as int?; - return value == null ? null : AndroidScanMode.values[value]; - case 131: - final value = readValue(buffer) as int?; - return value == null ? null : UniversalBleErrorCode.values[value]; - case 132: - return UniversalBleScanResult.decode(readValue(buffer)!); - case 133: - return UniversalBleService.decode(readValue(buffer)!); - case 134: - return UniversalBleCharacteristic.decode(readValue(buffer)!); - case 135: - return UniversalBleDescriptor.decode(readValue(buffer)!); - case 136: - return AndroidOptions.decode(readValue(buffer)!); - case 137: - return UniversalScanConfig.decode(readValue(buffer)!); - case 138: - return UniversalScanFilter.decode(readValue(buffer)!); - case 139: - return UniversalManufacturerDataFilter.decode(readValue(buffer)!); - case 140: - return UniversalManufacturerData.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralService || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; } + return _deepEquals(uuid, other.uuid) && + _deepEquals(primary, other.primary) && + _deepEquals(characteristics, other.characteristics); } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); } -/// Flutter -> Native -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 = '', - }) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - final BinaryMessenger? pigeonVar_binaryMessenger; +class PeripheralCharacteristic { + PeripheralCharacteristic({ + required this.uuid, + required this.properties, + required this.permissions, + this.descriptors, + this.value, + }); - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + String uuid; - final String pigeonVar_messageChannelSuffix; + List properties; - Future getBluetoothAvailabilityState() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + List permissions; + + List? descriptors; + + Uint8List? value; + + List _toList() { + return [ + uuid, + properties, + permissions, + descriptors, + value, + ]; } - Future hasPermissions(bool withAndroidFineLocation) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.hasPermissions$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [withAndroidFineLocation], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + Object encode() { + return _toList(); } - Future requestPermissions(bool withAndroidFineLocation) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestPermissions$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [withAndroidFineLocation], + static PeripheralCharacteristic decode(Object result) { + result as List; + return PeripheralCharacteristic( + uuid: result[0]! as String, + properties: (result[1]! as List).cast(), + permissions: (result[2]! as List).cast(), + descriptors: (result[3] as List?)?.cast(), + value: result[4] as Uint8List?, ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } } - Future enableBluetooth() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralCharacteristic || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(uuid, other.uuid) && + _deepEquals(properties, other.properties) && + _deepEquals(permissions, other.permissions) && + _deepEquals(descriptors, other.descriptors) && + _deepEquals(value, other.value); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class PeripheralDescriptor { + PeripheralDescriptor({ + required this.uuid, + this.value, + this.permissions, + }); + + String uuid; + + Uint8List? value; + + List? permissions; + + List _toList() { + return [ + uuid, + value, + permissions, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralDescriptor decode(Object result) { + result as List; + return PeripheralDescriptor( + uuid: result[0]! as String, + value: result[1] as Uint8List?, + permissions: (result[2] as List?)?.cast(), ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralDescriptor || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(uuid, other.uuid) && + _deepEquals(value, other.value) && + _deepEquals(permissions, other.permissions); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class PeripheralReadRequestResult { + PeripheralReadRequestResult({ + required this.value, + this.offset, + this.status, + }); + + Uint8List value; + + int? offset; + + int? status; + + List _toList() { + return [ + value, + offset, + status, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralReadRequestResult decode(Object result) { + result as List; + return PeripheralReadRequestResult( + value: result[0]! as Uint8List, + offset: result[1] as int?, + status: result[2] as int?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralReadRequestResult || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(value, other.value) && + _deepEquals(offset, other.offset) && + _deepEquals(status, other.status); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class PeripheralWriteRequestResult { + PeripheralWriteRequestResult({ + this.value, + this.offset, + this.status, + }); + + Uint8List? value; + + int? offset; + + int? status; + + List _toList() { + return [ + value, + offset, + status, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralWriteRequestResult decode(Object result) { + result as List; + return PeripheralWriteRequestResult( + value: result[0] as Uint8List?, + offset: result[1] as int?, + status: result[2] as int?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralWriteRequestResult || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(value, other.value) && + _deepEquals(offset, other.offset) && + _deepEquals(status, other.status); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class PeripheralManufacturerData { + PeripheralManufacturerData({ + required this.manufacturerId, + required this.data, + }); + + int manufacturerId; + + Uint8List data; + + List _toList() { + return [ + manufacturerId, + data, + ]; + } + + Object encode() { + return _toList(); + } + + static PeripheralManufacturerData decode(Object result) { + result as List; + return PeripheralManufacturerData( + manufacturerId: result[0]! as int, + data: result[1]! as Uint8List, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PeripheralManufacturerData || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(manufacturerId, other.manufacturerId) && + _deepEquals(data, other.data); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is UniversalBleLogLevel) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is AndroidScanMode) { + buffer.putUint8(130); + writeValue(buffer, value.index); + } else if (value is UniversalBleErrorCode) { + buffer.putUint8(131); + writeValue(buffer, value.index); + } else if (value is UniversalBleScanResult) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else if (value is UniversalBleService) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is UniversalBleCharacteristic) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is UniversalBleDescriptor) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is AndroidOptions) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is UniversalScanConfig) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is UniversalScanFilter) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is UniversalManufacturerDataFilter) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is UniversalManufacturerData) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is PeripheralService) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is PeripheralCharacteristic) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is PeripheralDescriptor) { + buffer.putUint8(143); + writeValue(buffer, value.encode()); + } else if (value is PeripheralReadRequestResult) { + buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else if (value is PeripheralWriteRequestResult) { + buffer.putUint8(145); + writeValue(buffer, value.encode()); + } else if (value is PeripheralManufacturerData) { + buffer.putUint8(146); + writeValue(buffer, value.encode()); } else { - return (pigeonVar_replyList[0] as bool?)!; + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final value = readValue(buffer) as int?; + return value == null ? null : UniversalBleLogLevel.values[value]; + case 130: + final value = readValue(buffer) as int?; + return value == null ? null : AndroidScanMode.values[value]; + case 131: + final value = readValue(buffer) as int?; + return value == null ? null : UniversalBleErrorCode.values[value]; + case 132: + return UniversalBleScanResult.decode(readValue(buffer)!); + case 133: + return UniversalBleService.decode(readValue(buffer)!); + case 134: + return UniversalBleCharacteristic.decode(readValue(buffer)!); + case 135: + return UniversalBleDescriptor.decode(readValue(buffer)!); + case 136: + return AndroidOptions.decode(readValue(buffer)!); + case 137: + return UniversalScanConfig.decode(readValue(buffer)!); + case 138: + return UniversalScanFilter.decode(readValue(buffer)!); + case 139: + return UniversalManufacturerDataFilter.decode(readValue(buffer)!); + case 140: + return UniversalManufacturerData.decode(readValue(buffer)!); + case 141: + return PeripheralService.decode(readValue(buffer)!); + case 142: + return PeripheralCharacteristic.decode(readValue(buffer)!); + case 143: + return PeripheralDescriptor.decode(readValue(buffer)!); + case 144: + return PeripheralReadRequestResult.decode(readValue(buffer)!); + case 145: + return PeripheralWriteRequestResult.decode(readValue(buffer)!); + case 146: + return PeripheralManufacturerData.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); } } +} + +/// Flutter -> Native +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 = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future getBluetoothAvailabilityState() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; + } + + Future hasPermissions(bool withAndroidFineLocation) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.hasPermissions$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([withAndroidFineLocation]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; + } + + Future requestPermissions(bool withAndroidFineLocation) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestPermissions$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([withAndroidFineLocation]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future enableBluetooth() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; + } Future disableBluetooth() async { final pigeonVar_channelName = @@ -771,28 +1221,17 @@ class UniversalBlePlatformChannel { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; } Future startScan( - UniversalScanFilter? filter, - UniversalScanConfig? config, - ) async { + UniversalScanFilter? filter, UniversalScanConfig? config) async { final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( @@ -800,141 +1239,326 @@ class UniversalBlePlatformChannel { pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([filter, config]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future stopScan() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future isScanning() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; + } + + Future connect(String deviceId, {bool? autoConnect}) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, autoConnect]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future disconnect(String deviceId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future setNotifiable(String deviceId, String service, + String characteristic, int bleInputProperty) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel + .send([deviceId, service, characteristic, bleInputProperty]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future> discoverServices( + String deviceId, bool withDescriptors) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, withDescriptors]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); + } + + Future readValue( + String deviceId, String service, String characteristic) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, service, characteristic]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as Uint8List; + } + + Future requestMtu(String deviceId, int expectedMtu) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, expectedMtu]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; + } + + Future writeValue(String deviceId, String service, + String characteristic, Uint8List value, int bleOutputProperty) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [filter, config], + [deviceId, service, characteristic, value, bleOutputProperty]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future isPaired(String deviceId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; } - Future stopScan() async { + Future pair(String deviceId) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; } - Future isScanning() async { + Future unPair(String deviceId) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future connect(String deviceId, {bool? autoConnect}) async { + Future> getSystemDevices( + List withServices) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId, autoConnect], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([withServices]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List) + .cast(); } - Future disconnect(String deviceId) async { + Future getConnectionState(String deviceId) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } - Future setNotifiable( - String deviceId, - String service, - String characteristic, - int bleInputProperty, - ) async { + Future readRssi(String deviceId) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId, service, characteristic, bleInputProperty], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; + } + + Future requestConnectionPriority(String deviceId, int priority) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestConnectionPriority$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, priority]); + final pigeonVar_replyList = + await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -948,384 +1572,436 @@ class UniversalBlePlatformChannel { } } - Future> discoverServices( - String deviceId, - bool withDescriptors, - ) async { + Future setLogLevel(UniversalBleLogLevel logLevel) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId, withDescriptors], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([logLevel]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } +} + +/// Native -> Flutter +abstract class UniversalBleCallbackChannel { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + void onAvailabilityChanged(int state); + + void onPairStateChange(String deviceId, bool isPaired, String? error); + + void onScanResult(UniversalBleScanResult result); + + void onValueChanged(String deviceId, String characteristicId, Uint8List value, + int? timestamp); + + void onConnectionChanged(String deviceId, bool connected, String? error); + + static void setUp( + UniversalBleCallbackChannel? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final int arg_state = args[0]! as int; + try { + api.onAvailabilityChanged(arg_state); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final bool arg_isPaired = args[1]! as bool; + final String? arg_error = args[2] as String?; + try { + api.onPairStateChange(arg_deviceId, arg_isPaired, arg_error); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final UniversalBleScanResult arg_result = + args[0]! as UniversalBleScanResult; + try { + api.onScanResult(arg_result); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final Uint8List arg_value = args[2]! as Uint8List; + final int? arg_timestamp = args[3] as int?; + try { + api.onValueChanged( + arg_deviceId, arg_characteristicId, arg_value, arg_timestamp); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final bool arg_connected = args[1]! as bool; + final String? arg_error = args[2] as String?; + try { + api.onConnectionChanged(arg_deviceId, arg_connected, arg_error); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } } } +} - Future readValue( - String deviceId, - String service, - String characteristic, - ) async { +/// Flutter -> Native (peripheral) +class UniversalBlePeripheralChannel { + /// Constructor for [UniversalBlePeripheralChannel]. 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. + UniversalBlePeripheralChannel( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future initialize() async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId, service, characteristic], - ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as Uint8List?)!; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future requestMtu(String deviceId, int expectedMtu) async { + Future isAdvertising() async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId, expectedMtu], - ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as bool?; } - Future writeValue( - String deviceId, - String service, - String characteristic, - Uint8List value, - int bleOutputProperty, - ) async { + Future isSupported() async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId, service, characteristic, value, bleOutputProperty], - ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; } - Future isPaired(String deviceId) async { + Future stopAdvertising() async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId], - ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future pair(String deviceId) async { + Future addService(PeripheralService service) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([service]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future unPair(String deviceId) async { + Future removeService(String serviceId) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([serviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future> getSystemDevices( - List withServices, - ) async { + Future clearServices() async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [withServices], - ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future getConnectionState(String deviceId) async { + Future> getServices() async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId], - ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); } - Future readRssi(String deviceId) async { + Future startAdvertising( + List services, + String? localName, + int? timeout, + PeripheralManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([ + services, + localName, + timeout, + manufacturerData, + addManufacturerDataInScanResponse + ]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future requestConnectionPriority(String deviceId, int priority) async { + Future updateCharacteristic( + String characteristicId, Uint8List value, String? deviceId) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestConnectionPriority$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger); + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId, priority]); - final pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + pigeonVar_channel.send([characteristicId, value, deviceId]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future setLogLevel(UniversalBleLogLevel logLevel) async { + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + Future> getSubscribedCentrals(String characteristicId) async { final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [logLevel], - ); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([characteristicId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); } } -/// Native -> Flutter -abstract class UniversalBleCallbackChannel { +/// Native -> Flutter (peripheral) +abstract class UniversalBlePeripheralCallback { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - void onAvailabilityChanged(int state); + PeripheralReadRequestResult? onReadRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); - void onPairStateChange(String deviceId, bool isPaired, String? error); + PeripheralWriteRequestResult? onWriteRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); - void onScanResult(UniversalBleScanResult result); + void onCharacteristicSubscriptionChange(String deviceId, + String characteristicId, bool isSubscribed, String? name); - void onValueChanged( - String deviceId, - String characteristicId, - Uint8List value, - int? timestamp, - ); + void onAdvertisingStatusUpdate(bool advertising, String? error); - void onConnectionChanged(String deviceId, bool connected, String? error); + void onServiceAdded(String serviceId, String? error); + + void onMtuChange(String deviceId, int mtu); + + void onConnectionStateChange(String deviceId, bool connected); static void setUp( - UniversalBleCallbackChannel? api, { + UniversalBlePeripheralCallback? api, { BinaryMessenger? binaryMessenger, String messageChannelSuffix = '', }) { @@ -1333,194 +2009,177 @@ abstract class UniversalBleCallbackChannel { messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final int arg_offset = args[2]! as int; + final Uint8List? arg_value = args[3] as Uint8List?; + try { + final PeripheralReadRequestResult? output = api.onReadRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final int arg_offset = args[2]! as int; + final Uint8List? arg_value = args[3] as Uint8List?; + try { + final PeripheralWriteRequestResult? output = api.onWriteRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged was null.', - ); - final List args = (message as List?)!; - final int? arg_state = (args[0] as int?); - assert( - arg_state != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged was null, expected non-null int.', - ); + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final bool arg_isSubscribed = args[2]! as bool; + final String? arg_name = args[3] as String?; try { - api.onAvailabilityChanged(arg_state!); + api.onCharacteristicSubscriptionChange( + arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange was null.', - ); - final List args = (message as List?)!; - final String? arg_deviceId = (args[0] as String?); - assert( - arg_deviceId != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange was null, expected non-null String.', - ); - final bool? arg_isPaired = (args[1] as bool?); - assert( - arg_isPaired != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange was null, expected non-null bool.', - ); - final String? arg_error = (args[2] as String?); + final List args = message! as List; + final bool arg_advertising = args[0]! as bool; + final String? arg_error = args[1] as String?; try { - api.onPairStateChange(arg_deviceId!, arg_isPaired!, arg_error); + api.onAdvertisingStatusUpdate(arg_advertising, arg_error); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null.', - ); - final List args = (message as List?)!; - 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.', - ); + final List args = message! as List; + final String arg_serviceId = args[0]! as String; + final String? arg_error = args[1] as String?; try { - api.onScanResult(arg_result!); + api.onServiceAdded(arg_serviceId, arg_error); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null.', - ); - final List args = (message as List?)!; - final String? arg_deviceId = (args[0] as String?); - assert( - arg_deviceId != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null, expected non-null String.', - ); - final String? arg_characteristicId = (args[1] as String?); - assert( - arg_characteristicId != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null, expected non-null String.', - ); - final Uint8List? arg_value = (args[2] as Uint8List?); - assert( - arg_value != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null, expected non-null Uint8List.', - ); - final int? arg_timestamp = (args[3] as int?); + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final int arg_mtu = args[1]! as int; try { - api.onValueChanged( - arg_deviceId!, - arg_characteristicId!, - arg_value!, - arg_timestamp, - ); + api.onMtuChange(arg_deviceId, arg_mtu); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged was null.', - ); - final List args = (message as List?)!; - final String? arg_deviceId = (args[0] as String?); - assert( - arg_deviceId != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged was null, expected non-null String.', - ); - final bool? arg_connected = (args[1] as bool?); - assert( - arg_connected != null, - 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged was null, expected non-null bool.', - ); - final String? arg_error = (args[2] as String?); + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final bool arg_connected = args[1]! as bool; try { - api.onConnectionChanged(arg_deviceId!, arg_connected!, arg_error); + api.onConnectionStateChange(arg_deviceId, arg_connected); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/pigeon/universal_ble.dart b/pigeon/universal_ble.dart index aa92a36b..9cbd3c08 100644 --- a/pigeon/universal_ble.dart +++ b/pigeon/universal_ble.dart @@ -239,6 +239,115 @@ class UniversalManufacturerData { }); } +class PeripheralService { + String uuid; + bool primary; + List characteristics; + PeripheralService(this.uuid, this.primary, this.characteristics); +} + +class PeripheralCharacteristic { + String uuid; + List properties; + List permissions; + List? descriptors; + Uint8List? value; + + PeripheralCharacteristic( + this.uuid, + this.properties, + this.permissions, + this.descriptors, + this.value, + ); +} + +class PeripheralDescriptor { + String uuid; + Uint8List? value; + List? permissions; + PeripheralDescriptor(this.uuid, this.value, this.permissions); +} + +class PeripheralReadRequestResult { + Uint8List value; + int? offset; + int? status; + PeripheralReadRequestResult({required this.value, this.offset, this.status}); +} + +class PeripheralWriteRequestResult { + Uint8List? value; + int? offset; + int? status; + PeripheralWriteRequestResult({this.value, this.offset, this.status}); +} + +class PeripheralManufacturerData { + int manufacturerId; + Uint8List data; + PeripheralManufacturerData( + {required this.manufacturerId, required this.data}); +} + +/// Flutter -> Native (peripheral) +@HostApi() +abstract class UniversalBlePeripheralChannel { + void initialize(); + bool? isAdvertising(); + bool isSupported(); + void stopAdvertising(); + void addService(PeripheralService service); + void removeService(String serviceId); + void clearServices(); + List getServices(); + void startAdvertising( + List services, + String? localName, + int? timeout, + PeripheralManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse, + ); + void updateCharacteristic( + String characteristicId, + Uint8List value, + String? deviceId, + ); + + /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore app state after restart. + List getSubscribedCentrals(String characteristicId); +} + +/// Native -> Flutter (peripheral) +@FlutterApi() +abstract class UniversalBlePeripheralCallback { + PeripheralReadRequestResult? onReadRequest( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + ); + + PeripheralWriteRequestResult? onWriteRequest( + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + ); + + void onCharacteristicSubscriptionChange( + String deviceId, + String characteristicId, + bool isSubscribed, + String? name, + ); + void onAdvertisingStatusUpdate(bool advertising, String? error); + void onServiceAdded(String serviceId, String? error); + void onMtuChange(String deviceId, int mtu); + void onConnectionStateChange(String deviceId, bool connected); +} + /// Unified error codes for all platforms enum UniversalBleErrorCode { // General errors diff --git a/pigeon/universal_ble_peripheral.dart b/pigeon/universal_ble_peripheral.dart deleted file mode 100644 index 1c013baf..00000000 --- a/pigeon/universal_ble_peripheral.dart +++ /dev/null @@ -1,127 +0,0 @@ -import 'package:pigeon/pigeon.dart'; - -// dart run pigeon --input pigeon/universal_ble_peripheral.dart -@ConfigurePigeon( - PigeonOptions( - dartPackageName: 'universal_ble', - dartOut: - 'lib/src/universal_ble_peripheral/generated/universal_ble_peripheral.g.dart', - kotlinOut: - 'android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheral.g.kt', - swiftOut: 'darwin/Classes/UniversalBlePeripheral.g.swift', - kotlinOptions: KotlinOptions(package: 'com.navideck.universal_ble'), - // Same CocoaPod target as UniversalBle.g.swift; omit duplicate PigeonError. - swiftOptions: SwiftOptions(includeErrorClass: false), - cppOptions: CppOptions(namespace: 'universal_ble'), - cppHeaderOut: 'windows/src/generated/universal_ble_peripheral.g.h', - cppSourceOut: 'windows/src/generated/universal_ble_peripheral.g.cpp', - ), -) -enum PeripheralBondState { bonding, bonded, none } - -class PeripheralService { - String uuid; - bool primary; - List characteristics; - PeripheralService(this.uuid, this.primary, this.characteristics); -} - -class PeripheralCharacteristic { - String uuid; - List properties; - List permissions; - List? descriptors; - Uint8List? value; - - PeripheralCharacteristic( - this.uuid, - this.properties, - this.permissions, - this.descriptors, - this.value, - ); -} - -class PeripheralDescriptor { - String uuid; - Uint8List? value; - List? permissions; - PeripheralDescriptor(this.uuid, this.value, this.permissions); -} - -class PeripheralReadRequestResult { - Uint8List value; - int? offset; - int? status; - PeripheralReadRequestResult({required this.value, this.offset, this.status}); -} - -class PeripheralWriteRequestResult { - Uint8List? value; - int? offset; - int? status; - PeripheralWriteRequestResult({this.value, this.offset, this.status}); -} - -class PeripheralManufacturerData { - int manufacturerId; - Uint8List data; - PeripheralManufacturerData( - {required this.manufacturerId, required this.data}); -} - -@HostApi() -abstract class UniversalBlePeripheralChannel { - void initialize(); - bool? isAdvertising(); - bool isSupported(); - void stopAdvertising(); - void addService(PeripheralService service); - void removeService(String serviceId); - void clearServices(); - List getServices(); - void startAdvertising( - List services, - String? localName, - int? timeout, - PeripheralManufacturerData? manufacturerData, - bool addManufacturerDataInScanResponse, - ); - void updateCharacteristic( - String characteristicId, - Uint8List value, - String? deviceId, - ); - - /// Returns peripheral-central device ids currently subscribed to [characteristicId] - /// (e.g. HID report characteristic). Used to restore app state after restart. - List getSubscribedCentrals(String characteristicId); -} - -@FlutterApi() -abstract class UniversalBlePeripheralCallback { - PeripheralReadRequestResult? onReadRequest( - String deviceId, - String characteristicId, - int offset, - Uint8List? value, - ); - - PeripheralWriteRequestResult? onWriteRequest( - String deviceId, - String characteristicId, - int offset, - Uint8List? value, - ); - - void onCharacteristicSubscriptionChange( - String deviceId, - String characteristicId, - bool isSubscribed, - String? name, - ); - void onAdvertisingStatusUpdate(bool advertising, String? error); - void onServiceAdded(String serviceId, String? error); - void onMtuChange(String deviceId, int mtu); - void onConnectionStateChange(String deviceId, bool connected); -} diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 5e8ca131..606812f9 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -41,8 +41,6 @@ list(APPEND PLUGIN_SOURCES "src/ui_thread_handler.hpp" "src/generated/universal_ble.g.cpp" "src/generated/universal_ble.g.h" - "src/generated/universal_ble_peripheral.g.cpp" - "src/generated/universal_ble_peripheral.g.h" "src/pin_entry.h" "src/universal_ble_filter_util.cpp" "src/universal_ble_filter_util.h" diff --git a/windows/src/generated/universal_ble.g.cpp b/windows/src/generated/universal_ble.g.cpp index 90171ad3..10bcd851 100644 --- a/windows/src/generated/universal_ble.g.cpp +++ b/windows/src/generated/universal_ble.g.cpp @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.1.4), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS @@ -10,16 +10,18 @@ #include #include +#include +#include #include #include #include namespace universal_ble { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -28,6 +30,201 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +namespace { +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b); + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b) { + if (a.get() == b.get()) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 1; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result += ((PigeonInternalDeepHash(kv.first) * 31) ^ PigeonInternalDeepHash(kv.second)); + } + return result; +} + +size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + +} // namespace // UniversalBleScanResult UniversalBleScanResult::UniversalBleScanResult(const std::string& device_id) @@ -199,6 +396,31 @@ UniversalBleScanResult UniversalBleScanResult::FromEncodableList(const Encodable return decoded; } +bool UniversalBleScanResult::operator==(const UniversalBleScanResult& other) const { + return PigeonInternalDeepEquals(device_id_, other.device_id_) && PigeonInternalDeepEquals(name_, other.name_) && PigeonInternalDeepEquals(is_paired_, other.is_paired_) && PigeonInternalDeepEquals(rssi_, other.rssi_) && PigeonInternalDeepEquals(manufacturer_data_list_, other.manufacturer_data_list_) && PigeonInternalDeepEquals(service_data_, other.service_data_) && PigeonInternalDeepEquals(services_, other.services_) && PigeonInternalDeepEquals(timestamp_, other.timestamp_); +} + +bool UniversalBleScanResult::operator!=(const UniversalBleScanResult& other) const { + return !(*this == other); +} + +size_t UniversalBleScanResult::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(device_id_); + result = result * 31 + PigeonInternalDeepHash(name_); + result = result * 31 + PigeonInternalDeepHash(is_paired_); + result = result * 31 + PigeonInternalDeepHash(rssi_); + result = result * 31 + PigeonInternalDeepHash(manufacturer_data_list_); + result = result * 31 + PigeonInternalDeepHash(service_data_); + result = result * 31 + PigeonInternalDeepHash(services_); + result = result * 31 + PigeonInternalDeepHash(timestamp_); + return result; +} + +size_t PigeonInternalDeepHash(const UniversalBleScanResult& v) { + return v.Hash(); +} + // UniversalBleService UniversalBleService::UniversalBleService(const std::string& uuid) @@ -250,6 +472,25 @@ UniversalBleService UniversalBleService::FromEncodableList(const EncodableList& return decoded; } +bool UniversalBleService::operator==(const UniversalBleService& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(characteristics_, other.characteristics_); +} + +bool UniversalBleService::operator!=(const UniversalBleService& other) const { + return !(*this == other); +} + +size_t UniversalBleService::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(characteristics_); + return result; +} + +size_t PigeonInternalDeepHash(const UniversalBleService& v) { + return v.Hash(); +} + // UniversalBleCharacteristic UniversalBleCharacteristic::UniversalBleCharacteristic( @@ -304,6 +545,26 @@ UniversalBleCharacteristic UniversalBleCharacteristic::FromEncodableList(const E return decoded; } +bool UniversalBleCharacteristic::operator==(const UniversalBleCharacteristic& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(properties_, other.properties_) && PigeonInternalDeepEquals(descriptors_, other.descriptors_); +} + +bool UniversalBleCharacteristic::operator!=(const UniversalBleCharacteristic& other) const { + return !(*this == other); +} + +size_t UniversalBleCharacteristic::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(properties_); + result = result * 31 + PigeonInternalDeepHash(descriptors_); + return result; +} + +size_t PigeonInternalDeepHash(const UniversalBleCharacteristic& v) { + return v.Hash(); +} + // UniversalBleDescriptor UniversalBleDescriptor::UniversalBleDescriptor(const std::string& uuid) @@ -331,6 +592,24 @@ UniversalBleDescriptor UniversalBleDescriptor::FromEncodableList(const Encodable return decoded; } +bool UniversalBleDescriptor::operator==(const UniversalBleDescriptor& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_); +} + +bool UniversalBleDescriptor::operator!=(const UniversalBleDescriptor& other) const { + return !(*this == other); +} + +size_t UniversalBleDescriptor::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + return result; +} + +size_t PigeonInternalDeepHash(const UniversalBleDescriptor& v) { + return v.Hash(); +} + // AndroidOptions AndroidOptions::AndroidOptions() {} @@ -408,6 +687,26 @@ AndroidOptions AndroidOptions::FromEncodableList(const EncodableList& list) { return decoded; } +bool AndroidOptions::operator==(const AndroidOptions& other) const { + return PigeonInternalDeepEquals(request_location_permission_, other.request_location_permission_) && PigeonInternalDeepEquals(scan_mode_, other.scan_mode_) && PigeonInternalDeepEquals(report_delay_millis_, other.report_delay_millis_); +} + +bool AndroidOptions::operator!=(const AndroidOptions& other) const { + return !(*this == other); +} + +size_t AndroidOptions::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(request_location_permission_); + result = result * 31 + PigeonInternalDeepHash(scan_mode_); + result = result * 31 + PigeonInternalDeepHash(report_delay_millis_); + return result; +} + +size_t PigeonInternalDeepHash(const AndroidOptions& v) { + return v.Hash(); +} + // UniversalScanConfig UniversalScanConfig::UniversalScanConfig() {} @@ -452,6 +751,24 @@ UniversalScanConfig UniversalScanConfig::FromEncodableList(const EncodableList& return decoded; } +bool UniversalScanConfig::operator==(const UniversalScanConfig& other) const { + return PigeonInternalDeepEquals(android_, other.android_); +} + +bool UniversalScanConfig::operator!=(const UniversalScanConfig& other) const { + return !(*this == other); +} + +size_t UniversalScanConfig::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(android_); + return result; +} + +size_t PigeonInternalDeepHash(const UniversalScanConfig& v) { + return v.Hash(); +} + // UniversalScanFilter UniversalScanFilter::UniversalScanFilter( @@ -506,6 +823,26 @@ UniversalScanFilter UniversalScanFilter::FromEncodableList(const EncodableList& return decoded; } +bool UniversalScanFilter::operator==(const UniversalScanFilter& other) const { + return PigeonInternalDeepEquals(with_services_, other.with_services_) && PigeonInternalDeepEquals(with_name_prefix_, other.with_name_prefix_) && PigeonInternalDeepEquals(with_manufacturer_data_, other.with_manufacturer_data_); +} + +bool UniversalScanFilter::operator!=(const UniversalScanFilter& other) const { + return !(*this == other); +} + +size_t UniversalScanFilter::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(with_services_); + result = result * 31 + PigeonInternalDeepHash(with_name_prefix_); + result = result * 31 + PigeonInternalDeepHash(with_manufacturer_data_); + return result; +} + +size_t PigeonInternalDeepHash(const UniversalScanFilter& v) { + return v.Hash(); +} + // UniversalManufacturerDataFilter UniversalManufacturerDataFilter::UniversalManufacturerDataFilter(int64_t company_identifier) @@ -577,6 +914,26 @@ UniversalManufacturerDataFilter UniversalManufacturerDataFilter::FromEncodableLi return decoded; } +bool UniversalManufacturerDataFilter::operator==(const UniversalManufacturerDataFilter& other) const { + return PigeonInternalDeepEquals(company_identifier_, other.company_identifier_) && PigeonInternalDeepEquals(data_, other.data_) && PigeonInternalDeepEquals(mask_, other.mask_); +} + +bool UniversalManufacturerDataFilter::operator!=(const UniversalManufacturerDataFilter& other) const { + return !(*this == other); +} + +size_t UniversalManufacturerDataFilter::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(company_identifier_); + result = result * 31 + PigeonInternalDeepHash(data_); + result = result * 31 + PigeonInternalDeepHash(mask_); + return result; +} + +size_t PigeonInternalDeepHash(const UniversalManufacturerDataFilter& v) { + return v.Hash(); +} + // UniversalManufacturerData UniversalManufacturerData::UniversalManufacturerData( @@ -618,151 +975,755 @@ UniversalManufacturerData UniversalManufacturerData::FromEncodableList(const Enc return decoded; } +bool UniversalManufacturerData::operator==(const UniversalManufacturerData& other) const { + return PigeonInternalDeepEquals(company_identifier_, other.company_identifier_) && PigeonInternalDeepEquals(data_, other.data_); +} -PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} +bool UniversalManufacturerData::operator!=(const UniversalManufacturerData& other) const { + return !(*this == other); +} -EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, - flutter::ByteStreamReader* stream) const { - switch (type) { - case 129: { - 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(enum_arg_value)); - } - case 130: { - 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(enum_arg_value)); - } - case 131: { - 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(enum_arg_value)); - } - case 132: { - return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get(ReadValue(stream)))); - } - case 133: { - return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get(ReadValue(stream)))); - } - case 134: { - return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); - } - case 135: { - return CustomEncodableValue(UniversalBleDescriptor::FromEncodableList(std::get(ReadValue(stream)))); - } - case 136: { - return CustomEncodableValue(AndroidOptions::FromEncodableList(std::get(ReadValue(stream)))); - } - case 137: { - return CustomEncodableValue(UniversalScanConfig::FromEncodableList(std::get(ReadValue(stream)))); - } - case 138: { - return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get(ReadValue(stream)))); - } - case 139: { - return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get(ReadValue(stream)))); - } - case 140: { - return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); - } - default: - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); - } +size_t UniversalManufacturerData::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(company_identifier_); + result = result * 31 + PigeonInternalDeepHash(data_); + return result; } -void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, - flutter::ByteStreamWriter* stream) const { - if (const CustomEncodableValue* custom_value = std::get_if(&value)) { - if (custom_value->type() == typeid(UniversalBleLogLevel)) { - stream->WriteByte(129); - WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); - return; - } - if (custom_value->type() == typeid(AndroidScanMode)) { - stream->WriteByte(130); - WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); - return; - } - if (custom_value->type() == typeid(UniversalBleErrorCode)) { - stream->WriteByte(131); - WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); - return; - } - if (custom_value->type() == typeid(UniversalBleScanResult)) { - stream->WriteByte(132); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(UniversalBleService)) { - stream->WriteByte(133); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(UniversalBleCharacteristic)) { - stream->WriteByte(134); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(UniversalBleDescriptor)) { - stream->WriteByte(135); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(AndroidOptions)) { - stream->WriteByte(136); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(UniversalScanConfig)) { - stream->WriteByte(137); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(UniversalScanFilter)) { - stream->WriteByte(138); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(UniversalManufacturerDataFilter)) { - stream->WriteByte(139); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(UniversalManufacturerData)) { - stream->WriteByte(140); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - } - flutter::StandardCodecSerializer::WriteValue(value, stream); +size_t PigeonInternalDeepHash(const UniversalManufacturerData& v) { + return v.Hash(); } -/// The codec used by UniversalBlePlatformChannel. -const flutter::StandardMessageCodec& UniversalBlePlatformChannel::GetCodec() { - return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +// PeripheralService + +PeripheralService::PeripheralService( + const std::string& uuid, + bool primary, + const EncodableList& characteristics) + : uuid_(uuid), + primary_(primary), + characteristics_(characteristics) {} + +const std::string& PeripheralService::uuid() const { + return uuid_; } -// Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binary_messenger`. -void UniversalBlePlatformChannel::SetUp( - flutter::BinaryMessenger* binary_messenger, - UniversalBlePlatformChannel* api) { - UniversalBlePlatformChannel::SetUp(binary_messenger, api, ""); +void PeripheralService::set_uuid(std::string_view value_arg) { + uuid_ = value_arg; } -void UniversalBlePlatformChannel::SetUp( - flutter::BinaryMessenger* binary_messenger, - UniversalBlePlatformChannel* api, - const std::string& message_channel_suffix) { - const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { - try { - api->GetBluetoothAvailabilityState([reply](ErrorOr&& output) { + +bool PeripheralService::primary() const { + return primary_; +} + +void PeripheralService::set_primary(bool value_arg) { + primary_ = value_arg; +} + + +const EncodableList& PeripheralService::characteristics() const { + return characteristics_; +} + +void PeripheralService::set_characteristics(const EncodableList& value_arg) { + characteristics_ = value_arg; +} + + +EncodableList PeripheralService::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(EncodableValue(uuid_)); + list.push_back(EncodableValue(primary_)); + list.push_back(EncodableValue(characteristics_)); + return list; +} + +PeripheralService PeripheralService::FromEncodableList(const EncodableList& list) { + PeripheralService decoded( + std::get(list[0]), + std::get(list[1]), + std::get(list[2])); + return decoded; +} + +bool PeripheralService::operator==(const PeripheralService& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(primary_, other.primary_) && PigeonInternalDeepEquals(characteristics_, other.characteristics_); +} + +bool PeripheralService::operator!=(const PeripheralService& other) const { + return !(*this == other); +} + +size_t PeripheralService::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(primary_); + result = result * 31 + PigeonInternalDeepHash(characteristics_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralService& v) { + return v.Hash(); +} + +// PeripheralCharacteristic + +PeripheralCharacteristic::PeripheralCharacteristic( + const std::string& uuid, + const EncodableList& properties, + const EncodableList& permissions) + : uuid_(uuid), + properties_(properties), + permissions_(permissions) {} + +PeripheralCharacteristic::PeripheralCharacteristic( + const std::string& uuid, + const EncodableList& properties, + const EncodableList& permissions, + const EncodableList* descriptors, + const std::vector* value) + : uuid_(uuid), + properties_(properties), + permissions_(permissions), + descriptors_(descriptors ? std::optional(*descriptors) : std::nullopt), + value_(value ? std::optional>(*value) : std::nullopt) {} + +const std::string& PeripheralCharacteristic::uuid() const { + return uuid_; +} + +void PeripheralCharacteristic::set_uuid(std::string_view value_arg) { + uuid_ = value_arg; +} + + +const EncodableList& PeripheralCharacteristic::properties() const { + return properties_; +} + +void PeripheralCharacteristic::set_properties(const EncodableList& value_arg) { + properties_ = value_arg; +} + + +const EncodableList& PeripheralCharacteristic::permissions() const { + return permissions_; +} + +void PeripheralCharacteristic::set_permissions(const EncodableList& value_arg) { + permissions_ = value_arg; +} + + +const EncodableList* PeripheralCharacteristic::descriptors() const { + return descriptors_ ? &(*descriptors_) : nullptr; +} + +void PeripheralCharacteristic::set_descriptors(const EncodableList* value_arg) { + descriptors_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralCharacteristic::set_descriptors(const EncodableList& value_arg) { + descriptors_ = value_arg; +} + + +const std::vector* PeripheralCharacteristic::value() const { + return value_ ? &(*value_) : nullptr; +} + +void PeripheralCharacteristic::set_value(const std::vector* value_arg) { + value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; +} + +void PeripheralCharacteristic::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +EncodableList PeripheralCharacteristic::ToEncodableList() const { + EncodableList list; + list.reserve(5); + list.push_back(EncodableValue(uuid_)); + list.push_back(EncodableValue(properties_)); + list.push_back(EncodableValue(permissions_)); + list.push_back(descriptors_ ? EncodableValue(*descriptors_) : EncodableValue()); + list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + return list; +} + +PeripheralCharacteristic PeripheralCharacteristic::FromEncodableList(const EncodableList& list) { + PeripheralCharacteristic decoded( + std::get(list[0]), + std::get(list[1]), + std::get(list[2])); + auto& encodable_descriptors = list[3]; + if (!encodable_descriptors.IsNull()) { + decoded.set_descriptors(std::get(encodable_descriptors)); + } + auto& encodable_value = list[4]; + if (!encodable_value.IsNull()) { + decoded.set_value(std::get>(encodable_value)); + } + return decoded; +} + +bool PeripheralCharacteristic::operator==(const PeripheralCharacteristic& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(properties_, other.properties_) && PigeonInternalDeepEquals(permissions_, other.permissions_) && PigeonInternalDeepEquals(descriptors_, other.descriptors_) && PigeonInternalDeepEquals(value_, other.value_); +} + +bool PeripheralCharacteristic::operator!=(const PeripheralCharacteristic& other) const { + return !(*this == other); +} + +size_t PeripheralCharacteristic::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(properties_); + result = result * 31 + PigeonInternalDeepHash(permissions_); + result = result * 31 + PigeonInternalDeepHash(descriptors_); + result = result * 31 + PigeonInternalDeepHash(value_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralCharacteristic& v) { + return v.Hash(); +} + +// PeripheralDescriptor + +PeripheralDescriptor::PeripheralDescriptor(const std::string& uuid) + : uuid_(uuid) {} + +PeripheralDescriptor::PeripheralDescriptor( + const std::string& uuid, + const std::vector* value, + const EncodableList* permissions) + : uuid_(uuid), + value_(value ? std::optional>(*value) : std::nullopt), + permissions_(permissions ? std::optional(*permissions) : std::nullopt) {} + +const std::string& PeripheralDescriptor::uuid() const { + return uuid_; +} + +void PeripheralDescriptor::set_uuid(std::string_view value_arg) { + uuid_ = value_arg; +} + + +const std::vector* PeripheralDescriptor::value() const { + return value_ ? &(*value_) : nullptr; +} + +void PeripheralDescriptor::set_value(const std::vector* value_arg) { + value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; +} + +void PeripheralDescriptor::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +const EncodableList* PeripheralDescriptor::permissions() const { + return permissions_ ? &(*permissions_) : nullptr; +} + +void PeripheralDescriptor::set_permissions(const EncodableList* value_arg) { + permissions_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralDescriptor::set_permissions(const EncodableList& value_arg) { + permissions_ = value_arg; +} + + +EncodableList PeripheralDescriptor::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(EncodableValue(uuid_)); + list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + list.push_back(permissions_ ? EncodableValue(*permissions_) : EncodableValue()); + return list; +} + +PeripheralDescriptor PeripheralDescriptor::FromEncodableList(const EncodableList& list) { + PeripheralDescriptor decoded( + std::get(list[0])); + auto& encodable_value = list[1]; + if (!encodable_value.IsNull()) { + decoded.set_value(std::get>(encodable_value)); + } + auto& encodable_permissions = list[2]; + if (!encodable_permissions.IsNull()) { + decoded.set_permissions(std::get(encodable_permissions)); + } + return decoded; +} + +bool PeripheralDescriptor::operator==(const PeripheralDescriptor& other) const { + return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(permissions_, other.permissions_); +} + +bool PeripheralDescriptor::operator!=(const PeripheralDescriptor& other) const { + return !(*this == other); +} + +size_t PeripheralDescriptor::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(uuid_); + result = result * 31 + PigeonInternalDeepHash(value_); + result = result * 31 + PigeonInternalDeepHash(permissions_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralDescriptor& v) { + return v.Hash(); +} + +// PeripheralReadRequestResult + +PeripheralReadRequestResult::PeripheralReadRequestResult(const std::vector& value) + : value_(value) {} + +PeripheralReadRequestResult::PeripheralReadRequestResult( + const std::vector& value, + const int64_t* offset, + const int64_t* status) + : value_(value), + offset_(offset ? std::optional(*offset) : std::nullopt), + status_(status ? std::optional(*status) : std::nullopt) {} + +const std::vector& PeripheralReadRequestResult::value() const { + return value_; +} + +void PeripheralReadRequestResult::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +const int64_t* PeripheralReadRequestResult::offset() const { + return offset_ ? &(*offset_) : nullptr; +} + +void PeripheralReadRequestResult::set_offset(const int64_t* value_arg) { + offset_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralReadRequestResult::set_offset(int64_t value_arg) { + offset_ = value_arg; +} + + +const int64_t* PeripheralReadRequestResult::status() const { + return status_ ? &(*status_) : nullptr; +} + +void PeripheralReadRequestResult::set_status(const int64_t* value_arg) { + status_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralReadRequestResult::set_status(int64_t value_arg) { + status_ = value_arg; +} + + +EncodableList PeripheralReadRequestResult::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(EncodableValue(value_)); + list.push_back(offset_ ? EncodableValue(*offset_) : EncodableValue()); + list.push_back(status_ ? EncodableValue(*status_) : EncodableValue()); + return list; +} + +PeripheralReadRequestResult PeripheralReadRequestResult::FromEncodableList(const EncodableList& list) { + PeripheralReadRequestResult decoded( + std::get>(list[0])); + auto& encodable_offset = list[1]; + if (!encodable_offset.IsNull()) { + decoded.set_offset(std::get(encodable_offset)); + } + auto& encodable_status = list[2]; + if (!encodable_status.IsNull()) { + decoded.set_status(std::get(encodable_status)); + } + return decoded; +} + +bool PeripheralReadRequestResult::operator==(const PeripheralReadRequestResult& other) const { + return PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(offset_, other.offset_) && PigeonInternalDeepEquals(status_, other.status_); +} + +bool PeripheralReadRequestResult::operator!=(const PeripheralReadRequestResult& other) const { + return !(*this == other); +} + +size_t PeripheralReadRequestResult::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(value_); + result = result * 31 + PigeonInternalDeepHash(offset_); + result = result * 31 + PigeonInternalDeepHash(status_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralReadRequestResult& v) { + return v.Hash(); +} + +// PeripheralWriteRequestResult + +PeripheralWriteRequestResult::PeripheralWriteRequestResult() {} + +PeripheralWriteRequestResult::PeripheralWriteRequestResult( + const std::vector* value, + const int64_t* offset, + const int64_t* status) + : value_(value ? std::optional>(*value) : std::nullopt), + offset_(offset ? std::optional(*offset) : std::nullopt), + status_(status ? std::optional(*status) : std::nullopt) {} + +const std::vector* PeripheralWriteRequestResult::value() const { + return value_ ? &(*value_) : nullptr; +} + +void PeripheralWriteRequestResult::set_value(const std::vector* value_arg) { + value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; +} + +void PeripheralWriteRequestResult::set_value(const std::vector& value_arg) { + value_ = value_arg; +} + + +const int64_t* PeripheralWriteRequestResult::offset() const { + return offset_ ? &(*offset_) : nullptr; +} + +void PeripheralWriteRequestResult::set_offset(const int64_t* value_arg) { + offset_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralWriteRequestResult::set_offset(int64_t value_arg) { + offset_ = value_arg; +} + + +const int64_t* PeripheralWriteRequestResult::status() const { + return status_ ? &(*status_) : nullptr; +} + +void PeripheralWriteRequestResult::set_status(const int64_t* value_arg) { + status_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void PeripheralWriteRequestResult::set_status(int64_t value_arg) { + status_ = value_arg; +} + + +EncodableList PeripheralWriteRequestResult::ToEncodableList() const { + EncodableList list; + list.reserve(3); + list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + list.push_back(offset_ ? EncodableValue(*offset_) : EncodableValue()); + list.push_back(status_ ? EncodableValue(*status_) : EncodableValue()); + return list; +} + +PeripheralWriteRequestResult PeripheralWriteRequestResult::FromEncodableList(const EncodableList& list) { + PeripheralWriteRequestResult decoded; + auto& encodable_value = list[0]; + if (!encodable_value.IsNull()) { + decoded.set_value(std::get>(encodable_value)); + } + auto& encodable_offset = list[1]; + if (!encodable_offset.IsNull()) { + decoded.set_offset(std::get(encodable_offset)); + } + auto& encodable_status = list[2]; + if (!encodable_status.IsNull()) { + decoded.set_status(std::get(encodable_status)); + } + return decoded; +} + +bool PeripheralWriteRequestResult::operator==(const PeripheralWriteRequestResult& other) const { + return PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(offset_, other.offset_) && PigeonInternalDeepEquals(status_, other.status_); +} + +bool PeripheralWriteRequestResult::operator!=(const PeripheralWriteRequestResult& other) const { + return !(*this == other); +} + +size_t PeripheralWriteRequestResult::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(value_); + result = result * 31 + PigeonInternalDeepHash(offset_); + result = result * 31 + PigeonInternalDeepHash(status_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralWriteRequestResult& v) { + return v.Hash(); +} + +// PeripheralManufacturerData + +PeripheralManufacturerData::PeripheralManufacturerData( + int64_t manufacturer_id, + const std::vector& data) + : manufacturer_id_(manufacturer_id), + data_(data) {} + +int64_t PeripheralManufacturerData::manufacturer_id() const { + return manufacturer_id_; +} + +void PeripheralManufacturerData::set_manufacturer_id(int64_t value_arg) { + manufacturer_id_ = value_arg; +} + + +const std::vector& PeripheralManufacturerData::data() const { + return data_; +} + +void PeripheralManufacturerData::set_data(const std::vector& value_arg) { + data_ = value_arg; +} + + +EncodableList PeripheralManufacturerData::ToEncodableList() const { + EncodableList list; + list.reserve(2); + list.push_back(EncodableValue(manufacturer_id_)); + list.push_back(EncodableValue(data_)); + return list; +} + +PeripheralManufacturerData PeripheralManufacturerData::FromEncodableList(const EncodableList& list) { + PeripheralManufacturerData decoded( + std::get(list[0]), + std::get>(list[1])); + return decoded; +} + +bool PeripheralManufacturerData::operator==(const PeripheralManufacturerData& other) const { + return PigeonInternalDeepEquals(manufacturer_id_, other.manufacturer_id_) && PigeonInternalDeepEquals(data_, other.data_); +} + +bool PeripheralManufacturerData::operator!=(const PeripheralManufacturerData& other) const { + return !(*this == other); +} + +size_t PeripheralManufacturerData::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(manufacturer_id_); + result = result * 31 + PigeonInternalDeepHash(data_); + return result; +} + +size_t PigeonInternalDeepHash(const PeripheralManufacturerData& v) { + return v.Hash(); +} + + +PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} + +EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( + uint8_t type, + ::flutter::ByteStreamReader* stream) const { + switch (type) { + case 129: { + 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(enum_arg_value)); + } + case 130: { + 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(enum_arg_value)); + } + case 131: { + 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(enum_arg_value)); + } + case 132: { + return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get(ReadValue(stream)))); + } + case 133: { + return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get(ReadValue(stream)))); + } + case 134: { + return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); + } + case 135: { + return CustomEncodableValue(UniversalBleDescriptor::FromEncodableList(std::get(ReadValue(stream)))); + } + case 136: { + return CustomEncodableValue(AndroidOptions::FromEncodableList(std::get(ReadValue(stream)))); + } + case 137: { + return CustomEncodableValue(UniversalScanConfig::FromEncodableList(std::get(ReadValue(stream)))); + } + case 138: { + return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get(ReadValue(stream)))); + } + case 139: { + return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get(ReadValue(stream)))); + } + case 140: { + return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); + } + case 141: { + return CustomEncodableValue(PeripheralService::FromEncodableList(std::get(ReadValue(stream)))); + } + case 142: { + return CustomEncodableValue(PeripheralCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); + } + case 143: { + return CustomEncodableValue(PeripheralDescriptor::FromEncodableList(std::get(ReadValue(stream)))); + } + case 144: { + return CustomEncodableValue(PeripheralReadRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + } + case 145: { + return CustomEncodableValue(PeripheralWriteRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + } + case 146: { + return CustomEncodableValue(PeripheralManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); + } + default: + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + } +} + +void PigeonInternalCodecSerializer::WriteValue( + const EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const { + if (const CustomEncodableValue* custom_value = std::get_if(&value)) { + if (custom_value->type() == typeid(UniversalBleLogLevel)) { + stream->WriteByte(129); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(AndroidScanMode)) { + stream->WriteByte(130); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(UniversalBleErrorCode)) { + stream->WriteByte(131); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(UniversalBleScanResult)) { + stream->WriteByte(132); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(UniversalBleService)) { + stream->WriteByte(133); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(UniversalBleCharacteristic)) { + stream->WriteByte(134); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(UniversalBleDescriptor)) { + stream->WriteByte(135); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(AndroidOptions)) { + stream->WriteByte(136); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(UniversalScanConfig)) { + stream->WriteByte(137); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(UniversalScanFilter)) { + stream->WriteByte(138); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(UniversalManufacturerDataFilter)) { + stream->WriteByte(139); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(UniversalManufacturerData)) { + stream->WriteByte(140); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralService)) { + stream->WriteByte(141); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralCharacteristic)) { + stream->WriteByte(142); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralDescriptor)) { + stream->WriteByte(143); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralReadRequestResult)) { + stream->WriteByte(144); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralWriteRequestResult)) { + stream->WriteByte(145); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + if (custom_value->type() == typeid(PeripheralManufacturerData)) { + stream->WriteByte(146); + WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); + return; + } + } + ::flutter::StandardCodecSerializer::WriteValue(value, stream); +} + +/// The codec used by UniversalBlePlatformChannel. +const ::flutter::StandardMessageCodec& UniversalBlePlatformChannel::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +} + +// Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binary_messenger`. +void UniversalBlePlatformChannel::SetUp( + ::flutter::BinaryMessenger* binary_messenger, + UniversalBlePlatformChannel* api) { + UniversalBlePlatformChannel::SetUp(binary_messenger, api, ""); +} + +void UniversalBlePlatformChannel::SetUp( + ::flutter::BinaryMessenger* binary_messenger, + UniversalBlePlatformChannel* api, + const std::string& message_channel_suffix) { + const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + api->GetBluetoothAvailabilityState([reply](ErrorOr&& output) { if (output.has_error()) { reply(WrapError(output.error())); return; @@ -782,7 +1743,7 @@ void UniversalBlePlatformChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.hasPermissions" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_with_android_fine_location_arg = args.at(0); @@ -810,7 +1771,7 @@ void UniversalBlePlatformChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestPermissions" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_with_android_fine_location_arg = args.at(0); @@ -818,8 +1779,225 @@ void UniversalBlePlatformChannel::SetUp( reply(WrapError("with_android_fine_location_arg unexpectedly null.")); return; } - const auto& with_android_fine_location_arg = std::get(encodable_with_android_fine_location_arg); - api->RequestPermissions(with_android_fine_location_arg, [reply](std::optional&& output) { + const auto& with_android_fine_location_arg = std::get(encodable_with_android_fine_location_arg); + api->RequestPermissions(with_android_fine_location_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + api->EnableBluetooth([reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + api->DisableBluetooth([reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_filter_arg = args.at(0); + const auto* filter_arg = encodable_filter_arg.IsNull() ? nullptr : &(std::any_cast(std::get(encodable_filter_arg))); + const auto& encodable_config_arg = args.at(1); + const auto* config_arg = encodable_config_arg.IsNull() ? nullptr : &(std::any_cast(std::get(encodable_config_arg))); + std::optional output = api->StartScan(filter_arg, config_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + std::optional output = api->StopScan(); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + ErrorOr output = api->IsScanning(); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); + return; + } + const auto& device_id_arg = std::get(encodable_device_id_arg); + const auto& encodable_auto_connect_arg = args.at(1); + const auto* auto_connect_arg = std::get_if(&encodable_auto_connect_arg); + std::optional output = api->Connect(device_id_arg, auto_connect_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); + return; + } + const auto& device_id_arg = std::get(encodable_device_id_arg); + std::optional output = api->Disconnect(device_id_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); + return; + } + const auto& device_id_arg = std::get(encodable_device_id_arg); + const auto& encodable_service_arg = args.at(1); + if (encodable_service_arg.IsNull()) { + reply(WrapError("service_arg unexpectedly null.")); + return; + } + const auto& service_arg = std::get(encodable_service_arg); + const auto& encodable_characteristic_arg = args.at(2); + if (encodable_characteristic_arg.IsNull()) { + reply(WrapError("characteristic_arg unexpectedly null.")); + return; + } + const auto& characteristic_arg = std::get(encodable_characteristic_arg); + const auto& encodable_ble_input_property_arg = args.at(3); + if (encodable_ble_input_property_arg.IsNull()) { + reply(WrapError("ble_input_property_arg unexpectedly null.")); + return; + } + const int64_t ble_input_property_arg = encodable_ble_input_property_arg.LongValue(); + api->SetNotifiable(device_id_arg, service_arg, characteristic_arg, ble_input_property_arg, [reply](std::optional&& output) { if (output.has_value()) { reply(WrapError(output.value())); return; @@ -837,11 +2015,24 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - api->EnableBluetooth([reply](ErrorOr&& output) { + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); + return; + } + const auto& device_id_arg = std::get(encodable_device_id_arg); + const auto& encodable_with_descriptors_arg = args.at(1); + if (encodable_with_descriptors_arg.IsNull()) { + reply(WrapError("with_descriptors_arg unexpectedly null.")); + return; + } + const auto& with_descriptors_arg = std::get(encodable_with_descriptors_arg); + api->DiscoverServices(device_id_arg, with_descriptors_arg, [reply](ErrorOr&& output) { if (output.has_error()) { reply(WrapError(output.error())); return; @@ -859,11 +2050,30 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - api->DisableBluetooth([reply](ErrorOr&& output) { + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); + return; + } + const auto& device_id_arg = std::get(encodable_device_id_arg); + const auto& encodable_service_arg = args.at(1); + if (encodable_service_arg.IsNull()) { + reply(WrapError("service_arg unexpectedly null.")); + return; + } + const auto& service_arg = std::get(encodable_service_arg); + const auto& encodable_characteristic_arg = args.at(2); + if (encodable_characteristic_arg.IsNull()) { + reply(WrapError("characteristic_arg unexpectedly null.")); + return; + } + const auto& characteristic_arg = std::get(encodable_characteristic_arg); + api->ReadValue(device_id_arg, service_arg, characteristic_arg, [reply](ErrorOr>&& output) { if (output.has_error()) { reply(WrapError(output.error())); return; @@ -881,23 +2091,32 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_filter_arg = args.at(0); - const auto* filter_arg = encodable_filter_arg.IsNull() ? nullptr : &(std::any_cast(std::get(encodable_filter_arg))); - const auto& encodable_config_arg = args.at(1); - const auto* config_arg = encodable_config_arg.IsNull() ? nullptr : &(std::any_cast(std::get(encodable_config_arg))); - std::optional output = api->StartScan(filter_arg, config_arg); - if (output.has_value()) { - reply(WrapError(output.value())); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); return; } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); + const auto& device_id_arg = std::get(encodable_device_id_arg); + const auto& encodable_expected_mtu_arg = args.at(1); + if (encodable_expected_mtu_arg.IsNull()) { + reply(WrapError("expected_mtu_arg unexpectedly null.")); + return; + } + const int64_t expected_mtu_arg = encodable_expected_mtu_arg.LongValue(); + api->RequestMtu(device_id_arg, expected_mtu_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -907,18 +2126,50 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - std::optional output = api->StopScan(); - if (output.has_value()) { - reply(WrapError(output.value())); + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); return; } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); + const auto& device_id_arg = std::get(encodable_device_id_arg); + const auto& encodable_service_arg = args.at(1); + if (encodable_service_arg.IsNull()) { + reply(WrapError("service_arg unexpectedly null.")); + return; + } + const auto& service_arg = std::get(encodable_service_arg); + const auto& encodable_characteristic_arg = args.at(2); + if (encodable_characteristic_arg.IsNull()) { + reply(WrapError("characteristic_arg unexpectedly null.")); + return; + } + const auto& characteristic_arg = std::get(encodable_characteristic_arg); + const auto& encodable_value_arg = args.at(3); + if (encodable_value_arg.IsNull()) { + reply(WrapError("value_arg unexpectedly null.")); + return; + } + const auto& value_arg = std::get>(encodable_value_arg); + const auto& encodable_ble_output_property_arg = args.at(4); + if (encodable_ble_output_property_arg.IsNull()) { + reply(WrapError("ble_output_property_arg unexpectedly null.")); + return; + } + const int64_t ble_output_property_arg = encodable_ble_output_property_arg.LongValue(); + api->WriteValue(device_id_arg, service_arg, characteristic_arg, value_arg, ble_output_property_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -928,18 +2179,26 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - ErrorOr output = api->IsScanning(); - if (output.has_error()) { - reply(WrapError(output.error())); + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); return; } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); + const auto& device_id_arg = std::get(encodable_device_id_arg); + api->IsPaired(device_id_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -949,9 +2208,9 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_device_id_arg = args.at(0); @@ -960,16 +2219,15 @@ void UniversalBlePlatformChannel::SetUp( return; } const auto& device_id_arg = std::get(encodable_device_id_arg); - const auto& encodable_auto_connect_arg = args.at(1); - const auto* auto_connect_arg = std::get_if(&encodable_auto_connect_arg); - std::optional output = api->Connect(device_id_arg, auto_connect_arg); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); + api->Pair(device_id_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -979,9 +2237,9 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_device_id_arg = args.at(0); @@ -990,7 +2248,7 @@ void UniversalBlePlatformChannel::SetUp( return; } const auto& device_id_arg = std::get(encodable_device_id_arg); - std::optional output = api->Disconnect(device_id_arg); + std::optional output = api->UnPair(device_id_arg); if (output.has_value()) { reply(WrapError(output.value())); return; @@ -1007,42 +2265,24 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); - return; - } - const auto& device_id_arg = std::get(encodable_device_id_arg); - const auto& encodable_service_arg = args.at(1); - if (encodable_service_arg.IsNull()) { - reply(WrapError("service_arg unexpectedly null.")); - return; - } - const auto& service_arg = std::get(encodable_service_arg); - const auto& encodable_characteristic_arg = args.at(2); - if (encodable_characteristic_arg.IsNull()) { - reply(WrapError("characteristic_arg unexpectedly null.")); - return; - } - const auto& characteristic_arg = std::get(encodable_characteristic_arg); - const auto& encodable_ble_input_property_arg = args.at(3); - if (encodable_ble_input_property_arg.IsNull()) { - reply(WrapError("ble_input_property_arg unexpectedly null.")); + const auto& encodable_with_services_arg = args.at(0); + if (encodable_with_services_arg.IsNull()) { + reply(WrapError("with_services_arg unexpectedly null.")); return; } - const int64_t ble_input_property_arg = encodable_ble_input_property_arg.LongValue(); - api->SetNotifiable(device_id_arg, service_arg, characteristic_arg, ble_input_property_arg, [reply](std::optional&& output) { - if (output.has_value()) { - reply(WrapError(output.value())); + const auto& with_services_arg = std::get(encodable_with_services_arg); + api->GetSystemDevices(with_services_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); return; } EncodableList wrapped; - wrapped.push_back(EncodableValue()); + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); reply(EncodableValue(std::move(wrapped))); }); } catch (const std::exception& exception) { @@ -1054,9 +2294,9 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_device_id_arg = args.at(0); @@ -1065,21 +2305,14 @@ void UniversalBlePlatformChannel::SetUp( return; } const auto& device_id_arg = std::get(encodable_device_id_arg); - const auto& encodable_with_descriptors_arg = args.at(1); - if (encodable_with_descriptors_arg.IsNull()) { - reply(WrapError("with_descriptors_arg unexpectedly null.")); + ErrorOr output = api->GetConnectionState(device_id_arg); + if (output.has_error()) { + reply(WrapError(output.error())); return; } - const auto& with_descriptors_arg = std::get(encodable_with_descriptors_arg); - api->DiscoverServices(device_id_arg, with_descriptors_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - }); + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -1089,9 +2322,9 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_device_id_arg = args.at(0); @@ -1100,19 +2333,7 @@ void UniversalBlePlatformChannel::SetUp( return; } const auto& device_id_arg = std::get(encodable_device_id_arg); - const auto& encodable_service_arg = args.at(1); - if (encodable_service_arg.IsNull()) { - reply(WrapError("service_arg unexpectedly null.")); - return; - } - const auto& service_arg = std::get(encodable_service_arg); - const auto& encodable_characteristic_arg = args.at(2); - if (encodable_characteristic_arg.IsNull()) { - reply(WrapError("characteristic_arg unexpectedly null.")); - return; - } - const auto& characteristic_arg = std::get(encodable_characteristic_arg); - api->ReadValue(device_id_arg, service_arg, characteristic_arg, [reply](ErrorOr>&& output) { + api->ReadRssi(device_id_arg, [reply](ErrorOr&& output) { if (output.has_error()) { reply(WrapError(output.error())); return; @@ -1130,7 +2351,7 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestConnectionPriority" + prepended_suffix, &GetCodec()); if (api != nullptr) { channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { try { @@ -1141,19 +2362,19 @@ void UniversalBlePlatformChannel::SetUp( return; } const auto& device_id_arg = std::get(encodable_device_id_arg); - const auto& encodable_expected_mtu_arg = args.at(1); - if (encodable_expected_mtu_arg.IsNull()) { - reply(WrapError("expected_mtu_arg unexpectedly null.")); + const auto& encodable_priority_arg = args.at(1); + if (encodable_priority_arg.IsNull()) { + reply(WrapError("priority_arg unexpectedly null.")); return; } - const int64_t expected_mtu_arg = encodable_expected_mtu_arg.LongValue(); - api->RequestMtu(device_id_arg, expected_mtu_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); + const int64_t priority_arg = encodable_priority_arg.LongValue(); + api->RequestConnectionPriority(device_id_arg, priority_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); return; } EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + wrapped.push_back(EncodableValue()); reply(EncodableValue(std::move(wrapped))); }); } catch (const std::exception& exception) { @@ -1165,50 +2386,261 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); - return; - } - const auto& device_id_arg = std::get(encodable_device_id_arg); - const auto& encodable_service_arg = args.at(1); - if (encodable_service_arg.IsNull()) { - reply(WrapError("service_arg unexpectedly null.")); + const auto& encodable_log_level_arg = args.at(0); + if (encodable_log_level_arg.IsNull()) { + reply(WrapError("log_level_arg unexpectedly null.")); return; } - const auto& service_arg = std::get(encodable_service_arg); - const auto& encodable_characteristic_arg = args.at(2); - if (encodable_characteristic_arg.IsNull()) { - reply(WrapError("characteristic_arg unexpectedly null.")); + const auto& log_level_arg = std::any_cast(std::get(encodable_log_level_arg)); + std::optional output = api->SetLogLevel(log_level_arg); + if (output.has_value()) { + reply(WrapError(output.value())); return; } - const auto& characteristic_arg = std::get(encodable_characteristic_arg); - const auto& encodable_value_arg = args.at(3); - if (encodable_value_arg.IsNull()) { - reply(WrapError("value_arg unexpectedly null.")); + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } +} + +EncodableValue UniversalBlePlatformChannel::WrapError(std::string_view error_message) { + return EncodableValue(EncodableList{ + EncodableValue(std::string(error_message)), + EncodableValue("Error"), + EncodableValue() + }); +} + +EncodableValue UniversalBlePlatformChannel::WrapError(const FlutterError& error) { + return EncodableValue(EncodableList{ + EncodableValue(error.code()), + EncodableValue(error.message()), + error.details() + }); +} + +// Generated class from Pigeon that represents Flutter messages that can be called from C++. +UniversalBleCallbackChannel::UniversalBleCallbackChannel(::flutter::BinaryMessenger* binary_messenger) + : binary_messenger_(binary_messenger), + message_channel_suffix_("") {} + +UniversalBleCallbackChannel::UniversalBleCallbackChannel( + ::flutter::BinaryMessenger* binary_messenger, + const std::string& message_channel_suffix) + : binary_messenger_(binary_messenger), + message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} + +const ::flutter::StandardMessageCodec& UniversalBleCallbackChannel::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +} + +void UniversalBleCallbackChannel::OnAvailabilityChanged( + int64_t state_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(state_arg), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBleCallbackChannel::OnPairStateChange( + const std::string& device_id_arg, + bool is_paired_arg, + const std::string* error_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(is_paired_arg), + error_arg ? EncodableValue(*error_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBleCallbackChannel::OnScanResult( + const UniversalBleScanResult& result_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + CustomEncodableValue(result_arg), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBleCallbackChannel::OnValueChanged( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + const std::vector& value_arg, + const int64_t* timestamp_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(value_arg), + timestamp_arg ? EncodableValue(*timestamp_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBleCallbackChannel::OnConnectionChanged( + const std::string& device_id_arg, + bool connected_arg, + const std::string* error_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(connected_arg), + error_arg ? EncodableValue(*error_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + on_success(); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +/// The codec used by UniversalBlePeripheralChannel. +const ::flutter::StandardMessageCodec& UniversalBlePeripheralChannel::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +} + +// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. +void UniversalBlePeripheralChannel::SetUp( + ::flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api) { + UniversalBlePeripheralChannel::SetUp(binary_messenger, api, ""); +} + +void UniversalBlePeripheralChannel::SetUp( + ::flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api, + const std::string& message_channel_suffix) { + const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + std::optional output = api->Initialize(); + if (output.has_value()) { + reply(WrapError(output.value())); return; } - const auto& value_arg = std::get>(encodable_value_arg); - const auto& encodable_ble_output_property_arg = args.at(4); - if (encodable_ble_output_property_arg.IsNull()) { - reply(WrapError("ble_output_property_arg unexpectedly null.")); + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + ErrorOr> output = api->IsAdvertising(); + if (output.has_error()) { + reply(WrapError(output.error())); return; } - const int64_t ble_output_property_arg = encodable_ble_output_property_arg.LongValue(); - api->WriteValue(device_id_arg, service_arg, characteristic_arg, value_arg, ble_output_property_arg, [reply](std::optional&& output) { - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back(EncodableValue(std::move(output_optional).value())); + } else { wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - }); + } + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -1218,26 +2650,18 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); + ErrorOr output = api->IsSupported(); + if (output.has_error()) { + reply(WrapError(output.error())); return; } - const auto& device_id_arg = std::get(encodable_device_id_arg); - api->IsPaired(device_id_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - }); + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -1247,26 +2671,18 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); + std::optional output = api->StopAdvertising(); + if (output.has_value()) { + reply(WrapError(output.value())); return; } - const auto& device_id_arg = std::get(encodable_device_id_arg); - api->Pair(device_id_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - }); + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -1276,18 +2692,18 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); + const auto& encodable_service_arg = args.at(0); + if (encodable_service_arg.IsNull()) { + reply(WrapError("service_arg unexpectedly null.")); return; } - const auto& device_id_arg = std::get(encodable_device_id_arg); - std::optional output = api->UnPair(device_id_arg); + const auto& service_arg = std::any_cast(std::get(encodable_service_arg)); + std::optional output = api->AddService(service_arg); if (output.has_value()) { reply(WrapError(output.value())); return; @@ -1304,26 +2720,25 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_with_services_arg = args.at(0); - if (encodable_with_services_arg.IsNull()) { - reply(WrapError("with_services_arg unexpectedly null.")); + const auto& encodable_service_id_arg = args.at(0); + if (encodable_service_id_arg.IsNull()) { + reply(WrapError("service_id_arg unexpectedly null.")); return; } - const auto& with_services_arg = std::get(encodable_with_services_arg); - api->GetSystemDevices(with_services_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - }); + const auto& service_id_arg = std::get(encodable_service_id_arg); + std::optional output = api->RemoveService(service_id_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -1333,18 +2748,32 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); + std::optional output = api->ClearServices(); + if (output.has_value()) { + reply(WrapError(output.value())); return; } - const auto& device_id_arg = std::get(encodable_device_id_arg); - ErrorOr output = api->GetConnectionState(device_id_arg); + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + ErrorOr output = api->GetServices(); if (output.has_error()) { reply(WrapError(output.error())); return; @@ -1361,26 +2790,37 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); + const auto& encodable_services_arg = args.at(0); + if (encodable_services_arg.IsNull()) { + reply(WrapError("services_arg unexpectedly null.")); return; } - const auto& device_id_arg = std::get(encodable_device_id_arg); - api->ReadRssi(device_id_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - }); + const auto& services_arg = std::get(encodable_services_arg); + const auto& encodable_local_name_arg = args.at(1); + const auto* local_name_arg = std::get_if(&encodable_local_name_arg); + const auto& encodable_timeout_arg = args.at(2); + const auto* timeout_arg = std::get_if(&encodable_timeout_arg); + const auto& encodable_manufacturer_data_arg = args.at(3); + const auto* manufacturer_data_arg = encodable_manufacturer_data_arg.IsNull() ? nullptr : &(std::any_cast(std::get(encodable_manufacturer_data_arg))); + const auto& encodable_add_manufacturer_data_in_scan_response_arg = args.at(4); + if (encodable_add_manufacturer_data_in_scan_response_arg.IsNull()) { + reply(WrapError("add_manufacturer_data_in_scan_response_arg unexpectedly null.")); + return; + } + const auto& add_manufacturer_data_in_scan_response_arg = std::get(encodable_add_manufacturer_data_in_scan_response_arg); + std::optional output = api->StartAdvertising(services_arg, local_name_arg, timeout_arg, manufacturer_data_arg, add_manufacturer_data_in_scan_response_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -1390,32 +2830,33 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestConnectionPriority" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_device_id_arg = args.at(0); - if (encodable_device_id_arg.IsNull()) { - reply(WrapError("device_id_arg unexpectedly null.")); + const auto& encodable_characteristic_id_arg = args.at(0); + if (encodable_characteristic_id_arg.IsNull()) { + reply(WrapError("characteristic_id_arg unexpectedly null.")); return; } - const auto& device_id_arg = std::get(encodable_device_id_arg); - const auto& encodable_priority_arg = args.at(1); - if (encodable_priority_arg.IsNull()) { - reply(WrapError("priority_arg unexpectedly null.")); + const auto& characteristic_id_arg = std::get(encodable_characteristic_id_arg); + const auto& encodable_value_arg = args.at(1); + if (encodable_value_arg.IsNull()) { + reply(WrapError("value_arg unexpectedly null.")); return; } - const int64_t priority_arg = encodable_priority_arg.LongValue(); - api->RequestConnectionPriority(device_id_arg, priority_arg, [reply](std::optional&& output) { - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - }); + const auto& value_arg = std::get>(encodable_value_arg); + const auto& encodable_device_id_arg = args.at(2); + const auto* device_id_arg = std::get_if(&encodable_device_id_arg); + std::optional output = api->UpdateCharacteristic(characteristic_id_arg, value_arg, device_id_arg); + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); } @@ -1425,24 +2866,24 @@ void UniversalBlePlatformChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); - const auto& encodable_log_level_arg = args.at(0); - if (encodable_log_level_arg.IsNull()) { - reply(WrapError("log_level_arg unexpectedly null.")); + const auto& encodable_characteristic_id_arg = args.at(0); + if (encodable_characteristic_id_arg.IsNull()) { + reply(WrapError("characteristic_id_arg unexpectedly null.")); return; } - const auto& log_level_arg = std::any_cast(std::get(encodable_log_level_arg)); - std::optional output = api->SetLogLevel(log_level_arg); - if (output.has_value()) { - reply(WrapError(output.value())); + const auto& characteristic_id_arg = std::get(encodable_characteristic_id_arg); + ErrorOr output = api->GetSubscribedCentrals(characteristic_id_arg); + if (output.has_error()) { + reply(WrapError(output.error())); return; } EncodableList wrapped; - wrapped.push_back(EncodableValue()); + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); @@ -1454,7 +2895,7 @@ void UniversalBlePlatformChannel::SetUp( } } -EncodableValue UniversalBlePlatformChannel::WrapError(std::string_view error_message) { +EncodableValue UniversalBlePeripheralChannel::WrapError(std::string_view error_message) { return EncodableValue(EncodableList{ EncodableValue(std::string(error_message)), EncodableValue("Error"), @@ -1462,7 +2903,7 @@ EncodableValue UniversalBlePlatformChannel::WrapError(std::string_view error_mes }); } -EncodableValue UniversalBlePlatformChannel::WrapError(const FlutterError& error) { +EncodableValue UniversalBlePeripheralChannel::WrapError(const FlutterError& error) { return EncodableValue(EncodableList{ EncodableValue(error.code()), EncodableValue(error.message()), @@ -1471,28 +2912,98 @@ EncodableValue UniversalBlePlatformChannel::WrapError(const FlutterError& error) } // Generated class from Pigeon that represents Flutter messages that can be called from C++. -UniversalBleCallbackChannel::UniversalBleCallbackChannel(flutter::BinaryMessenger* binary_messenger) +UniversalBlePeripheralCallback::UniversalBlePeripheralCallback(::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} -UniversalBleCallbackChannel::UniversalBleCallbackChannel( - flutter::BinaryMessenger* binary_messenger, +UniversalBlePeripheralCallback::UniversalBlePeripheralCallback( + ::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& UniversalBleCallbackChannel::GetCodec() { - return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); +const ::flutter::StandardMessageCodec& UniversalBlePeripheralCallback::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); } -void UniversalBleCallbackChannel::OnAvailabilityChanged( - int64_t state_arg, +void UniversalBlePeripheralCallback::OnReadRequest( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + int64_t offset_arg, + const std::vector* value_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(offset_arg), + value_arg ? EncodableValue(*value_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); + on_success(return_value); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnWriteRequest( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + int64_t offset_arg, + const std::vector* value_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(offset_arg), + value_arg ? EncodableValue(*value_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); + on_success(return_value); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnCharacteristicSubscriptionChange( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + bool is_subscribed_arg, + const std::string* name_arg, std::function&& on_success, std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged" + message_channel_suffix_; + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange" + message_channel_suffix_; BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(state_arg), + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(is_subscribed_arg), + name_arg ? EncodableValue(*name_arg) : EncodableValue(), }); channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); @@ -1510,17 +3021,15 @@ void UniversalBleCallbackChannel::OnAvailabilityChanged( }); } -void UniversalBleCallbackChannel::OnPairStateChange( - const std::string& device_id_arg, - bool is_paired_arg, +void UniversalBlePeripheralCallback::OnAdvertisingStatusUpdate( + bool advertising_arg, const std::string* error_arg, std::function&& on_success, std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange" + message_channel_suffix_; + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate" + message_channel_suffix_; BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(device_id_arg), - EncodableValue(is_paired_arg), + EncodableValue(advertising_arg), error_arg ? EncodableValue(*error_arg) : EncodableValue(), }); channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { @@ -1539,14 +3048,16 @@ void UniversalBleCallbackChannel::OnPairStateChange( }); } -void UniversalBleCallbackChannel::OnScanResult( - const UniversalBleScanResult& result_arg, +void UniversalBlePeripheralCallback::OnServiceAdded( + const std::string& service_id_arg, + const std::string* error_arg, std::function&& on_success, std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult" + message_channel_suffix_; + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded" + message_channel_suffix_; BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - CustomEncodableValue(result_arg), + EncodableValue(service_id_arg), + error_arg ? EncodableValue(*error_arg) : EncodableValue(), }); channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); @@ -1564,20 +3075,16 @@ void UniversalBleCallbackChannel::OnScanResult( }); } -void UniversalBleCallbackChannel::OnValueChanged( +void UniversalBlePeripheralCallback::OnMtuChange( const std::string& device_id_arg, - const std::string& characteristic_id_arg, - const std::vector& value_arg, - const int64_t* timestamp_arg, + int64_t mtu_arg, std::function&& on_success, std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged" + message_channel_suffix_; + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange" + message_channel_suffix_; BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ EncodableValue(device_id_arg), - EncodableValue(characteristic_id_arg), - EncodableValue(value_arg), - timestamp_arg ? EncodableValue(*timestamp_arg) : EncodableValue(), + EncodableValue(mtu_arg), }); channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); @@ -1595,18 +3102,16 @@ void UniversalBleCallbackChannel::OnValueChanged( }); } -void UniversalBleCallbackChannel::OnConnectionChanged( +void UniversalBlePeripheralCallback::OnConnectionStateChange( const std::string& device_id_arg, bool connected_arg, - const std::string* error_arg, std::function&& on_success, std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged" + message_channel_suffix_; + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange" + message_channel_suffix_; BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ EncodableValue(device_id_arg), EncodableValue(connected_arg), - error_arg ? EncodableValue(*error_arg) : EncodableValue(), }); channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); diff --git a/windows/src/generated/universal_ble.g.h b/windows/src/generated/universal_ble.g.h index 88cb5177..f26eed11 100644 --- a/windows/src/generated/universal_ble.g.h +++ b/windows/src/generated/universal_ble.g.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.1.4), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_UNIVERSAL_BLE_G_H_ @@ -23,17 +23,17 @@ class FlutterError { : code_(code) {} explicit FlutterError(const std::string& code, const std::string& message) : code_(code), message_(message) {} - explicit FlutterError(const std::string& code, const std::string& message, const flutter::EncodableValue& details) + explicit FlutterError(const std::string& code, const std::string& message, const ::flutter::EncodableValue& details) : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; template class ErrorOr { @@ -50,6 +50,8 @@ template class ErrorOr { private: friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; ErrorOr() = default; T TakeValue() && { return std::get(std::move(v_)); } @@ -152,9 +154,9 @@ class UniversalBleScanResult { const std::string* name, const bool* is_paired, const int64_t* rssi, - const flutter::EncodableList* manufacturer_data_list, - const flutter::EncodableMap* service_data, - const flutter::EncodableList* services, + const ::flutter::EncodableList* manufacturer_data_list, + const ::flutter::EncodableMap* service_data, + const ::flutter::EncodableList* services, const int64_t* timestamp); const std::string& device_id() const; @@ -172,35 +174,41 @@ class UniversalBleScanResult { void set_rssi(const int64_t* value_arg); void set_rssi(int64_t value_arg); - const flutter::EncodableList* manufacturer_data_list() const; - void set_manufacturer_data_list(const flutter::EncodableList* value_arg); - void set_manufacturer_data_list(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* manufacturer_data_list() const; + void set_manufacturer_data_list(const ::flutter::EncodableList* value_arg); + void set_manufacturer_data_list(const ::flutter::EncodableList& value_arg); - const flutter::EncodableMap* service_data() const; - void set_service_data(const flutter::EncodableMap* value_arg); - void set_service_data(const flutter::EncodableMap& value_arg); + const ::flutter::EncodableMap* service_data() const; + void set_service_data(const ::flutter::EncodableMap* value_arg); + void set_service_data(const ::flutter::EncodableMap& value_arg); - const flutter::EncodableList* services() const; - void set_services(const flutter::EncodableList* value_arg); - void set_services(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* services() const; + void set_services(const ::flutter::EncodableList* value_arg); + void set_services(const ::flutter::EncodableList& value_arg); const int64_t* timestamp() const; void set_timestamp(const int64_t* value_arg); void set_timestamp(int64_t value_arg); + bool operator==(const UniversalBleScanResult& other) const; + bool operator!=(const UniversalBleScanResult& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalBleScanResult FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalBleScanResult FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::string device_id_; std::optional name_; std::optional is_paired_; std::optional rssi_; - std::optional manufacturer_data_list_; - std::optional service_data_; - std::optional services_; + std::optional<::flutter::EncodableList> manufacturer_data_list_; + std::optional<::flutter::EncodableMap> service_data_; + std::optional<::flutter::EncodableList> services_; std::optional timestamp_; }; @@ -214,23 +222,29 @@ class UniversalBleService { // Constructs an object setting all fields. explicit UniversalBleService( const std::string& uuid, - const flutter::EncodableList* characteristics); + const ::flutter::EncodableList* characteristics); const std::string& uuid() const; void set_uuid(std::string_view value_arg); - const flutter::EncodableList* characteristics() const; - void set_characteristics(const flutter::EncodableList* value_arg); - void set_characteristics(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList* characteristics() const; + void set_characteristics(const ::flutter::EncodableList* value_arg); + void set_characteristics(const ::flutter::EncodableList& value_arg); + bool operator==(const UniversalBleService& other) const; + bool operator!=(const UniversalBleService& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalBleService FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalBleService FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::string uuid_; - std::optional characteristics_; + std::optional<::flutter::EncodableList> characteristics_; }; @@ -240,27 +254,33 @@ class UniversalBleCharacteristic { // Constructs an object setting all fields. explicit UniversalBleCharacteristic( const std::string& uuid, - const flutter::EncodableList& properties, - const flutter::EncodableList& descriptors); + const ::flutter::EncodableList& properties, + const ::flutter::EncodableList& descriptors); const std::string& uuid() const; void set_uuid(std::string_view value_arg); - const flutter::EncodableList& properties() const; - void set_properties(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& properties() const; + void set_properties(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& descriptors() const; - void set_descriptors(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& descriptors() const; + void set_descriptors(const ::flutter::EncodableList& value_arg); + bool operator==(const UniversalBleCharacteristic& other) const; + bool operator!=(const UniversalBleCharacteristic& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalBleCharacteristic FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalBleCharacteristic FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::string uuid_; - flutter::EncodableList properties_; - flutter::EncodableList descriptors_; + ::flutter::EncodableList properties_; + ::flutter::EncodableList descriptors_; }; @@ -273,11 +293,17 @@ class UniversalBleDescriptor { const std::string& uuid() const; void set_uuid(std::string_view value_arg); + bool operator==(const UniversalBleDescriptor& other) const; + bool operator!=(const UniversalBleDescriptor& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalBleDescriptor FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalBleDescriptor FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::string uuid_; }; @@ -314,12 +340,18 @@ class AndroidOptions { void set_report_delay_millis(const int64_t* value_arg); void set_report_delay_millis(int64_t value_arg); + bool operator==(const AndroidOptions& other) const; + bool operator!=(const AndroidOptions& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static AndroidOptions FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static AndroidOptions FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalScanConfig; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::optional request_location_permission_; std::optional scan_mode_; @@ -345,11 +377,17 @@ class UniversalScanConfig { void set_android(const AndroidOptions* value_arg); void set_android(const AndroidOptions& value_arg); + bool operator==(const UniversalScanConfig& other) const; + bool operator!=(const UniversalScanConfig& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalScanConfig FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalScanConfig FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; std::unique_ptr android_; }; @@ -362,28 +400,34 @@ class UniversalScanFilter { public: // Constructs an object setting all fields. explicit UniversalScanFilter( - const flutter::EncodableList& with_services, - const flutter::EncodableList& with_name_prefix, - const flutter::EncodableList& with_manufacturer_data); + const ::flutter::EncodableList& with_services, + const ::flutter::EncodableList& with_name_prefix, + const ::flutter::EncodableList& with_manufacturer_data); - const flutter::EncodableList& with_services() const; - void set_with_services(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& with_services() const; + void set_with_services(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& with_name_prefix() const; - void set_with_name_prefix(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& with_name_prefix() const; + void set_with_name_prefix(const ::flutter::EncodableList& value_arg); - const flutter::EncodableList& with_manufacturer_data() const; - void set_with_manufacturer_data(const flutter::EncodableList& value_arg); + const ::flutter::EncodableList& with_manufacturer_data() const; + void set_with_manufacturer_data(const ::flutter::EncodableList& value_arg); + bool operator==(const UniversalScanFilter& other) const; + bool operator!=(const UniversalScanFilter& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalScanFilter FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalScanFilter FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; - flutter::EncodableList with_services_; - flutter::EncodableList with_name_prefix_; - flutter::EncodableList with_manufacturer_data_; + ::flutter::EncodableList with_services_; + ::flutter::EncodableList with_name_prefix_; + ::flutter::EncodableList with_manufacturer_data_; }; @@ -410,11 +454,17 @@ class UniversalManufacturerDataFilter { void set_mask(const std::vector* value_arg); void set_mask(const std::vector& value_arg); + bool operator==(const UniversalManufacturerDataFilter& other) const; + bool operator!=(const UniversalManufacturerDataFilter& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalManufacturerDataFilter FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalManufacturerDataFilter FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; int64_t company_identifier_; std::optional> data_; @@ -436,18 +486,269 @@ class UniversalManufacturerData { const std::vector& data() const; void set_data(const std::vector& value_arg); + bool operator==(const UniversalManufacturerData& other) const; + bool operator!=(const UniversalManufacturerData& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; private: - static UniversalManufacturerData FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static UniversalManufacturerData FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class UniversalBlePlatformChannel; friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; friend class PigeonInternalCodecSerializer; int64_t company_identifier_; std::vector data_; }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { +// Generated class from Pigeon that represents data sent in messages. +class PeripheralService { + public: + // Constructs an object setting all fields. + explicit PeripheralService( + const std::string& uuid, + bool primary, + const ::flutter::EncodableList& characteristics); + + const std::string& uuid() const; + void set_uuid(std::string_view value_arg); + + bool primary() const; + void set_primary(bool value_arg); + + const ::flutter::EncodableList& characteristics() const; + void set_characteristics(const ::flutter::EncodableList& value_arg); + + bool operator==(const PeripheralService& other) const; + bool operator!=(const PeripheralService& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; + private: + static PeripheralService FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePlatformChannel; + friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::string uuid_; + bool primary_; + ::flutter::EncodableList characteristics_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralCharacteristic { + public: + // Constructs an object setting all non-nullable fields. + explicit PeripheralCharacteristic( + const std::string& uuid, + const ::flutter::EncodableList& properties, + const ::flutter::EncodableList& permissions); + + // Constructs an object setting all fields. + explicit PeripheralCharacteristic( + const std::string& uuid, + const ::flutter::EncodableList& properties, + const ::flutter::EncodableList& permissions, + const ::flutter::EncodableList* descriptors, + const std::vector* value); + + const std::string& uuid() const; + void set_uuid(std::string_view value_arg); + + const ::flutter::EncodableList& properties() const; + void set_properties(const ::flutter::EncodableList& value_arg); + + const ::flutter::EncodableList& permissions() const; + void set_permissions(const ::flutter::EncodableList& value_arg); + + const ::flutter::EncodableList* descriptors() const; + void set_descriptors(const ::flutter::EncodableList* value_arg); + void set_descriptors(const ::flutter::EncodableList& value_arg); + + const std::vector* value() const; + void set_value(const std::vector* value_arg); + void set_value(const std::vector& value_arg); + + bool operator==(const PeripheralCharacteristic& other) const; + bool operator!=(const PeripheralCharacteristic& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; + private: + static PeripheralCharacteristic FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePlatformChannel; + friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::string uuid_; + ::flutter::EncodableList properties_; + ::flutter::EncodableList permissions_; + std::optional<::flutter::EncodableList> descriptors_; + std::optional> value_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralDescriptor { + public: + // Constructs an object setting all non-nullable fields. + explicit PeripheralDescriptor(const std::string& uuid); + + // Constructs an object setting all fields. + explicit PeripheralDescriptor( + const std::string& uuid, + const std::vector* value, + const ::flutter::EncodableList* permissions); + + const std::string& uuid() const; + void set_uuid(std::string_view value_arg); + + const std::vector* value() const; + void set_value(const std::vector* value_arg); + void set_value(const std::vector& value_arg); + + const ::flutter::EncodableList* permissions() const; + void set_permissions(const ::flutter::EncodableList* value_arg); + void set_permissions(const ::flutter::EncodableList& value_arg); + + bool operator==(const PeripheralDescriptor& other) const; + bool operator!=(const PeripheralDescriptor& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; + private: + static PeripheralDescriptor FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePlatformChannel; + friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::string uuid_; + std::optional> value_; + std::optional<::flutter::EncodableList> permissions_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralReadRequestResult { + public: + // Constructs an object setting all non-nullable fields. + explicit PeripheralReadRequestResult(const std::vector& value); + + // Constructs an object setting all fields. + explicit PeripheralReadRequestResult( + const std::vector& value, + const int64_t* offset, + const int64_t* status); + + const std::vector& value() const; + void set_value(const std::vector& value_arg); + + const int64_t* offset() const; + void set_offset(const int64_t* value_arg); + void set_offset(int64_t value_arg); + + const int64_t* status() const; + void set_status(const int64_t* value_arg); + void set_status(int64_t value_arg); + + bool operator==(const PeripheralReadRequestResult& other) const; + bool operator!=(const PeripheralReadRequestResult& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; + private: + static PeripheralReadRequestResult FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePlatformChannel; + friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::vector value_; + std::optional offset_; + std::optional status_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralWriteRequestResult { + public: + // Constructs an object setting all non-nullable fields. + PeripheralWriteRequestResult(); + + // Constructs an object setting all fields. + explicit PeripheralWriteRequestResult( + const std::vector* value, + const int64_t* offset, + const int64_t* status); + + const std::vector* value() const; + void set_value(const std::vector* value_arg); + void set_value(const std::vector& value_arg); + + const int64_t* offset() const; + void set_offset(const int64_t* value_arg); + void set_offset(int64_t value_arg); + + const int64_t* status() const; + void set_status(const int64_t* value_arg); + void set_status(int64_t value_arg); + + bool operator==(const PeripheralWriteRequestResult& other) const; + bool operator!=(const PeripheralWriteRequestResult& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; + private: + static PeripheralWriteRequestResult FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePlatformChannel; + friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + std::optional> value_; + std::optional offset_; + std::optional status_; +}; + + +// Generated class from Pigeon that represents data sent in messages. +class PeripheralManufacturerData { + public: + // Constructs an object setting all fields. + explicit PeripheralManufacturerData( + int64_t manufacturer_id, + const std::vector& data); + + int64_t manufacturer_id() const; + void set_manufacturer_id(int64_t value_arg); + + const std::vector& data() const; + void set_data(const std::vector& value_arg); + + bool operator==(const PeripheralManufacturerData& other) const; + bool operator!=(const PeripheralManufacturerData& other) const; + /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. + size_t Hash() const; + private: + static PeripheralManufacturerData FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; + friend class UniversalBlePlatformChannel; + friend class UniversalBleCallbackChannel; + friend class UniversalBlePeripheralChannel; + friend class UniversalBlePeripheralCallback; + friend class PigeonInternalCodecSerializer; + int64_t manufacturer_id_; + std::vector data_; +}; + + +class PigeonInternalCodecSerializer : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -456,12 +757,12 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { } void WriteValue( - const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; + const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( + ::flutter::EncodableValue ReadValueOfType( uint8_t type, - flutter::ByteStreamReader* stream) const override; + ::flutter::ByteStreamReader* stream) const override; }; // Flutter -> Native @@ -497,7 +798,7 @@ class UniversalBlePlatformChannel { virtual void DiscoverServices( const std::string& device_id, bool with_descriptors, - std::function reply)> result) = 0; + std::function reply)> result) = 0; virtual void ReadValue( const std::string& device_id, const std::string& service, @@ -522,8 +823,8 @@ class UniversalBlePlatformChannel { std::function reply)> result) = 0; virtual std::optional UnPair(const std::string& device_id) = 0; virtual void GetSystemDevices( - const flutter::EncodableList& with_services, - std::function reply)> result) = 0; + const ::flutter::EncodableList& with_services, + std::function reply)> result) = 0; virtual ErrorOr GetConnectionState(const std::string& device_id) = 0; virtual void ReadRssi( const std::string& device_id, @@ -535,17 +836,17 @@ class UniversalBlePlatformChannel { virtual std::optional SetLogLevel(const UniversalBleLogLevel& log_level) = 0; // The codec used by UniversalBlePlatformChannel. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binary_messenger`. static void SetUp( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, UniversalBlePlatformChannel* api); static void SetUp( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, UniversalBlePlatformChannel* api, const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: UniversalBlePlatformChannel() = default; }; @@ -554,11 +855,11 @@ class UniversalBlePlatformChannel { // Generated class from Pigeon that represents Flutter messages that can be called from C++. class UniversalBleCallbackChannel { public: - UniversalBleCallbackChannel(flutter::BinaryMessenger* binary_messenger); + UniversalBleCallbackChannel(::flutter::BinaryMessenger* binary_messenger); UniversalBleCallbackChannel( - flutter::BinaryMessenger* binary_messenger, + ::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); void OnAvailabilityChanged( int64_t state, std::function&& on_success, @@ -587,7 +888,108 @@ class UniversalBleCallbackChannel { std::function&& on_success, std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; + std::string message_channel_suffix_; +}; + +// Flutter -> Native (peripheral) +// +// Generated interface from Pigeon that represents a handler of messages from Flutter. +class UniversalBlePeripheralChannel { + public: + UniversalBlePeripheralChannel(const UniversalBlePeripheralChannel&) = delete; + UniversalBlePeripheralChannel& operator=(const UniversalBlePeripheralChannel&) = delete; + virtual ~UniversalBlePeripheralChannel() {} + virtual std::optional Initialize() = 0; + virtual ErrorOr> IsAdvertising() = 0; + virtual ErrorOr IsSupported() = 0; + virtual std::optional StopAdvertising() = 0; + virtual std::optional AddService(const PeripheralService& service) = 0; + virtual std::optional RemoveService(const std::string& service_id) = 0; + virtual std::optional ClearServices() = 0; + virtual ErrorOr<::flutter::EncodableList> GetServices() = 0; + virtual std::optional StartAdvertising( + const ::flutter::EncodableList& services, + const std::string* local_name, + const int64_t* timeout, + const PeripheralManufacturerData* manufacturer_data, + bool add_manufacturer_data_in_scan_response) = 0; + virtual std::optional UpdateCharacteristic( + const std::string& characteristic_id, + const std::vector& value, + const std::string* device_id) = 0; + // Returns peripheral-central device ids currently subscribed to [characteristicId] + // (e.g. HID report characteristic). Used to restore app state after restart. + virtual ErrorOr<::flutter::EncodableList> GetSubscribedCentrals(const std::string& characteristic_id) = 0; + + // The codec used by UniversalBlePeripheralChannel. + static const ::flutter::StandardMessageCodec& GetCodec(); + // Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. + static void SetUp( + ::flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api); + static void SetUp( + ::flutter::BinaryMessenger* binary_messenger, + UniversalBlePeripheralChannel* api, + const std::string& message_channel_suffix); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); + protected: + UniversalBlePeripheralChannel() = default; +}; +// Native -> Flutter (peripheral) +// +// Generated class from Pigeon that represents Flutter messages that can be called from C++. +class UniversalBlePeripheralCallback { + public: + UniversalBlePeripheralCallback(::flutter::BinaryMessenger* binary_messenger); + UniversalBlePeripheralCallback( + ::flutter::BinaryMessenger* binary_messenger, + const std::string& message_channel_suffix); + static const ::flutter::StandardMessageCodec& GetCodec(); + void OnReadRequest( + const std::string& device_id, + const std::string& characteristic_id, + int64_t offset, + const std::vector* value, + std::function&& on_success, + std::function&& on_error); + void OnWriteRequest( + const std::string& device_id, + const std::string& characteristic_id, + int64_t offset, + const std::vector* value, + std::function&& on_success, + std::function&& on_error); + void OnCharacteristicSubscriptionChange( + const std::string& device_id, + const std::string& characteristic_id, + bool is_subscribed, + const std::string* name, + std::function&& on_success, + std::function&& on_error); + void OnAdvertisingStatusUpdate( + bool advertising, + const std::string* error, + std::function&& on_success, + std::function&& on_error); + void OnServiceAdded( + const std::string& service_id, + const std::string* error, + std::function&& on_success, + std::function&& on_error); + void OnMtuChange( + const std::string& device_id, + int64_t mtu, + std::function&& on_success, + std::function&& on_error); + void OnConnectionStateChange( + const std::string& device_id, + bool connected, + std::function&& on_success, + std::function&& on_error); + private: + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; diff --git a/windows/src/generated/universal_ble_peripheral.g.cpp b/windows/src/generated/universal_ble_peripheral.g.cpp deleted file mode 100644 index ce9a23cb..00000000 --- a/windows/src/generated/universal_ble_peripheral.g.cpp +++ /dev/null @@ -1,1387 +0,0 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. -// See also: https://pub.dev/packages/pigeon - -#undef _HAS_EXCEPTIONS - -#include "universal_ble_peripheral.g.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace universal_ble { -using ::flutter::BasicMessageChannel; -using ::flutter::CustomEncodableValue; -using ::flutter::EncodableList; -using ::flutter::EncodableMap; -using ::flutter::EncodableValue; - -FlutterError CreateConnectionError(const std::string channel_name) { - return FlutterError( - "channel-error", - "Unable to establish connection on channel: '" + channel_name + "'.", - EncodableValue("")); -} - -namespace { -template -bool PigeonInternalDeepEquals(const T& a, const T& b); - -bool PigeonInternalDeepEquals(const double& a, const double& b); - -template -bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); - -template -bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); - -template -bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b); - -template -bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b); - -bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b); - -template -bool PigeonInternalDeepEquals(const T& a, const T& b) { - return a == b; -} - -template -bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b) { - if (a.size() != b.size()) { - return false; - } - for (size_t i = 0; i < a.size(); ++i) { - if (!PigeonInternalDeepEquals(a[i], b[i])) { - return false; - } - } - return true; -} - -template -bool PigeonInternalDeepEquals(const std::map& a, const std::map& b) { - if (a.size() != b.size()) { - return false; - } - for (const auto& kv : a) { - bool found = false; - for (const auto& b_kv : b) { - if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { - if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { - found = true; - break; - } else { - return false; - } - } - } - if (!found) { - return false; - } - } - return true; -} - -bool PigeonInternalDeepEquals(const double& a, const double& b) { - // Normalize -0.0 to 0.0 and handle NaN equality. - return (a == b) || (std::isnan(a) && std::isnan(b)); -} - -template -bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b) { - if (!a && !b) { - return true; - } - if (!a || !b) { - return false; - } - return PigeonInternalDeepEquals(*a, *b); -} - -template -bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b) { - if (a.get() == b.get()) { - return true; - } - if (!a || !b) { - return false; - } - return PigeonInternalDeepEquals(*a, *b); -} - -bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b) { - if (a.index() != b.index()) { - return false; - } - if (const double* da = std::get_if(&a)) { - return PigeonInternalDeepEquals(*da, std::get(b)); - } else if (const ::flutter::EncodableList* la = std::get_if<::flutter::EncodableList>(&a)) { - return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); - } else if (const ::flutter::EncodableMap* ma = std::get_if<::flutter::EncodableMap>(&a)) { - return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); - } - return a == b; -} - -template -size_t PigeonInternalDeepHash(const T& v); - -size_t PigeonInternalDeepHash(const double& v); - -template -size_t PigeonInternalDeepHash(const std::vector& v); - -template -size_t PigeonInternalDeepHash(const std::map& v); - -template -size_t PigeonInternalDeepHash(const std::optional& v); - -template -size_t PigeonInternalDeepHash(const std::unique_ptr& v); - -size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); - -template -size_t PigeonInternalDeepHash(const T& v) { - return std::hash()(v); -} - -template -size_t PigeonInternalDeepHash(const std::vector& v) { - size_t result = 1; - for (const auto& item : v) { - result = result * 31 + PigeonInternalDeepHash(item); - } - return result; -} - -template -size_t PigeonInternalDeepHash(const std::map& v) { - size_t result = 0; - for (const auto& kv : v) { - result += ((PigeonInternalDeepHash(kv.first) * 31) ^ PigeonInternalDeepHash(kv.second)); - } - return result; -} - -size_t PigeonInternalDeepHash(const double& v) { - if (std::isnan(v)) { - // Normalize NaN to a consistent hash. - return std::hash()(std::numeric_limits::quiet_NaN()); - } - if (v == 0.0) { - // Normalize -0.0 to 0.0 so they have the same hash code. - return std::hash()(0.0); - } - return std::hash()(v); -} - -template -size_t PigeonInternalDeepHash(const std::optional& v) { - return v ? PigeonInternalDeepHash(*v) : 0; -} - -template -size_t PigeonInternalDeepHash(const std::unique_ptr& v) { - return v ? PigeonInternalDeepHash(*v) : 0; -} - -size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { - size_t result = v.index(); - if (const double* dv = std::get_if(&v)) { - result = result * 31 + PigeonInternalDeepHash(*dv); - } else if (const ::flutter::EncodableList* lv = - std::get_if<::flutter::EncodableList>(&v)) { - result = result * 31 + PigeonInternalDeepHash(*lv); - } else if (const ::flutter::EncodableMap* mv = - std::get_if<::flutter::EncodableMap>(&v)) { - result = result * 31 + PigeonInternalDeepHash(*mv); - } else { - std::visit( - [&result](const auto& val) { - using T = std::decay_t; - if constexpr (!std::is_same_v && - !std::is_same_v && - !std::is_same_v && - !std::is_same_v && - !std::is_same_v) { - result = result * 31 + PigeonInternalDeepHash(val); - } - }, - v); - } - return result; -} - -} // namespace -// PeripheralService - -PeripheralService::PeripheralService( - const std::string& uuid, - bool primary, - const EncodableList& characteristics) - : uuid_(uuid), - primary_(primary), - characteristics_(characteristics) {} - -const std::string& PeripheralService::uuid() const { - return uuid_; -} - -void PeripheralService::set_uuid(std::string_view value_arg) { - uuid_ = value_arg; -} - - -bool PeripheralService::primary() const { - return primary_; -} - -void PeripheralService::set_primary(bool value_arg) { - primary_ = value_arg; -} - - -const EncodableList& PeripheralService::characteristics() const { - return characteristics_; -} - -void PeripheralService::set_characteristics(const EncodableList& value_arg) { - characteristics_ = value_arg; -} - - -EncodableList PeripheralService::ToEncodableList() const { - EncodableList list; - list.reserve(3); - list.push_back(EncodableValue(uuid_)); - list.push_back(EncodableValue(primary_)); - list.push_back(EncodableValue(characteristics_)); - return list; -} - -PeripheralService PeripheralService::FromEncodableList(const EncodableList& list) { - PeripheralService decoded( - std::get(list[0]), - std::get(list[1]), - std::get(list[2])); - return decoded; -} - -bool PeripheralService::operator==(const PeripheralService& other) const { - return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(primary_, other.primary_) && PigeonInternalDeepEquals(characteristics_, other.characteristics_); -} - -bool PeripheralService::operator!=(const PeripheralService& other) const { - return !(*this == other); -} - -size_t PeripheralService::Hash() const { - size_t result = 1; - result = result * 31 + PigeonInternalDeepHash(uuid_); - result = result * 31 + PigeonInternalDeepHash(primary_); - result = result * 31 + PigeonInternalDeepHash(characteristics_); - return result; -} - -size_t PigeonInternalDeepHash(const PeripheralService& v) { - return v.Hash(); -} - -// PeripheralCharacteristic - -PeripheralCharacteristic::PeripheralCharacteristic( - const std::string& uuid, - const EncodableList& properties, - const EncodableList& permissions) - : uuid_(uuid), - properties_(properties), - permissions_(permissions) {} - -PeripheralCharacteristic::PeripheralCharacteristic( - const std::string& uuid, - const EncodableList& properties, - const EncodableList& permissions, - const EncodableList* descriptors, - const std::vector* value) - : uuid_(uuid), - properties_(properties), - permissions_(permissions), - descriptors_(descriptors ? std::optional(*descriptors) : std::nullopt), - value_(value ? std::optional>(*value) : std::nullopt) {} - -const std::string& PeripheralCharacteristic::uuid() const { - return uuid_; -} - -void PeripheralCharacteristic::set_uuid(std::string_view value_arg) { - uuid_ = value_arg; -} - - -const EncodableList& PeripheralCharacteristic::properties() const { - return properties_; -} - -void PeripheralCharacteristic::set_properties(const EncodableList& value_arg) { - properties_ = value_arg; -} - - -const EncodableList& PeripheralCharacteristic::permissions() const { - return permissions_; -} - -void PeripheralCharacteristic::set_permissions(const EncodableList& value_arg) { - permissions_ = value_arg; -} - - -const EncodableList* PeripheralCharacteristic::descriptors() const { - return descriptors_ ? &(*descriptors_) : nullptr; -} - -void PeripheralCharacteristic::set_descriptors(const EncodableList* value_arg) { - descriptors_ = value_arg ? std::optional(*value_arg) : std::nullopt; -} - -void PeripheralCharacteristic::set_descriptors(const EncodableList& value_arg) { - descriptors_ = value_arg; -} - - -const std::vector* PeripheralCharacteristic::value() const { - return value_ ? &(*value_) : nullptr; -} - -void PeripheralCharacteristic::set_value(const std::vector* value_arg) { - value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; -} - -void PeripheralCharacteristic::set_value(const std::vector& value_arg) { - value_ = value_arg; -} - - -EncodableList PeripheralCharacteristic::ToEncodableList() const { - EncodableList list; - list.reserve(5); - list.push_back(EncodableValue(uuid_)); - list.push_back(EncodableValue(properties_)); - list.push_back(EncodableValue(permissions_)); - list.push_back(descriptors_ ? EncodableValue(*descriptors_) : EncodableValue()); - list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); - return list; -} - -PeripheralCharacteristic PeripheralCharacteristic::FromEncodableList(const EncodableList& list) { - PeripheralCharacteristic decoded( - std::get(list[0]), - std::get(list[1]), - std::get(list[2])); - auto& encodable_descriptors = list[3]; - if (!encodable_descriptors.IsNull()) { - decoded.set_descriptors(std::get(encodable_descriptors)); - } - auto& encodable_value = list[4]; - if (!encodable_value.IsNull()) { - decoded.set_value(std::get>(encodable_value)); - } - return decoded; -} - -bool PeripheralCharacteristic::operator==(const PeripheralCharacteristic& other) const { - return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(properties_, other.properties_) && PigeonInternalDeepEquals(permissions_, other.permissions_) && PigeonInternalDeepEquals(descriptors_, other.descriptors_) && PigeonInternalDeepEquals(value_, other.value_); -} - -bool PeripheralCharacteristic::operator!=(const PeripheralCharacteristic& other) const { - return !(*this == other); -} - -size_t PeripheralCharacteristic::Hash() const { - size_t result = 1; - result = result * 31 + PigeonInternalDeepHash(uuid_); - result = result * 31 + PigeonInternalDeepHash(properties_); - result = result * 31 + PigeonInternalDeepHash(permissions_); - result = result * 31 + PigeonInternalDeepHash(descriptors_); - result = result * 31 + PigeonInternalDeepHash(value_); - return result; -} - -size_t PigeonInternalDeepHash(const PeripheralCharacteristic& v) { - return v.Hash(); -} - -// PeripheralDescriptor - -PeripheralDescriptor::PeripheralDescriptor(const std::string& uuid) - : uuid_(uuid) {} - -PeripheralDescriptor::PeripheralDescriptor( - const std::string& uuid, - const std::vector* value, - const EncodableList* permissions) - : uuid_(uuid), - value_(value ? std::optional>(*value) : std::nullopt), - permissions_(permissions ? std::optional(*permissions) : std::nullopt) {} - -const std::string& PeripheralDescriptor::uuid() const { - return uuid_; -} - -void PeripheralDescriptor::set_uuid(std::string_view value_arg) { - uuid_ = value_arg; -} - - -const std::vector* PeripheralDescriptor::value() const { - return value_ ? &(*value_) : nullptr; -} - -void PeripheralDescriptor::set_value(const std::vector* value_arg) { - value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; -} - -void PeripheralDescriptor::set_value(const std::vector& value_arg) { - value_ = value_arg; -} - - -const EncodableList* PeripheralDescriptor::permissions() const { - return permissions_ ? &(*permissions_) : nullptr; -} - -void PeripheralDescriptor::set_permissions(const EncodableList* value_arg) { - permissions_ = value_arg ? std::optional(*value_arg) : std::nullopt; -} - -void PeripheralDescriptor::set_permissions(const EncodableList& value_arg) { - permissions_ = value_arg; -} - - -EncodableList PeripheralDescriptor::ToEncodableList() const { - EncodableList list; - list.reserve(3); - list.push_back(EncodableValue(uuid_)); - list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); - list.push_back(permissions_ ? EncodableValue(*permissions_) : EncodableValue()); - return list; -} - -PeripheralDescriptor PeripheralDescriptor::FromEncodableList(const EncodableList& list) { - PeripheralDescriptor decoded( - std::get(list[0])); - auto& encodable_value = list[1]; - if (!encodable_value.IsNull()) { - decoded.set_value(std::get>(encodable_value)); - } - auto& encodable_permissions = list[2]; - if (!encodable_permissions.IsNull()) { - decoded.set_permissions(std::get(encodable_permissions)); - } - return decoded; -} - -bool PeripheralDescriptor::operator==(const PeripheralDescriptor& other) const { - return PigeonInternalDeepEquals(uuid_, other.uuid_) && PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(permissions_, other.permissions_); -} - -bool PeripheralDescriptor::operator!=(const PeripheralDescriptor& other) const { - return !(*this == other); -} - -size_t PeripheralDescriptor::Hash() const { - size_t result = 1; - result = result * 31 + PigeonInternalDeepHash(uuid_); - result = result * 31 + PigeonInternalDeepHash(value_); - result = result * 31 + PigeonInternalDeepHash(permissions_); - return result; -} - -size_t PigeonInternalDeepHash(const PeripheralDescriptor& v) { - return v.Hash(); -} - -// PeripheralReadRequestResult - -PeripheralReadRequestResult::PeripheralReadRequestResult(const std::vector& value) - : value_(value) {} - -PeripheralReadRequestResult::PeripheralReadRequestResult( - const std::vector& value, - const int64_t* offset, - const int64_t* status) - : value_(value), - offset_(offset ? std::optional(*offset) : std::nullopt), - status_(status ? std::optional(*status) : std::nullopt) {} - -const std::vector& PeripheralReadRequestResult::value() const { - return value_; -} - -void PeripheralReadRequestResult::set_value(const std::vector& value_arg) { - value_ = value_arg; -} - - -const int64_t* PeripheralReadRequestResult::offset() const { - return offset_ ? &(*offset_) : nullptr; -} - -void PeripheralReadRequestResult::set_offset(const int64_t* value_arg) { - offset_ = value_arg ? std::optional(*value_arg) : std::nullopt; -} - -void PeripheralReadRequestResult::set_offset(int64_t value_arg) { - offset_ = value_arg; -} - - -const int64_t* PeripheralReadRequestResult::status() const { - return status_ ? &(*status_) : nullptr; -} - -void PeripheralReadRequestResult::set_status(const int64_t* value_arg) { - status_ = value_arg ? std::optional(*value_arg) : std::nullopt; -} - -void PeripheralReadRequestResult::set_status(int64_t value_arg) { - status_ = value_arg; -} - - -EncodableList PeripheralReadRequestResult::ToEncodableList() const { - EncodableList list; - list.reserve(3); - list.push_back(EncodableValue(value_)); - list.push_back(offset_ ? EncodableValue(*offset_) : EncodableValue()); - list.push_back(status_ ? EncodableValue(*status_) : EncodableValue()); - return list; -} - -PeripheralReadRequestResult PeripheralReadRequestResult::FromEncodableList(const EncodableList& list) { - PeripheralReadRequestResult decoded( - std::get>(list[0])); - auto& encodable_offset = list[1]; - if (!encodable_offset.IsNull()) { - decoded.set_offset(std::get(encodable_offset)); - } - auto& encodable_status = list[2]; - if (!encodable_status.IsNull()) { - decoded.set_status(std::get(encodable_status)); - } - return decoded; -} - -bool PeripheralReadRequestResult::operator==(const PeripheralReadRequestResult& other) const { - return PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(offset_, other.offset_) && PigeonInternalDeepEquals(status_, other.status_); -} - -bool PeripheralReadRequestResult::operator!=(const PeripheralReadRequestResult& other) const { - return !(*this == other); -} - -size_t PeripheralReadRequestResult::Hash() const { - size_t result = 1; - result = result * 31 + PigeonInternalDeepHash(value_); - result = result * 31 + PigeonInternalDeepHash(offset_); - result = result * 31 + PigeonInternalDeepHash(status_); - return result; -} - -size_t PigeonInternalDeepHash(const PeripheralReadRequestResult& v) { - return v.Hash(); -} - -// PeripheralWriteRequestResult - -PeripheralWriteRequestResult::PeripheralWriteRequestResult() {} - -PeripheralWriteRequestResult::PeripheralWriteRequestResult( - const std::vector* value, - const int64_t* offset, - const int64_t* status) - : value_(value ? std::optional>(*value) : std::nullopt), - offset_(offset ? std::optional(*offset) : std::nullopt), - status_(status ? std::optional(*status) : std::nullopt) {} - -const std::vector* PeripheralWriteRequestResult::value() const { - return value_ ? &(*value_) : nullptr; -} - -void PeripheralWriteRequestResult::set_value(const std::vector* value_arg) { - value_ = value_arg ? std::optional>(*value_arg) : std::nullopt; -} - -void PeripheralWriteRequestResult::set_value(const std::vector& value_arg) { - value_ = value_arg; -} - - -const int64_t* PeripheralWriteRequestResult::offset() const { - return offset_ ? &(*offset_) : nullptr; -} - -void PeripheralWriteRequestResult::set_offset(const int64_t* value_arg) { - offset_ = value_arg ? std::optional(*value_arg) : std::nullopt; -} - -void PeripheralWriteRequestResult::set_offset(int64_t value_arg) { - offset_ = value_arg; -} - - -const int64_t* PeripheralWriteRequestResult::status() const { - return status_ ? &(*status_) : nullptr; -} - -void PeripheralWriteRequestResult::set_status(const int64_t* value_arg) { - status_ = value_arg ? std::optional(*value_arg) : std::nullopt; -} - -void PeripheralWriteRequestResult::set_status(int64_t value_arg) { - status_ = value_arg; -} - - -EncodableList PeripheralWriteRequestResult::ToEncodableList() const { - EncodableList list; - list.reserve(3); - list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); - list.push_back(offset_ ? EncodableValue(*offset_) : EncodableValue()); - list.push_back(status_ ? EncodableValue(*status_) : EncodableValue()); - return list; -} - -PeripheralWriteRequestResult PeripheralWriteRequestResult::FromEncodableList(const EncodableList& list) { - PeripheralWriteRequestResult decoded; - auto& encodable_value = list[0]; - if (!encodable_value.IsNull()) { - decoded.set_value(std::get>(encodable_value)); - } - auto& encodable_offset = list[1]; - if (!encodable_offset.IsNull()) { - decoded.set_offset(std::get(encodable_offset)); - } - auto& encodable_status = list[2]; - if (!encodable_status.IsNull()) { - decoded.set_status(std::get(encodable_status)); - } - return decoded; -} - -bool PeripheralWriteRequestResult::operator==(const PeripheralWriteRequestResult& other) const { - return PigeonInternalDeepEquals(value_, other.value_) && PigeonInternalDeepEquals(offset_, other.offset_) && PigeonInternalDeepEquals(status_, other.status_); -} - -bool PeripheralWriteRequestResult::operator!=(const PeripheralWriteRequestResult& other) const { - return !(*this == other); -} - -size_t PeripheralWriteRequestResult::Hash() const { - size_t result = 1; - result = result * 31 + PigeonInternalDeepHash(value_); - result = result * 31 + PigeonInternalDeepHash(offset_); - result = result * 31 + PigeonInternalDeepHash(status_); - return result; -} - -size_t PigeonInternalDeepHash(const PeripheralWriteRequestResult& v) { - return v.Hash(); -} - -// PeripheralManufacturerData - -PeripheralManufacturerData::PeripheralManufacturerData( - int64_t manufacturer_id, - const std::vector& data) - : manufacturer_id_(manufacturer_id), - data_(data) {} - -int64_t PeripheralManufacturerData::manufacturer_id() const { - return manufacturer_id_; -} - -void PeripheralManufacturerData::set_manufacturer_id(int64_t value_arg) { - manufacturer_id_ = value_arg; -} - - -const std::vector& PeripheralManufacturerData::data() const { - return data_; -} - -void PeripheralManufacturerData::set_data(const std::vector& value_arg) { - data_ = value_arg; -} - - -EncodableList PeripheralManufacturerData::ToEncodableList() const { - EncodableList list; - list.reserve(2); - list.push_back(EncodableValue(manufacturer_id_)); - list.push_back(EncodableValue(data_)); - return list; -} - -PeripheralManufacturerData PeripheralManufacturerData::FromEncodableList(const EncodableList& list) { - PeripheralManufacturerData decoded( - std::get(list[0]), - std::get>(list[1])); - return decoded; -} - -bool PeripheralManufacturerData::operator==(const PeripheralManufacturerData& other) const { - return PigeonInternalDeepEquals(manufacturer_id_, other.manufacturer_id_) && PigeonInternalDeepEquals(data_, other.data_); -} - -bool PeripheralManufacturerData::operator!=(const PeripheralManufacturerData& other) const { - return !(*this == other); -} - -size_t PeripheralManufacturerData::Hash() const { - size_t result = 1; - result = result * 31 + PigeonInternalDeepHash(manufacturer_id_); - result = result * 31 + PigeonInternalDeepHash(data_); - return result; -} - -size_t PigeonInternalDeepHash(const PeripheralManufacturerData& v) { - return v.Hash(); -} - - -PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} - -EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, - ::flutter::ByteStreamReader* stream) const { - switch (type) { - case 129: { - 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(enum_arg_value)); - } - case 130: { - return CustomEncodableValue(PeripheralService::FromEncodableList(std::get(ReadValue(stream)))); - } - case 131: { - return CustomEncodableValue(PeripheralCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); - } - case 132: { - return CustomEncodableValue(PeripheralDescriptor::FromEncodableList(std::get(ReadValue(stream)))); - } - case 133: { - return CustomEncodableValue(PeripheralReadRequestResult::FromEncodableList(std::get(ReadValue(stream)))); - } - case 134: { - return CustomEncodableValue(PeripheralWriteRequestResult::FromEncodableList(std::get(ReadValue(stream)))); - } - case 135: { - return CustomEncodableValue(PeripheralManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); - } - default: - return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); - } -} - -void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, - ::flutter::ByteStreamWriter* stream) const { - if (const CustomEncodableValue* custom_value = std::get_if(&value)) { - if (custom_value->type() == typeid(PeripheralBondState)) { - stream->WriteByte(129); - WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); - return; - } - if (custom_value->type() == typeid(PeripheralService)) { - stream->WriteByte(130); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(PeripheralCharacteristic)) { - stream->WriteByte(131); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(PeripheralDescriptor)) { - stream->WriteByte(132); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(PeripheralReadRequestResult)) { - stream->WriteByte(133); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(PeripheralWriteRequestResult)) { - stream->WriteByte(134); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - if (custom_value->type() == typeid(PeripheralManufacturerData)) { - stream->WriteByte(135); - WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); - return; - } - } - ::flutter::StandardCodecSerializer::WriteValue(value, stream); -} - -/// The codec used by UniversalBlePeripheralChannel. -const ::flutter::StandardMessageCodec& UniversalBlePeripheralChannel::GetCodec() { - return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); -} - -// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. -void UniversalBlePeripheralChannel::SetUp( - ::flutter::BinaryMessenger* binary_messenger, - UniversalBlePeripheralChannel* api) { - UniversalBlePeripheralChannel::SetUp(binary_messenger, api, ""); -} - -void UniversalBlePeripheralChannel::SetUp( - ::flutter::BinaryMessenger* binary_messenger, - UniversalBlePeripheralChannel* api, - const std::string& message_channel_suffix) { - const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - std::optional output = api->Initialize(); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - ErrorOr> output = api->IsAdvertising(); - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - auto output_optional = std::move(output).TakeValue(); - if (output_optional) { - wrapped.push_back(EncodableValue(std::move(output_optional).value())); - } else { - wrapped.push_back(EncodableValue()); - } - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - ErrorOr output = api->IsSupported(); - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - std::optional output = api->StopAdvertising(); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_service_arg = args.at(0); - if (encodable_service_arg.IsNull()) { - reply(WrapError("service_arg unexpectedly null.")); - return; - } - const auto& service_arg = std::any_cast(std::get(encodable_service_arg)); - std::optional output = api->AddService(service_arg); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_service_id_arg = args.at(0); - if (encodable_service_id_arg.IsNull()) { - reply(WrapError("service_id_arg unexpectedly null.")); - return; - } - const auto& service_id_arg = std::get(encodable_service_id_arg); - std::optional output = api->RemoveService(service_id_arg); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - std::optional output = api->ClearServices(); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - ErrorOr output = api->GetServices(); - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_services_arg = args.at(0); - if (encodable_services_arg.IsNull()) { - reply(WrapError("services_arg unexpectedly null.")); - return; - } - const auto& services_arg = std::get(encodable_services_arg); - const auto& encodable_local_name_arg = args.at(1); - const auto* local_name_arg = std::get_if(&encodable_local_name_arg); - const auto& encodable_timeout_arg = args.at(2); - const auto* timeout_arg = std::get_if(&encodable_timeout_arg); - const auto& encodable_manufacturer_data_arg = args.at(3); - const auto* manufacturer_data_arg = encodable_manufacturer_data_arg.IsNull() ? nullptr : &(std::any_cast(std::get(encodable_manufacturer_data_arg))); - const auto& encodable_add_manufacturer_data_in_scan_response_arg = args.at(4); - if (encodable_add_manufacturer_data_in_scan_response_arg.IsNull()) { - reply(WrapError("add_manufacturer_data_in_scan_response_arg unexpectedly null.")); - return; - } - const auto& add_manufacturer_data_in_scan_response_arg = std::get(encodable_add_manufacturer_data_in_scan_response_arg); - std::optional output = api->StartAdvertising(services_arg, local_name_arg, timeout_arg, manufacturer_data_arg, add_manufacturer_data_in_scan_response_arg); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_characteristic_id_arg = args.at(0); - if (encodable_characteristic_id_arg.IsNull()) { - reply(WrapError("characteristic_id_arg unexpectedly null.")); - return; - } - const auto& characteristic_id_arg = std::get(encodable_characteristic_id_arg); - const auto& encodable_value_arg = args.at(1); - if (encodable_value_arg.IsNull()) { - reply(WrapError("value_arg unexpectedly null.")); - return; - } - const auto& value_arg = std::get>(encodable_value_arg); - const auto& encodable_device_id_arg = args.at(2); - const auto* device_id_arg = std::get_if(&encodable_device_id_arg); - std::optional output = api->UpdateCharacteristic(characteristic_id_arg, value_arg, device_id_arg); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_characteristic_id_arg = args.at(0); - if (encodable_characteristic_id_arg.IsNull()) { - reply(WrapError("characteristic_id_arg unexpectedly null.")); - return; - } - const auto& characteristic_id_arg = std::get(encodable_characteristic_id_arg); - ErrorOr output = api->GetSubscribedCentrals(characteristic_id_arg); - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } -} - -EncodableValue UniversalBlePeripheralChannel::WrapError(std::string_view error_message) { - return EncodableValue(EncodableList{ - EncodableValue(std::string(error_message)), - EncodableValue("Error"), - EncodableValue() - }); -} - -EncodableValue UniversalBlePeripheralChannel::WrapError(const FlutterError& error) { - return EncodableValue(EncodableList{ - EncodableValue(error.code()), - EncodableValue(error.message()), - error.details() - }); -} - -// Generated class from Pigeon that represents Flutter messages that can be called from C++. -UniversalBlePeripheralCallback::UniversalBlePeripheralCallback(::flutter::BinaryMessenger* binary_messenger) - : binary_messenger_(binary_messenger), - message_channel_suffix_("") {} - -UniversalBlePeripheralCallback::UniversalBlePeripheralCallback( - ::flutter::BinaryMessenger* binary_messenger, - const std::string& message_channel_suffix) - : binary_messenger_(binary_messenger), - message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} - -const ::flutter::StandardMessageCodec& UniversalBlePeripheralCallback::GetCodec() { - return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); -} - -void UniversalBlePeripheralCallback::OnReadRequest( - const std::string& device_id_arg, - const std::string& characteristic_id_arg, - int64_t offset_arg, - const std::vector* value_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(device_id_arg), - EncodableValue(characteristic_id_arg), - EncodableValue(offset_arg), - value_arg ? EncodableValue(*value_arg) : EncodableValue(), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); - on_success(return_value); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - -void UniversalBlePeripheralCallback::OnWriteRequest( - const std::string& device_id_arg, - const std::string& characteristic_id_arg, - int64_t offset_arg, - const std::vector* value_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(device_id_arg), - EncodableValue(characteristic_id_arg), - EncodableValue(offset_arg), - value_arg ? EncodableValue(*value_arg) : EncodableValue(), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); - on_success(return_value); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - -void UniversalBlePeripheralCallback::OnCharacteristicSubscriptionChange( - const std::string& device_id_arg, - const std::string& characteristic_id_arg, - bool is_subscribed_arg, - const std::string* name_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(device_id_arg), - EncodableValue(characteristic_id_arg), - EncodableValue(is_subscribed_arg), - name_arg ? EncodableValue(*name_arg) : EncodableValue(), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - on_success(); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - -void UniversalBlePeripheralCallback::OnAdvertisingStatusUpdate( - bool advertising_arg, - const std::string* error_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(advertising_arg), - error_arg ? EncodableValue(*error_arg) : EncodableValue(), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - on_success(); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - -void UniversalBlePeripheralCallback::OnServiceAdded( - const std::string& service_id_arg, - const std::string* error_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(service_id_arg), - error_arg ? EncodableValue(*error_arg) : EncodableValue(), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - on_success(); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - -void UniversalBlePeripheralCallback::OnMtuChange( - const std::string& device_id_arg, - int64_t mtu_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(device_id_arg), - EncodableValue(mtu_arg), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - on_success(); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - -void UniversalBlePeripheralCallback::OnConnectionStateChange( - const std::string& device_id_arg, - bool connected_arg, - std::function&& on_success, - std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange" + message_channel_suffix_; - BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); - EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(device_id_arg), - EncodableValue(connected_arg), - }); - channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { - std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); - const auto& encodable_return_value = *response; - const auto* list_return_value = std::get_if(&encodable_return_value); - if (list_return_value) { - if (list_return_value->size() > 1) { - on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); - } else { - on_success(); - } - } else { - on_error(CreateConnectionError(channel_name)); - } - }); -} - -} // namespace universal_ble diff --git a/windows/src/generated/universal_ble_peripheral.g.h b/windows/src/generated/universal_ble_peripheral.g.h deleted file mode 100644 index c0b79a1a..00000000 --- a/windows/src/generated/universal_ble_peripheral.g.h +++ /dev/null @@ -1,415 +0,0 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. -// See also: https://pub.dev/packages/pigeon - -#ifndef PIGEON_UNIVERSAL_BLE_PERIPHERAL_G_H_ -#define PIGEON_UNIVERSAL_BLE_PERIPHERAL_G_H_ -#include -#include -#include -#include - -#include -#include -#include - -namespace universal_ble { - - -// Generated class from Pigeon. - -class FlutterError { - public: - explicit FlutterError(const std::string& code) - : code_(code) {} - explicit FlutterError(const std::string& code, const std::string& message) - : code_(code), message_(message) {} - explicit FlutterError(const std::string& code, const std::string& message, const ::flutter::EncodableValue& details) - : code_(code), message_(message), details_(details) {} - - const std::string& code() const { return code_; } - const std::string& message() const { return message_; } - const ::flutter::EncodableValue& details() const { return details_; } - - private: - std::string code_; - std::string message_; - ::flutter::EncodableValue details_; -}; - -template class ErrorOr { - public: - ErrorOr(const T& rhs) : v_(rhs) {} - ErrorOr(const T&& rhs) : v_(std::move(rhs)) {} - ErrorOr(const FlutterError& rhs) : v_(rhs) {} - ErrorOr(const FlutterError&& rhs) : v_(std::move(rhs)) {} - - bool has_error() const { return std::holds_alternative(v_); } - const T& value() const { return std::get(v_); }; - const FlutterError& error() const { return std::get(v_); }; - - private: - friend class UniversalBlePeripheralChannel; - friend class UniversalBlePeripheralCallback; - ErrorOr() = default; - T TakeValue() && { return std::get(std::move(v_)); } - - std::variant v_; -}; - - -enum class PeripheralBondState { - kBonding = 0, - kBonded = 1, - kNone = 2 -}; - - -// Generated class from Pigeon that represents data sent in messages. -class PeripheralService { - public: - // Constructs an object setting all fields. - explicit PeripheralService( - const std::string& uuid, - bool primary, - const ::flutter::EncodableList& characteristics); - - const std::string& uuid() const; - void set_uuid(std::string_view value_arg); - - bool primary() const; - void set_primary(bool value_arg); - - const ::flutter::EncodableList& characteristics() const; - void set_characteristics(const ::flutter::EncodableList& value_arg); - - bool operator==(const PeripheralService& other) const; - bool operator!=(const PeripheralService& other) const; - /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. - size_t Hash() const; - private: - static PeripheralService FromEncodableList(const ::flutter::EncodableList& list); - ::flutter::EncodableList ToEncodableList() const; - friend class UniversalBlePeripheralChannel; - friend class UniversalBlePeripheralCallback; - friend class PigeonInternalCodecSerializer; - std::string uuid_; - bool primary_; - ::flutter::EncodableList characteristics_; -}; - - -// Generated class from Pigeon that represents data sent in messages. -class PeripheralCharacteristic { - public: - // Constructs an object setting all non-nullable fields. - explicit PeripheralCharacteristic( - const std::string& uuid, - const ::flutter::EncodableList& properties, - const ::flutter::EncodableList& permissions); - - // Constructs an object setting all fields. - explicit PeripheralCharacteristic( - const std::string& uuid, - const ::flutter::EncodableList& properties, - const ::flutter::EncodableList& permissions, - const ::flutter::EncodableList* descriptors, - const std::vector* value); - - const std::string& uuid() const; - void set_uuid(std::string_view value_arg); - - const ::flutter::EncodableList& properties() const; - void set_properties(const ::flutter::EncodableList& value_arg); - - const ::flutter::EncodableList& permissions() const; - void set_permissions(const ::flutter::EncodableList& value_arg); - - const ::flutter::EncodableList* descriptors() const; - void set_descriptors(const ::flutter::EncodableList* value_arg); - void set_descriptors(const ::flutter::EncodableList& value_arg); - - const std::vector* value() const; - void set_value(const std::vector* value_arg); - void set_value(const std::vector& value_arg); - - bool operator==(const PeripheralCharacteristic& other) const; - bool operator!=(const PeripheralCharacteristic& other) const; - /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. - size_t Hash() const; - private: - static PeripheralCharacteristic FromEncodableList(const ::flutter::EncodableList& list); - ::flutter::EncodableList ToEncodableList() const; - friend class UniversalBlePeripheralChannel; - friend class UniversalBlePeripheralCallback; - friend class PigeonInternalCodecSerializer; - std::string uuid_; - ::flutter::EncodableList properties_; - ::flutter::EncodableList permissions_; - std::optional<::flutter::EncodableList> descriptors_; - std::optional> value_; -}; - - -// Generated class from Pigeon that represents data sent in messages. -class PeripheralDescriptor { - public: - // Constructs an object setting all non-nullable fields. - explicit PeripheralDescriptor(const std::string& uuid); - - // Constructs an object setting all fields. - explicit PeripheralDescriptor( - const std::string& uuid, - const std::vector* value, - const ::flutter::EncodableList* permissions); - - const std::string& uuid() const; - void set_uuid(std::string_view value_arg); - - const std::vector* value() const; - void set_value(const std::vector* value_arg); - void set_value(const std::vector& value_arg); - - const ::flutter::EncodableList* permissions() const; - void set_permissions(const ::flutter::EncodableList* value_arg); - void set_permissions(const ::flutter::EncodableList& value_arg); - - bool operator==(const PeripheralDescriptor& other) const; - bool operator!=(const PeripheralDescriptor& other) const; - /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. - size_t Hash() const; - private: - static PeripheralDescriptor FromEncodableList(const ::flutter::EncodableList& list); - ::flutter::EncodableList ToEncodableList() const; - friend class UniversalBlePeripheralChannel; - friend class UniversalBlePeripheralCallback; - friend class PigeonInternalCodecSerializer; - std::string uuid_; - std::optional> value_; - std::optional<::flutter::EncodableList> permissions_; -}; - - -// Generated class from Pigeon that represents data sent in messages. -class PeripheralReadRequestResult { - public: - // Constructs an object setting all non-nullable fields. - explicit PeripheralReadRequestResult(const std::vector& value); - - // Constructs an object setting all fields. - explicit PeripheralReadRequestResult( - const std::vector& value, - const int64_t* offset, - const int64_t* status); - - const std::vector& value() const; - void set_value(const std::vector& value_arg); - - const int64_t* offset() const; - void set_offset(const int64_t* value_arg); - void set_offset(int64_t value_arg); - - const int64_t* status() const; - void set_status(const int64_t* value_arg); - void set_status(int64_t value_arg); - - bool operator==(const PeripheralReadRequestResult& other) const; - bool operator!=(const PeripheralReadRequestResult& other) const; - /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. - size_t Hash() const; - private: - static PeripheralReadRequestResult FromEncodableList(const ::flutter::EncodableList& list); - ::flutter::EncodableList ToEncodableList() const; - friend class UniversalBlePeripheralChannel; - friend class UniversalBlePeripheralCallback; - friend class PigeonInternalCodecSerializer; - std::vector value_; - std::optional offset_; - std::optional status_; -}; - - -// Generated class from Pigeon that represents data sent in messages. -class PeripheralWriteRequestResult { - public: - // Constructs an object setting all non-nullable fields. - PeripheralWriteRequestResult(); - - // Constructs an object setting all fields. - explicit PeripheralWriteRequestResult( - const std::vector* value, - const int64_t* offset, - const int64_t* status); - - const std::vector* value() const; - void set_value(const std::vector* value_arg); - void set_value(const std::vector& value_arg); - - const int64_t* offset() const; - void set_offset(const int64_t* value_arg); - void set_offset(int64_t value_arg); - - const int64_t* status() const; - void set_status(const int64_t* value_arg); - void set_status(int64_t value_arg); - - bool operator==(const PeripheralWriteRequestResult& other) const; - bool operator!=(const PeripheralWriteRequestResult& other) const; - /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. - size_t Hash() const; - private: - static PeripheralWriteRequestResult FromEncodableList(const ::flutter::EncodableList& list); - ::flutter::EncodableList ToEncodableList() const; - friend class UniversalBlePeripheralChannel; - friend class UniversalBlePeripheralCallback; - friend class PigeonInternalCodecSerializer; - std::optional> value_; - std::optional offset_; - std::optional status_; -}; - - -// Generated class from Pigeon that represents data sent in messages. -class PeripheralManufacturerData { - public: - // Constructs an object setting all fields. - explicit PeripheralManufacturerData( - int64_t manufacturer_id, - const std::vector& data); - - int64_t manufacturer_id() const; - void set_manufacturer_id(int64_t value_arg); - - const std::vector& data() const; - void set_data(const std::vector& value_arg); - - bool operator==(const PeripheralManufacturerData& other) const; - bool operator!=(const PeripheralManufacturerData& other) const; - /// Returns a hash code value for the object. This method is supported for the benefit of hash tables. - size_t Hash() const; - private: - static PeripheralManufacturerData FromEncodableList(const ::flutter::EncodableList& list); - ::flutter::EncodableList ToEncodableList() const; - friend class UniversalBlePeripheralChannel; - friend class UniversalBlePeripheralCallback; - friend class PigeonInternalCodecSerializer; - int64_t manufacturer_id_; - std::vector data_; -}; - - -class PigeonInternalCodecSerializer : public ::flutter::StandardCodecSerializer { - public: - PigeonInternalCodecSerializer(); - inline static PigeonInternalCodecSerializer& GetInstance() { - static PigeonInternalCodecSerializer sInstance; - return sInstance; - } - - void WriteValue( - const ::flutter::EncodableValue& value, - ::flutter::ByteStreamWriter* stream) const override; - protected: - ::flutter::EncodableValue ReadValueOfType( - uint8_t type, - ::flutter::ByteStreamReader* stream) const override; -}; - -// Generated interface from Pigeon that represents a handler of messages from Flutter. -class UniversalBlePeripheralChannel { - public: - UniversalBlePeripheralChannel(const UniversalBlePeripheralChannel&) = delete; - UniversalBlePeripheralChannel& operator=(const UniversalBlePeripheralChannel&) = delete; - virtual ~UniversalBlePeripheralChannel() {} - virtual std::optional Initialize() = 0; - virtual ErrorOr> IsAdvertising() = 0; - virtual ErrorOr IsSupported() = 0; - virtual std::optional StopAdvertising() = 0; - virtual std::optional AddService(const PeripheralService& service) = 0; - virtual std::optional RemoveService(const std::string& service_id) = 0; - virtual std::optional ClearServices() = 0; - virtual ErrorOr<::flutter::EncodableList> GetServices() = 0; - virtual std::optional StartAdvertising( - const ::flutter::EncodableList& services, - const std::string* local_name, - const int64_t* timeout, - const PeripheralManufacturerData* manufacturer_data, - bool add_manufacturer_data_in_scan_response) = 0; - virtual std::optional UpdateCharacteristic( - const std::string& characteristic_id, - const std::vector& value, - const std::string* device_id) = 0; - // Returns peripheral-central device ids currently subscribed to [characteristicId] - // (e.g. HID report characteristic). Used to restore app state after restart. - virtual ErrorOr<::flutter::EncodableList> GetSubscribedCentrals(const std::string& characteristic_id) = 0; - - // The codec used by UniversalBlePeripheralChannel. - static const ::flutter::StandardMessageCodec& GetCodec(); - // Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binary_messenger`. - static void SetUp( - ::flutter::BinaryMessenger* binary_messenger, - UniversalBlePeripheralChannel* api); - static void SetUp( - ::flutter::BinaryMessenger* binary_messenger, - UniversalBlePeripheralChannel* api, - const std::string& message_channel_suffix); - static ::flutter::EncodableValue WrapError(std::string_view error_message); - static ::flutter::EncodableValue WrapError(const FlutterError& error); - protected: - UniversalBlePeripheralChannel() = default; -}; -// Generated class from Pigeon that represents Flutter messages that can be called from C++. -class UniversalBlePeripheralCallback { - public: - UniversalBlePeripheralCallback(::flutter::BinaryMessenger* binary_messenger); - UniversalBlePeripheralCallback( - ::flutter::BinaryMessenger* binary_messenger, - const std::string& message_channel_suffix); - static const ::flutter::StandardMessageCodec& GetCodec(); - void OnReadRequest( - const std::string& device_id, - const std::string& characteristic_id, - int64_t offset, - const std::vector* value, - std::function&& on_success, - std::function&& on_error); - void OnWriteRequest( - const std::string& device_id, - const std::string& characteristic_id, - int64_t offset, - const std::vector* value, - std::function&& on_success, - std::function&& on_error); - void OnCharacteristicSubscriptionChange( - const std::string& device_id, - const std::string& characteristic_id, - bool is_subscribed, - const std::string* name, - std::function&& on_success, - std::function&& on_error); - void OnAdvertisingStatusUpdate( - bool advertising, - const std::string* error, - std::function&& on_success, - std::function&& on_error); - void OnServiceAdded( - const std::string& service_id, - const std::string* error, - std::function&& on_success, - std::function&& on_error); - void OnMtuChange( - const std::string& device_id, - int64_t mtu, - std::function&& on_success, - std::function&& on_error); - void OnConnectionStateChange( - const std::string& device_id, - bool connected, - std::function&& on_success, - std::function&& on_error); - private: - ::flutter::BinaryMessenger* binary_messenger_; - std::string message_channel_suffix_; -}; - -} // namespace universal_ble -#endif // PIGEON_UNIVERSAL_BLE_PERIPHERAL_G_H_ diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index d8582082..8e81c183 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -14,7 +14,6 @@ #include "enum_parser.h" #include "generated/universal_ble.g.h" -#include "generated/universal_ble_peripheral.g.h" #include "helper/universal_ble_logger.h" #include "helper/universal_enum.h" #include "helper/utils.h" diff --git a/windows/src/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h index deb4ce79..6f7fd6c1 100644 --- a/windows/src/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -16,7 +16,6 @@ #include #include "generated/universal_ble.g.h" -#include "generated/universal_ble_peripheral.g.h" #include "helper/universal_ble_base.h" #include "helper/universal_enum.h" #include "helper/utils.h" From 60870602d6d534c4207418227eed0520bc818789 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 12:03:02 +0200 Subject: [PATCH 13/23] Fix compilation --- .../universal_ble/UniversalBlePeripheralPlugin.swift | 6 ++++++ example/macos/Podfile.lock | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 67e8d2bd..8387710f 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -142,6 +142,12 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne ) { _ in } } + nonisolated func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { + if peripheral.state != .poweredOn { + callbackChannel.onAdvertisingStatusUpdate(advertising: false, error: nil) { _ in } + } + } + nonisolated func peripheralManager( _: CBPeripheralManager, didAdd service: CBService, diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index cffb3dba..f496afd0 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -1,27 +1,20 @@ PODS: - - ble_peripheral (0.0.1): - - Flutter - - FlutterMacOS - FlutterMacOS (1.0.0) - universal_ble (0.0.1): - Flutter - FlutterMacOS DEPENDENCIES: - - ble_peripheral (from `Flutter/ephemeral/.symlinks/plugins/ble_peripheral/darwin`) - FlutterMacOS (from `Flutter/ephemeral`) - universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`) EXTERNAL SOURCES: - ble_peripheral: - :path: Flutter/ephemeral/.symlinks/plugins/ble_peripheral/darwin FlutterMacOS: :path: Flutter/ephemeral universal_ble: :path: Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin SPEC CHECKSUMS: - ble_peripheral: 1d6cb378caaef61cd39410652a4de1a68dfba4f2 FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914 From 20ca418dd23abc64c3bae13bf7b675416e1ff8d1 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 14:22:57 +0200 Subject: [PATCH 14/23] Remove initialize API --- README.md | 1 - .../navideck/universal_ble/UniversalBle.g.kt | 17 - .../UniversalBlePeripheralPlugin.kt | 19 +- .../universal_ble/UniversalBle.g.swift | 14 - .../UniversalBlePeripheralPlugin.swift | 5 +- example/lib/peripheral/peripheral_home.dart | 5 +- .../universal_ble_peripheral.dart | 1 - .../universal_ble_peripheral_pigeon.dart | 3 - ...sal_ble_peripheral_platform_interface.dart | 6 - .../universal_ble_pigeon/universal_ble.g.dart | 845 +++++++----------- pigeon/universal_ble.dart | 1 - windows/src/generated/universal_ble.g.cpp | 21 - windows/src/generated/universal_ble.g.h | 1 - 13 files changed, 361 insertions(+), 578 deletions(-) diff --git a/README.md b/README.md index 50de1d23..2ee98dd1 100644 --- a/README.md +++ b/README.md @@ -636,7 +636,6 @@ The error parser automatically converts platform-specific error formats (strings ```dart import 'package:universal_ble/universal_ble.dart'; -await UniversalBlePeripheral.initialize(); await UniversalBlePeripheral.addService( BleService("0000180F-0000-1000-8000-00805F9B34FB", [ BleCharacteristic( diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt index 0e4dc7db..c94d538c 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt @@ -1698,7 +1698,6 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger, * Generated interface from Pigeon that represents a handler of messages from Flutter. */ interface UniversalBlePeripheralChannel { - fun initialize() fun isAdvertising(): Boolean? fun isSupported(): Boolean fun stopAdvertising() @@ -1723,22 +1722,6 @@ interface UniversalBlePeripheralChannel { @JvmOverloads fun setUp(binaryMessenger: BinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - api.initialize() - listOf(null) - } catch (exception: Throwable) { - UniversalBlePigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$separatedMessageChannelSuffix", codec) if (api != null) { diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index 54ca4484..bb62b010 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -49,6 +49,12 @@ class UniversalBlePeripheralPlugin( private var originalAdapterName: String? = null private var adapterNameOverridden = false + init { + kotlin.runCatching { initializePeripheral() }.onFailure { + Log.w(TAG, "Deferred peripheral init: ${it.message}") + } + } + fun attachActivity(activity: Activity?) { this.activity = activity } @@ -69,9 +75,10 @@ class UniversalBlePeripheralPlugin( clearPeripheralCaches() } - override fun initialize() { + private fun initializePeripheral() { val adapter = bluetoothManager.adapter ?: throw UnsupportedOperationException("Bluetooth is not available.") + if (bluetoothLeAdvertiser != null && gattServer != null && receiverRegistered) return bluetoothLeAdvertiser = adapter.bluetoothLeAdvertiser ?: throw UnsupportedOperationException( "Bluetooth LE Advertising not supported on this device.", @@ -106,6 +113,7 @@ class UniversalBlePeripheralPlugin( } override fun addService(service: PeripheralService) { + initializePeripheral() gattServer?.addService(service.toGattService()) } @@ -114,11 +122,15 @@ class UniversalBlePeripheralPlugin( } override fun clearServices() { + initializePeripheral() gattServer?.clearServices() } override fun getServices(): List = - gattServer?.services?.map { it.uuid.toString() } ?: emptyList() + runCatching { + initializePeripheral() + gattServer?.services?.map { it.uuid.toString() } ?: emptyList() + }.getOrDefault(emptyList()) override fun startAdvertising( services: List, @@ -127,6 +139,7 @@ class UniversalBlePeripheralPlugin( manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Boolean, ) { + initializePeripheral() if (!isBluetoothEnabled()) { activity?.startActivityForResult( Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), @@ -183,6 +196,7 @@ class UniversalBlePeripheralPlugin( } override fun stopAdvertising() { + initializePeripheral() handler.post { bluetoothLeAdvertiser?.stopAdvertising(advertiseCallback) restoreAdapterNameIfNeeded() @@ -192,6 +206,7 @@ class UniversalBlePeripheralPlugin( } override fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) { + initializePeripheral() val characteristic = characteristicId.findCharacteristic() ?: throw Exception("Characteristic not found") characteristic.value = value diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift index 6132c78f..92377968 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift @@ -1547,7 +1547,6 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol { /// /// Generated protocol from Pigeon that represents a handler of messages from Flutter. protocol UniversalBlePeripheralChannel { - func initialize() throws func isAdvertising() throws -> Bool? func isSupported() throws -> Bool func stopAdvertising() throws @@ -1568,19 +1567,6 @@ class UniversalBlePeripheralChannelSetup { /// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" - let initializeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - initializeChannel.setMessageHandler { _, reply in - do { - try api.initialize() - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - initializeChannel.setMessageHandler(nil) - } let isAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { isAdvertisingChannel.setMessageHandler { _, reply in diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 8387710f..8be383d5 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -20,6 +20,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne init(callbackChannel: UniversalBlePeripheralCallback) { self.callbackChannel = callbackChannel super.init() + _ = peripheralManager.isAdvertising } deinit { @@ -29,10 +30,6 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne clearCentrals() } - func initialize() throws { - _ = peripheralManager.isAdvertising - } - func isSupported() throws -> Bool { true } diff --git a/example/lib/peripheral/peripheral_home.dart b/example/lib/peripheral/peripheral_home.dart index 40cbccb0..d07946a5 100644 --- a/example/lib/peripheral/peripheral_home.dart +++ b/example/lib/peripheral/peripheral_home.dart @@ -66,12 +66,11 @@ class _PeripheralHomeState extends State { } Future _initialize() async { - await UniversalBlePeripheral.initialize(); final supported = await UniversalBlePeripheral.isSupported(); setState(() { - _initialized = true; + _initialized = supported; }); - _log('Peripheral initialized. supported=$supported'); + _log('Peripheral ready check. supported=$supported'); } Future _addServices() async { diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart index 1b8f72db..f86bf0a9 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -17,7 +17,6 @@ class UniversalBlePeripheral { _platform = instance; } - static Future initialize() => _platform.initialize(); static Future isSupported() => _platform.isSupported(); static Future isAdvertising() => _platform.isAdvertising(); diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index 371b135b..0678be48 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -22,9 +22,6 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform StreamController<({String serviceId, String? error})>.broadcast(); bool _disposed = false; - @override - Future initialize() => _channel.initialize(); - @override Future isSupported() => _channel.isSupported(); diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart index fd8634ba..73976e40 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -39,7 +39,6 @@ abstract class UniversalBlePeripheralPlatform { OnPeripheralWriteRequest? writeRequestCallback; OnPeripheralMtuChange? mtuChangeCallback; - Future initialize(); Future isSupported(); Future isAdvertising(); @@ -98,11 +97,6 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { throw _notSupported(); } - @override - Future initialize() async { - throw _notSupported(); - } - @override Future isAdvertising() async { throw _notSupported(); diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index 57a8fa12..8bc0fefc 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -10,9 +10,9 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; Object? _extractReplyValueOrThrow( - List? replyList, - String channelName, { - required bool isNullValid, + List? replyList, + String channelName, { + required bool isNullValid, }) { if (replyList == null) { throw PlatformException( @@ -34,8 +34,8 @@ Object? _extractReplyValueOrThrow( return replyList.firstOrNull; } -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { + +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -44,7 +44,6 @@ List wrapResponse( } return [error.code, error.message, error.details]; } - bool _deepEquals(Object? a, Object? b) { if (identical(a, b)) { return true; @@ -107,6 +106,7 @@ int _deepHash(Object? value) { return value.hashCode; } + enum UniversalBleLogLevel { none, error, @@ -231,8 +231,7 @@ class UniversalBleScanResult { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalBleScanResult decode(Object result) { result as List; @@ -241,10 +240,8 @@ class UniversalBleScanResult { name: result[1] as String?, isPaired: result[2] as bool?, rssi: result[3] as int?, - manufacturerDataList: - (result[4] as List?)?.cast(), - serviceData: - (result[5] as Map?)?.cast(), + manufacturerDataList: (result[4] as List?)?.cast(), + serviceData: (result[5] as Map?)?.cast(), services: (result[6] as List?)?.cast(), timestamp: result[7] as int?, ); @@ -259,14 +256,7 @@ class UniversalBleScanResult { if (identical(this, other)) { return true; } - return _deepEquals(deviceId, other.deviceId) && - _deepEquals(name, other.name) && - _deepEquals(isPaired, other.isPaired) && - _deepEquals(rssi, other.rssi) && - _deepEquals(manufacturerDataList, other.manufacturerDataList) && - _deepEquals(serviceData, other.serviceData) && - _deepEquals(services, other.services) && - _deepEquals(timestamp, other.timestamp); + return _deepEquals(deviceId, other.deviceId) && _deepEquals(name, other.name) && _deepEquals(isPaired, other.isPaired) && _deepEquals(rssi, other.rssi) && _deepEquals(manufacturerDataList, other.manufacturerDataList) && _deepEquals(serviceData, other.serviceData) && _deepEquals(services, other.services) && _deepEquals(timestamp, other.timestamp); } @override @@ -292,15 +282,13 @@ class UniversalBleService { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalBleService decode(Object result) { result as List; return UniversalBleService( uuid: result[0]! as String, - characteristics: - (result[1] as List?)?.cast(), + characteristics: (result[1] as List?)?.cast(), ); } @@ -313,8 +301,7 @@ class UniversalBleService { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(characteristics, other.characteristics); + return _deepEquals(uuid, other.uuid) && _deepEquals(characteristics, other.characteristics); } @override @@ -344,8 +331,7 @@ class UniversalBleCharacteristic { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalBleCharacteristic decode(Object result) { result as List; @@ -359,16 +345,13 @@ class UniversalBleCharacteristic { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! UniversalBleCharacteristic || - other.runtimeType != runtimeType) { + if (other is! UniversalBleCharacteristic || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(properties, other.properties) && - _deepEquals(descriptors, other.descriptors); + return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(descriptors, other.descriptors); } @override @@ -390,8 +373,7 @@ class UniversalBleDescriptor { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalBleDescriptor decode(Object result) { result as List; @@ -445,8 +427,7 @@ class AndroidOptions { } Object encode() { - return _toList(); - } + return _toList(); } static AndroidOptions decode(Object result) { result as List; @@ -466,10 +447,7 @@ class AndroidOptions { if (identical(this, other)) { return true; } - return _deepEquals( - requestLocationPermission, other.requestLocationPermission) && - _deepEquals(scanMode, other.scanMode) && - _deepEquals(reportDelayMillis, other.reportDelayMillis); + return _deepEquals(requestLocationPermission, other.requestLocationPermission) && _deepEquals(scanMode, other.scanMode) && _deepEquals(reportDelayMillis, other.reportDelayMillis); } @override @@ -491,8 +469,7 @@ class UniversalScanConfig { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalScanConfig decode(Object result) { result as List; @@ -541,16 +518,14 @@ class UniversalScanFilter { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalScanFilter decode(Object result) { result as List; return UniversalScanFilter( withServices: (result[0]! as List).cast(), withNamePrefix: (result[1]! as List).cast(), - withManufacturerData: - (result[2]! as List).cast(), + withManufacturerData: (result[2]! as List).cast(), ); } @@ -563,9 +538,7 @@ class UniversalScanFilter { if (identical(this, other)) { return true; } - return _deepEquals(withServices, other.withServices) && - _deepEquals(withNamePrefix, other.withNamePrefix) && - _deepEquals(withManufacturerData, other.withManufacturerData); + return _deepEquals(withServices, other.withServices) && _deepEquals(withNamePrefix, other.withNamePrefix) && _deepEquals(withManufacturerData, other.withManufacturerData); } @override @@ -595,8 +568,7 @@ class UniversalManufacturerDataFilter { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalManufacturerDataFilter decode(Object result) { result as List; @@ -610,16 +582,13 @@ class UniversalManufacturerDataFilter { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! UniversalManufacturerDataFilter || - other.runtimeType != runtimeType) { + if (other is! UniversalManufacturerDataFilter || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(companyIdentifier, other.companyIdentifier) && - _deepEquals(data, other.data) && - _deepEquals(mask, other.mask); + return _deepEquals(companyIdentifier, other.companyIdentifier) && _deepEquals(data, other.data) && _deepEquals(mask, other.mask); } @override @@ -645,8 +614,7 @@ class UniversalManufacturerData { } Object encode() { - return _toList(); - } + return _toList(); } static UniversalManufacturerData decode(Object result) { result as List; @@ -659,15 +627,13 @@ class UniversalManufacturerData { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! UniversalManufacturerData || - other.runtimeType != runtimeType) { + if (other is! UniversalManufacturerData || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(companyIdentifier, other.companyIdentifier) && - _deepEquals(data, other.data); + return _deepEquals(companyIdentifier, other.companyIdentifier) && _deepEquals(data, other.data); } @override @@ -697,16 +663,14 @@ class PeripheralService { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralService decode(Object result) { result as List; return PeripheralService( uuid: result[0]! as String, primary: result[1]! as bool, - characteristics: - (result[2]! as List).cast(), + characteristics: (result[2]! as List).cast(), ); } @@ -719,9 +683,7 @@ class PeripheralService { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(primary, other.primary) && - _deepEquals(characteristics, other.characteristics); + return _deepEquals(uuid, other.uuid) && _deepEquals(primary, other.primary) && _deepEquals(characteristics, other.characteristics); } @override @@ -759,8 +721,7 @@ class PeripheralCharacteristic { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralCharacteristic decode(Object result) { result as List; @@ -776,18 +737,13 @@ class PeripheralCharacteristic { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralCharacteristic || - other.runtimeType != runtimeType) { + if (other is! PeripheralCharacteristic || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(properties, other.properties) && - _deepEquals(permissions, other.permissions) && - _deepEquals(descriptors, other.descriptors) && - _deepEquals(value, other.value); + return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(permissions, other.permissions) && _deepEquals(descriptors, other.descriptors) && _deepEquals(value, other.value); } @override @@ -817,8 +773,7 @@ class PeripheralDescriptor { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralDescriptor decode(Object result) { result as List; @@ -838,9 +793,7 @@ class PeripheralDescriptor { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && - _deepEquals(value, other.value) && - _deepEquals(permissions, other.permissions); + return _deepEquals(uuid, other.uuid) && _deepEquals(value, other.value) && _deepEquals(permissions, other.permissions); } @override @@ -870,8 +823,7 @@ class PeripheralReadRequestResult { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralReadRequestResult decode(Object result) { result as List; @@ -885,16 +837,13 @@ class PeripheralReadRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralReadRequestResult || - other.runtimeType != runtimeType) { + if (other is! PeripheralReadRequestResult || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && - _deepEquals(offset, other.offset) && - _deepEquals(status, other.status); + return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); } @override @@ -924,8 +873,7 @@ class PeripheralWriteRequestResult { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralWriteRequestResult decode(Object result) { result as List; @@ -939,16 +887,13 @@ class PeripheralWriteRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralWriteRequestResult || - other.runtimeType != runtimeType) { + if (other is! PeripheralWriteRequestResult || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && - _deepEquals(offset, other.offset) && - _deepEquals(status, other.status); + return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); } @override @@ -974,8 +919,7 @@ class PeripheralManufacturerData { } Object encode() { - return _toList(); - } + return _toList(); } static PeripheralManufacturerData decode(Object result) { result as List; @@ -988,15 +932,13 @@ class PeripheralManufacturerData { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralManufacturerData || - other.runtimeType != runtimeType) { + if (other is! PeripheralManufacturerData || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(manufacturerId, other.manufacturerId) && - _deepEquals(data, other.data); + return _deepEquals(manufacturerId, other.manufacturerId) && _deepEquals(data, other.data); } @override @@ -1004,6 +946,7 @@ class PeripheralManufacturerData { int get hashCode => _deepHash([runtimeType, ..._toList()]); } + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -1011,58 +954,58 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is UniversalBleLogLevel) { + } else if (value is UniversalBleLogLevel) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is AndroidScanMode) { + } else if (value is AndroidScanMode) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is UniversalBleErrorCode) { + } else if (value is UniversalBleErrorCode) { buffer.putUint8(131); writeValue(buffer, value.index); - } else if (value is UniversalBleScanResult) { + } else if (value is UniversalBleScanResult) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is UniversalBleService) { + } else if (value is UniversalBleService) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is UniversalBleCharacteristic) { + } else if (value is UniversalBleCharacteristic) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is UniversalBleDescriptor) { + } else if (value is UniversalBleDescriptor) { buffer.putUint8(135); writeValue(buffer, value.encode()); - } else if (value is AndroidOptions) { + } else if (value is AndroidOptions) { buffer.putUint8(136); writeValue(buffer, value.encode()); - } else if (value is UniversalScanConfig) { + } else if (value is UniversalScanConfig) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is UniversalScanFilter) { + } else if (value is UniversalScanFilter) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is UniversalManufacturerDataFilter) { + } else if (value is UniversalManufacturerDataFilter) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is UniversalManufacturerData) { + } else if (value is UniversalManufacturerData) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is PeripheralService) { + } else if (value is PeripheralService) { buffer.putUint8(141); writeValue(buffer, value.encode()); - } else if (value is PeripheralCharacteristic) { + } else if (value is PeripheralCharacteristic) { buffer.putUint8(142); writeValue(buffer, value.encode()); - } else if (value is PeripheralDescriptor) { + } else if (value is PeripheralDescriptor) { buffer.putUint8(143); writeValue(buffer, value.encode()); - } else if (value is PeripheralReadRequestResult) { + } else if (value is PeripheralReadRequestResult) { buffer.putUint8(144); writeValue(buffer, value.encode()); - } else if (value is PeripheralWriteRequestResult) { + } else if (value is PeripheralWriteRequestResult) { buffer.putUint8(145); writeValue(buffer, value.encode()); - } else if (value is PeripheralManufacturerData) { + } else if (value is PeripheralManufacturerData) { buffer.putUint8(146); writeValue(buffer, value.encode()); } else { @@ -1123,11 +1066,9 @@ 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 pigeonChannelCodec = _PigeonCodec(); @@ -1135,8 +1076,7 @@ class UniversalBlePlatformChannel { final String pigeonVar_messageChannelSuffix; Future getBluetoothAvailabilityState() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1146,55 +1086,53 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as int; } Future hasPermissions(bool withAndroidFineLocation) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.hasPermissions$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.hasPermissions$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([withAndroidFineLocation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([withAndroidFineLocation]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future requestPermissions(bool withAndroidFineLocation) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestPermissions$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestPermissions$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([withAndroidFineLocation]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([withAndroidFineLocation]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future enableBluetooth() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1204,16 +1142,16 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future disableBluetooth() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1223,36 +1161,34 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } - Future startScan( - UniversalScanFilter? filter, UniversalScanConfig? config) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix'; + Future startScan(UniversalScanFilter? filter, UniversalScanConfig? config) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([filter, config]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([filter, config]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future stopScan() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1262,15 +1198,15 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future isScanning() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1280,271 +1216,253 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future connect(String deviceId, {bool? autoConnect}) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId, autoConnect]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, autoConnect]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future disconnect(String deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } - Future setNotifiable(String deviceId, String service, - String characteristic, int bleInputProperty) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix'; + Future setNotifiable(String deviceId, String service, String characteristic, int bleInputProperty) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel - .send([deviceId, service, characteristic, bleInputProperty]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, service, characteristic, bleInputProperty]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } - Future> discoverServices( - String deviceId, bool withDescriptors) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix'; + Future> discoverServices(String deviceId, bool withDescriptors) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId, withDescriptors]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, withDescriptors]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return (pigeonVar_replyValue! as List).cast(); } - Future readValue( - String deviceId, String service, String characteristic) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix'; + Future readValue(String deviceId, String service, String characteristic) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId, service, characteristic]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, service, characteristic]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as Uint8List; } Future requestMtu(String deviceId, int expectedMtu) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId, expectedMtu]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, expectedMtu]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as int; } - Future writeValue(String deviceId, String service, - String characteristic, Uint8List value, int bleOutputProperty) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix'; + Future writeValue(String deviceId, String service, String characteristic, Uint8List value, int bleOutputProperty) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [deviceId, service, characteristic, value, bleOutputProperty]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, service, characteristic, value, bleOutputProperty]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future isPaired(String deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future pair(String deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future unPair(String deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } - Future> getSystemDevices( - List withServices) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix'; + Future> getSystemDevices(List withServices) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([withServices]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([withServices]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); - return (pigeonVar_replyValue! as List) - .cast(); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return (pigeonVar_replyValue! as List).cast(); } Future getConnectionState(String deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as int; } Future readRssi(String deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as int; } @@ -1573,22 +1491,21 @@ class UniversalBlePlatformChannel { } Future setLogLevel(UniversalBleLogLevel logLevel) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([logLevel]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([logLevel]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } } @@ -1602,22 +1519,15 @@ abstract class UniversalBleCallbackChannel { void onScanResult(UniversalBleScanResult result); - void onValueChanged(String deviceId, String characteristicId, Uint8List value, - int? timestamp); + void onValueChanged(String deviceId, String characteristicId, Uint8List value, int? timestamp); 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 pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1630,17 +1540,15 @@ abstract class UniversalBleCallbackChannel { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1655,41 +1563,36 @@ abstract class UniversalBleCallbackChannel { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { final List args = message! as List; - final UniversalBleScanResult arg_result = - args[0]! as UniversalBleScanResult; + final UniversalBleScanResult arg_result = args[0]! as UniversalBleScanResult; try { api.onScanResult(arg_result); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1701,22 +1604,19 @@ abstract class UniversalBleCallbackChannel { final Uint8List arg_value = args[2]! as Uint8List; final int? arg_timestamp = args[3] as int?; try { - api.onValueChanged( - arg_deviceId, arg_characteristicId, arg_value, arg_timestamp); + api.onValueChanged(arg_deviceId, arg_characteristicId, arg_value, arg_timestamp); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1731,9 +1631,8 @@ abstract class UniversalBleCallbackChannel { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } @@ -1746,38 +1645,17 @@ class UniversalBlePeripheralChannel { /// Constructor for [UniversalBlePeripheralChannel]. 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. - UniversalBlePeripheralChannel( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + UniversalBlePeripheralChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); final String pigeonVar_messageChannelSuffix; - Future initialize() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); - } - Future isAdvertising() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1787,16 +1665,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; return pigeonVar_replyValue as bool?; } Future isSupported() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1806,16 +1684,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return pigeonVar_replyValue! as bool; } Future stopAdvertising() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1825,53 +1703,51 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future addService(PeripheralService service) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([service]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([service]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future removeService(String serviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([serviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([serviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future clearServices() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1881,15 +1757,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future> getServices() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1899,82 +1775,68 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return (pigeonVar_replyValue! as List).cast(); } - Future startAdvertising( - List services, - String? localName, - int? timeout, - PeripheralManufacturerData? manufacturerData, - bool addManufacturerDataInScanResponse) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; + Future startAdvertising(List services, String? localName, int? timeout, PeripheralManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([ - services, - localName, - timeout, - manufacturerData, - addManufacturerDataInScanResponse - ]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([services, localName, timeout, manufacturerData, addManufacturerDataInScanResponse]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } - Future updateCharacteristic( - String characteristicId, Uint8List value, String? deviceId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; + Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([characteristicId, value, deviceId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId, value, deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } /// Returns peripheral-central device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. Future> getSubscribedCentrals(String characteristicId) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([characteristicId]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; return (pigeonVar_replyValue! as List).cast(); } } @@ -1983,14 +1845,11 @@ class UniversalBlePeripheralChannel { abstract class UniversalBlePeripheralCallback { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - PeripheralReadRequestResult? onReadRequest( - String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - PeripheralWriteRequestResult? onWriteRequest( - String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralWriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); - void onCharacteristicSubscriptionChange(String deviceId, - String characteristicId, bool isSubscribed, String? name); + void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); void onAdvertisingStatusUpdate(bool advertising, String? error); @@ -2000,17 +1859,11 @@ abstract class UniversalBlePeripheralCallback { void onConnectionStateChange(String deviceId, bool connected); - static void setUp( - UniversalBlePeripheralCallback? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(UniversalBlePeripheralCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2022,22 +1875,19 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralReadRequestResult? output = api.onReadRequest( - arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralReadRequestResult? output = api.onReadRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2049,22 +1899,19 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralWriteRequestResult? output = api.onWriteRequest( - arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralWriteRequestResult? output = api.onWriteRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2076,22 +1923,19 @@ abstract class UniversalBlePeripheralCallback { final bool arg_isSubscribed = args[2]! as bool; final String? arg_name = args[3] as String?; try { - api.onCharacteristicSubscriptionChange( - arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); + api.onCharacteristicSubscriptionChange(arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2105,17 +1949,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2129,17 +1971,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2153,17 +1993,15 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', - pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2177,9 +2015,8 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/pigeon/universal_ble.dart b/pigeon/universal_ble.dart index 9cbd3c08..f81f8e7b 100644 --- a/pigeon/universal_ble.dart +++ b/pigeon/universal_ble.dart @@ -293,7 +293,6 @@ class PeripheralManufacturerData { /// Flutter -> Native (peripheral) @HostApi() abstract class UniversalBlePeripheralChannel { - void initialize(); bool? isAdvertising(); bool isSupported(); void stopAdvertising(); diff --git a/windows/src/generated/universal_ble.g.cpp b/windows/src/generated/universal_ble.g.cpp index 10bcd851..e3dd43af 100644 --- a/windows/src/generated/universal_ble.g.cpp +++ b/windows/src/generated/universal_ble.g.cpp @@ -2602,27 +2602,6 @@ void UniversalBlePeripheralChannel::SetUp( UniversalBlePeripheralChannel* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.initialize" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - std::optional output = api->Initialize(); - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising" + prepended_suffix, &GetCodec()); if (api != nullptr) { diff --git a/windows/src/generated/universal_ble.g.h b/windows/src/generated/universal_ble.g.h index f26eed11..b09764fb 100644 --- a/windows/src/generated/universal_ble.g.h +++ b/windows/src/generated/universal_ble.g.h @@ -900,7 +900,6 @@ class UniversalBlePeripheralChannel { UniversalBlePeripheralChannel(const UniversalBlePeripheralChannel&) = delete; UniversalBlePeripheralChannel& operator=(const UniversalBlePeripheralChannel&) = delete; virtual ~UniversalBlePeripheralChannel() {} - virtual std::optional Initialize() = 0; virtual ErrorOr> IsAdvertising() = 0; virtual ErrorOr IsSupported() = 0; virtual std::optional StopAdvertising() = 0; From 3742aabdb0cd4284c65dcb3fc72003d44a32fe79 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 14:22:57 +0200 Subject: [PATCH 15/23] Remove initialize API --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2ee98dd1..a16cab03 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,6 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | API | Android | iOS | macOS | Windows | Linux | Web | | :--------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | -| initialize | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | isSupported | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | isAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | addService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | From 83e64fadb685cf3b17f9736107ee7d160c721fd8 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 14:38:05 +0200 Subject: [PATCH 16/23] Refactor BLE peripheral API to enhance functionality and clarity - Replaced `isSupported()` with `isFeatureSupported()` and `isAdvertising()` with `getAdvertisingState()`. - Introduced new methods for managing peripheral readiness and advertising states. - Updated event handling to use a stream for peripheral events, replacing static callback setters. - Added enums for `PeripheralReadinessState` and `PeripheralAdvertisingState` to standardize state management across platforms. - Adjusted documentation and example usage to reflect API changes. --- README.md | 63 +++++-- .../navideck/universal_ble/UniversalBle.g.kt | 142 +++++++++++---- .../UniversalBlePeripheralPlugin.kt | 29 ++- .../universal_ble/UniversalBle.g.swift | 138 +++++++++----- .../UniversalBlePeripheralPlugin.swift | 39 +++- example/lib/peripheral/peripheral_home.dart | 98 +++++----- .../universal_ble_peripheral.dart | 171 ++++++++++++------ .../universal_ble_peripheral_pigeon.dart | 139 +++++++++++--- ...sal_ble_peripheral_platform_interface.dart | 148 +++++++++++---- .../universal_ble_pigeon/universal_ble.g.dart | 129 ++++++++----- pigeon/universal_ble.dart | 23 ++- test/universal_ble_peripheral_test.dart | 103 +++++++++++ windows/src/generated/universal_ble.g.cpp | 126 ++++++++----- windows/src/generated/universal_ble.g.h | 25 ++- windows/src/universal_ble_plugin.cpp | 41 +++-- windows/src/universal_ble_plugin.h | 6 +- 16 files changed, 1033 insertions(+), 387 deletions(-) diff --git a/README.md b/README.md index a16cab03..a46477b5 100644 --- a/README.md +++ b/README.md @@ -63,20 +63,24 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE ### Peripheral Mode (`UniversalBlePeripheral`) -| API | Android | iOS | macOS | Windows | Linux | Web | -| :--------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | -| isSupported | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| isAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| addService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| removeService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| clearServices | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| getServices | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| startAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| stopAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| updateCharacteristic | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| peripheral callbacks\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | - -\* callbacks include advertising state, read/write requests, subscription changes, and related peripheral events. +| API | Android | iOS | macOS | Windows | Linux | Web | +| :----------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | +| isFeatureSupported | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getReadinessState\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getAdvertisingState | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| addService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| removeService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| clearServices | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getServices | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| startAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| stopAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| updateCharacteristicValue\*\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getSubscribedCentrals | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| events stream\*\*\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | + +\* `getReadinessState` returns a snapshot state. Use `eventStream` for ongoing runtime changes. +\*\* `updateCharacteristicValue` supports broadcast to all subscribed centrals or a specific central via `PeripheralUpdateTarget`. +\*\*\* events include advertising state changes, read/write requests, subscription changes, and related peripheral events. ## Getting Started @@ -90,6 +94,7 @@ dependencies: and import it wherever you want to use it: ```dart +import 'dart:typed_data'; import 'package:universal_ble/universal_ble.dart'; ``` @@ -628,14 +633,18 @@ The error parser automatically converts platform-specific error formats (strings ## Peripheral Mode -`universal_ble` provides peripheral mode through `UniversalBlePeripheral`, so your app can advertise as a peripheral "server" in addition to client mode. +`universal_ble` provides peripheral mode through `UniversalBlePeripheralClient`, so your app can advertise as a peripheral "server" in addition to client mode. ### Basic setup ```dart import 'package:universal_ble/universal_ble.dart'; -await UniversalBlePeripheral.addService( +final peripheral = UniversalBlePeripheralClient(); +final ready = await peripheral.isFeatureSupported(); +if (!ready) return; + +await peripheral.addService( BleService("0000180F-0000-1000-8000-00805F9B34FB", [ BleCharacteristic( "00002A19-0000-1000-8000-00805F9B34FB", @@ -646,12 +655,30 @@ await UniversalBlePeripheral.addService( primary: true, ); -await UniversalBlePeripheral.startAdvertising( - services: ["0000180F-0000-1000-8000-00805F9B34FB"], +await peripheral.startAdvertising( + services: [PeripheralServiceId("0000180F-0000-1000-8000-00805F9B34FB")], localName: "UniversalBlePeripheral", ); + +final sub = peripheral.eventStream.listen((event) { + // Handle UniversalBlePeripheralEvent subtypes. +}); + +peripheral.setRequestHandlers( + onReadRequest: (deviceId, characteristicId, offset, value) => + BleReadRequestResult(value: value ?? Uint8List(0)), + onWriteRequest: (deviceId, characteristicId, offset, value) => + const BleWriteRequestResult(), +); ``` +### Breaking changes + +- `isSupported()` was replaced by `isFeatureSupported()`. +- `isAdvertising()` was replaced by `getAdvertisingState()`. +- Static callback setters were replaced by `eventStream` + `setRequestHandlers(...)`. +- `UniversalBlePeripheralClient` is the recommended API; `UniversalBlePeripheral` remains as a singleton facade. + ### Platform notes - Linux/Web currently return unsupported for peripheral mode. diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt index c94d538c..e0448e9f 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt @@ -224,6 +224,34 @@ enum class AndroidScanMode(val raw: Int) { } } +enum class PeripheralReadinessState(val raw: Int) { + UNKNOWN(0), + READY(1), + BLUETOOTH_OFF(2), + UNAUTHORIZED(3), + UNSUPPORTED(4); + + companion object { + fun ofRaw(raw: Int): PeripheralReadinessState? { + return values().firstOrNull { it.raw == raw } + } + } +} + +enum class PeripheralAdvertisingState(val raw: Int) { + IDLE(0), + STARTING(1), + ADVERTISING(2), + STOPPING(3), + ERROR(4); + + companion object { + fun ofRaw(raw: Int): PeripheralAdvertisingState? { + return values().firstOrNull { it.raw == raw } + } + } +} + /** Unified error codes for all platforms */ enum class UniversalBleErrorCode(val raw: Int) { UNKNOWN_ERROR(0), @@ -952,80 +980,90 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() { } 131.toByte() -> { return (readValue(buffer) as Long?)?.let { - UniversalBleErrorCode.ofRaw(it.toInt()) + PeripheralReadinessState.ofRaw(it.toInt()) } } 132.toByte() -> { + return (readValue(buffer) as Long?)?.let { + PeripheralAdvertisingState.ofRaw(it.toInt()) + } + } + 133.toByte() -> { + return (readValue(buffer) as Long?)?.let { + UniversalBleErrorCode.ofRaw(it.toInt()) + } + } + 134.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalBleScanResult.fromList(it) } } - 133.toByte() -> { + 135.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalBleService.fromList(it) } } - 134.toByte() -> { + 136.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalBleCharacteristic.fromList(it) } } - 135.toByte() -> { + 137.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalBleDescriptor.fromList(it) } } - 136.toByte() -> { + 138.toByte() -> { return (readValue(buffer) as? List)?.let { AndroidOptions.fromList(it) } } - 137.toByte() -> { + 139.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalScanConfig.fromList(it) } } - 138.toByte() -> { + 140.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalScanFilter.fromList(it) } } - 139.toByte() -> { + 141.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalManufacturerDataFilter.fromList(it) } } - 140.toByte() -> { + 142.toByte() -> { return (readValue(buffer) as? List)?.let { UniversalManufacturerData.fromList(it) } } - 141.toByte() -> { + 143.toByte() -> { return (readValue(buffer) as? List)?.let { PeripheralService.fromList(it) } } - 142.toByte() -> { + 144.toByte() -> { return (readValue(buffer) as? List)?.let { PeripheralCharacteristic.fromList(it) } } - 143.toByte() -> { + 145.toByte() -> { return (readValue(buffer) as? List)?.let { PeripheralDescriptor.fromList(it) } } - 144.toByte() -> { + 146.toByte() -> { return (readValue(buffer) as? List)?.let { PeripheralReadRequestResult.fromList(it) } } - 145.toByte() -> { + 147.toByte() -> { return (readValue(buffer) as? List)?.let { PeripheralWriteRequestResult.fromList(it) } } - 146.toByte() -> { + 148.toByte() -> { return (readValue(buffer) as? List)?.let { PeripheralManufacturerData.fromList(it) } @@ -1043,68 +1081,76 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() { stream.write(130) writeValue(stream, value.raw.toLong()) } - is UniversalBleErrorCode -> { + is PeripheralReadinessState -> { stream.write(131) writeValue(stream, value.raw.toLong()) } - is UniversalBleScanResult -> { + is PeripheralAdvertisingState -> { stream.write(132) + writeValue(stream, value.raw.toLong()) + } + is UniversalBleErrorCode -> { + stream.write(133) + writeValue(stream, value.raw.toLong()) + } + is UniversalBleScanResult -> { + stream.write(134) writeValue(stream, value.toList()) } is UniversalBleService -> { - stream.write(133) + stream.write(135) writeValue(stream, value.toList()) } is UniversalBleCharacteristic -> { - stream.write(134) + stream.write(136) writeValue(stream, value.toList()) } is UniversalBleDescriptor -> { - stream.write(135) + stream.write(137) writeValue(stream, value.toList()) } is AndroidOptions -> { - stream.write(136) + stream.write(138) writeValue(stream, value.toList()) } is UniversalScanConfig -> { - stream.write(137) + stream.write(139) writeValue(stream, value.toList()) } is UniversalScanFilter -> { - stream.write(138) + stream.write(140) writeValue(stream, value.toList()) } is UniversalManufacturerDataFilter -> { - stream.write(139) + stream.write(141) writeValue(stream, value.toList()) } is UniversalManufacturerData -> { - stream.write(140) + stream.write(142) writeValue(stream, value.toList()) } is PeripheralService -> { - stream.write(141) + stream.write(143) writeValue(stream, value.toList()) } is PeripheralCharacteristic -> { - stream.write(142) + stream.write(144) writeValue(stream, value.toList()) } is PeripheralDescriptor -> { - stream.write(143) + stream.write(145) writeValue(stream, value.toList()) } is PeripheralReadRequestResult -> { - stream.write(144) + stream.write(146) writeValue(stream, value.toList()) } is PeripheralWriteRequestResult -> { - stream.write(145) + stream.write(147) writeValue(stream, value.toList()) } is PeripheralManufacturerData -> { - stream.write(146) + stream.write(148) writeValue(stream, value.toList()) } else -> super.writeValue(stream, value) @@ -1698,8 +1744,9 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger, * Generated interface from Pigeon that represents a handler of messages from Flutter. */ interface UniversalBlePeripheralChannel { - fun isAdvertising(): Boolean? - fun isSupported(): Boolean + fun getAdvertisingState(): PeripheralAdvertisingState + fun isFeatureSupported(): Boolean + fun getReadinessState(): PeripheralReadinessState fun stopAdvertising() fun addService(service: PeripheralService) fun removeService(serviceId: String) @@ -1723,11 +1770,26 @@ interface UniversalBlePeripheralChannel { fun setUp(binaryMessenger: BinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$separatedMessageChannelSuffix", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getAdvertisingState$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.getAdvertisingState()) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported$separatedMessageChannelSuffix", codec) if (api != null) { channel.setMessageHandler { _, reply -> val wrapped: List = try { - listOf(api.isAdvertising()) + listOf(api.isFeatureSupported()) } catch (exception: Throwable) { UniversalBlePigeonUtils.wrapError(exception) } @@ -1738,11 +1800,11 @@ interface UniversalBlePeripheralChannel { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$separatedMessageChannelSuffix", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState$separatedMessageChannelSuffix", codec) if (api != null) { channel.setMessageHandler { _, reply -> val wrapped: List = try { - listOf(api.isSupported()) + listOf(api.getReadinessState()) } catch (exception: Throwable) { UniversalBlePigeonUtils.wrapError(exception) } @@ -1962,12 +2024,12 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge } } } - fun onAdvertisingStatusUpdate(advertisingArg: Boolean, errorArg: String?, callback: (Result) -> Unit) + fun onAdvertisingStateChange(stateArg: PeripheralAdvertisingState, errorArg: String?, callback: (Result) -> Unit) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$separatedMessageChannelSuffix" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStateChange$separatedMessageChannelSuffix" val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(advertisingArg, errorArg)) { + channel.send(listOf(stateArg, errorArg)) { if (it is List<*>) { if (it.size > 1) { callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index bb62b010..d9f72764 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -44,7 +44,7 @@ class UniversalBlePeripheralPlugin( private val bluetoothDevicesMap: MutableMap = HashMap() private val listOfDevicesWaitingForBond = mutableListOf() private val emptyBytes = byteArrayOf() - private var advertising: Boolean? = null + private var advertisingState: PeripheralAdvertisingState = PeripheralAdvertisingState.IDLE private var receiverRegistered = false private var originalAdapterName: String? = null private var adapterNameOverridden = false @@ -102,9 +102,9 @@ class UniversalBlePeripheralPlugin( } } - override fun isAdvertising(): Boolean? = advertising + override fun getAdvertisingState(): PeripheralAdvertisingState = advertisingState - override fun isSupported(): Boolean { + override fun isFeatureSupported(): Boolean { val adapter = bluetoothManager.adapter ?: return false if (!adapter.isMultipleAdvertisementSupported) { return false @@ -112,6 +112,12 @@ class UniversalBlePeripheralPlugin( return true } + override fun getReadinessState(): PeripheralReadinessState { + val adapter = bluetoothManager.adapter ?: return PeripheralReadinessState.UNSUPPORTED + if (!adapter.isEnabled) return PeripheralReadinessState.BLUETOOTH_OFF + return PeripheralReadinessState.READY + } + override fun addService(service: PeripheralService) { initializePeripheral() gattServer?.addService(service.toGattService()) @@ -140,6 +146,8 @@ class UniversalBlePeripheralPlugin( addManufacturerDataInScanResponse: Boolean, ) { initializePeripheral() + advertisingState = PeripheralAdvertisingState.STARTING + callback.onAdvertisingStateChange(PeripheralAdvertisingState.STARTING, null) {} if (!isBluetoothEnabled()) { activity?.startActivityForResult( Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), @@ -197,11 +205,13 @@ class UniversalBlePeripheralPlugin( override fun stopAdvertising() { initializePeripheral() + advertisingState = PeripheralAdvertisingState.STOPPING + callback.onAdvertisingStateChange(PeripheralAdvertisingState.STOPPING, null) {} handler.post { bluetoothLeAdvertiser?.stopAdvertising(advertiseCallback) restoreAdapterNameIfNeeded() - advertising = false - callback.onAdvertisingStatusUpdate(false, null) {} + advertisingState = PeripheralAdvertisingState.IDLE + callback.onAdvertisingStateChange(PeripheralAdvertisingState.IDLE, null) {} } } @@ -281,14 +291,17 @@ class UniversalBlePeripheralPlugin( ADVERTISE_FAILED_TOO_MANY_ADVERTISERS -> "Too many advertisers" else -> "Failed to start advertising: $errorCode" } - callback.onAdvertisingStatusUpdate(false, errorMessage) {} + advertisingState = PeripheralAdvertisingState.ERROR + callback.onAdvertisingStateChange(PeripheralAdvertisingState.ERROR, errorMessage) {} } } override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) { super.onStartSuccess(settingsInEffect) - advertising = true - handler.post { callback.onAdvertisingStatusUpdate(true, null) {} } + advertisingState = PeripheralAdvertisingState.ADVERTISING + handler.post { + callback.onAdvertisingStateChange(PeripheralAdvertisingState.ADVERTISING, null) {} + } } } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift index 92377968..4adee68e 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift @@ -195,6 +195,22 @@ enum AndroidScanMode: Int { case opportunistic = 3 } +enum PeripheralReadinessState: Int { + case unknown = 0 + case ready = 1 + case bluetoothOff = 2 + case unauthorized = 3 + case unsupported = 4 +} + +enum PeripheralAdvertisingState: Int { + case idle = 0 + case starting = 1 + case advertising = 2 + case stopping = 3 + case error = 4 +} + /// Unified error codes for all platforms enum UniversalBleErrorCode: Int { case unknownError = 0 @@ -902,38 +918,50 @@ private class UniversalBlePigeonCodecReader: FlutterStandardReader { case 131: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return UniversalBleErrorCode(rawValue: enumResultAsInt) + return PeripheralReadinessState(rawValue: enumResultAsInt) } return nil case 132: - return UniversalBleScanResult.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return PeripheralAdvertisingState(rawValue: enumResultAsInt) + } + return nil case 133: - return UniversalBleService.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return UniversalBleErrorCode(rawValue: enumResultAsInt) + } + return nil case 134: - return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?]) + return UniversalBleScanResult.fromList(self.readValue() as! [Any?]) case 135: - return UniversalBleDescriptor.fromList(self.readValue() as! [Any?]) + return UniversalBleService.fromList(self.readValue() as! [Any?]) case 136: - return AndroidOptions.fromList(self.readValue() as! [Any?]) + return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?]) case 137: - return UniversalScanConfig.fromList(self.readValue() as! [Any?]) + return UniversalBleDescriptor.fromList(self.readValue() as! [Any?]) case 138: - return UniversalScanFilter.fromList(self.readValue() as! [Any?]) + return AndroidOptions.fromList(self.readValue() as! [Any?]) case 139: - return UniversalManufacturerDataFilter.fromList(self.readValue() as! [Any?]) + return UniversalScanConfig.fromList(self.readValue() as! [Any?]) case 140: - return UniversalManufacturerData.fromList(self.readValue() as! [Any?]) + return UniversalScanFilter.fromList(self.readValue() as! [Any?]) case 141: - return PeripheralService.fromList(self.readValue() as! [Any?]) + return UniversalManufacturerDataFilter.fromList(self.readValue() as! [Any?]) case 142: - return PeripheralCharacteristic.fromList(self.readValue() as! [Any?]) + return UniversalManufacturerData.fromList(self.readValue() as! [Any?]) case 143: - return PeripheralDescriptor.fromList(self.readValue() as! [Any?]) + return PeripheralService.fromList(self.readValue() as! [Any?]) case 144: - return PeripheralReadRequestResult.fromList(self.readValue() as! [Any?]) + return PeripheralCharacteristic.fromList(self.readValue() as! [Any?]) case 145: - return PeripheralWriteRequestResult.fromList(self.readValue() as! [Any?]) + return PeripheralDescriptor.fromList(self.readValue() as! [Any?]) case 146: + return PeripheralReadRequestResult.fromList(self.readValue() as! [Any?]) + case 147: + return PeripheralWriteRequestResult.fromList(self.readValue() as! [Any?]) + case 148: return PeripheralManufacturerData.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -949,53 +977,59 @@ private class UniversalBlePigeonCodecWriter: FlutterStandardWriter { } else if let value = value as? AndroidScanMode { super.writeByte(130) super.writeValue(value.rawValue) - } else if let value = value as? UniversalBleErrorCode { + } else if let value = value as? PeripheralReadinessState { super.writeByte(131) super.writeValue(value.rawValue) - } else if let value = value as? UniversalBleScanResult { + } else if let value = value as? PeripheralAdvertisingState { super.writeByte(132) + super.writeValue(value.rawValue) + } else if let value = value as? UniversalBleErrorCode { + super.writeByte(133) + super.writeValue(value.rawValue) + } else if let value = value as? UniversalBleScanResult { + super.writeByte(134) super.writeValue(value.toList()) } else if let value = value as? UniversalBleService { - super.writeByte(133) + super.writeByte(135) super.writeValue(value.toList()) } else if let value = value as? UniversalBleCharacteristic { - super.writeByte(134) + super.writeByte(136) super.writeValue(value.toList()) } else if let value = value as? UniversalBleDescriptor { - super.writeByte(135) + super.writeByte(137) super.writeValue(value.toList()) } else if let value = value as? AndroidOptions { - super.writeByte(136) + super.writeByte(138) super.writeValue(value.toList()) } else if let value = value as? UniversalScanConfig { - super.writeByte(137) + super.writeByte(139) super.writeValue(value.toList()) } else if let value = value as? UniversalScanFilter { - super.writeByte(138) + super.writeByte(140) super.writeValue(value.toList()) } else if let value = value as? UniversalManufacturerDataFilter { - super.writeByte(139) + super.writeByte(141) super.writeValue(value.toList()) } else if let value = value as? UniversalManufacturerData { - super.writeByte(140) + super.writeByte(142) super.writeValue(value.toList()) } else if let value = value as? PeripheralService { - super.writeByte(141) + super.writeByte(143) super.writeValue(value.toList()) } else if let value = value as? PeripheralCharacteristic { - super.writeByte(142) + super.writeByte(144) super.writeValue(value.toList()) } else if let value = value as? PeripheralDescriptor { - super.writeByte(143) + super.writeByte(145) super.writeValue(value.toList()) } else if let value = value as? PeripheralReadRequestResult { - super.writeByte(144) + super.writeByte(146) super.writeValue(value.toList()) } else if let value = value as? PeripheralWriteRequestResult { - super.writeByte(145) + super.writeByte(147) super.writeValue(value.toList()) } else if let value = value as? PeripheralManufacturerData { - super.writeByte(146) + super.writeByte(148) super.writeValue(value.toList()) } else { super.writeValue(value) @@ -1547,8 +1581,9 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol { /// /// Generated protocol from Pigeon that represents a handler of messages from Flutter. protocol UniversalBlePeripheralChannel { - func isAdvertising() throws -> Bool? - func isSupported() throws -> Bool + func getAdvertisingState() throws -> PeripheralAdvertisingState + func isFeatureSupported() throws -> Bool + func getReadinessState() throws -> PeripheralReadinessState func stopAdvertising() throws func addService(service: PeripheralService) throws func removeService(serviceId: String) throws @@ -1567,31 +1602,44 @@ class UniversalBlePeripheralChannelSetup { /// Sets up an instance of `UniversalBlePeripheralChannel` to handle messages through the `binaryMessenger`. static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UniversalBlePeripheralChannel?, messageChannelSuffix: String = "") { let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" - let isAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + let getAdvertisingStateChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getAdvertisingState\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAdvertisingStateChannel.setMessageHandler { _, reply in + do { + let result = try api.getAdvertisingState() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getAdvertisingStateChannel.setMessageHandler(nil) + } + let isFeatureSupportedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { - isAdvertisingChannel.setMessageHandler { _, reply in + isFeatureSupportedChannel.setMessageHandler { _, reply in do { - let result = try api.isAdvertising() + let result = try api.isFeatureSupported() reply(wrapResult(result)) } catch { reply(wrapError(error)) } } } else { - isAdvertisingChannel.setMessageHandler(nil) + isFeatureSupportedChannel.setMessageHandler(nil) } - let isSupportedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + let getReadinessStateChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { - isSupportedChannel.setMessageHandler { _, reply in + getReadinessStateChannel.setMessageHandler { _, reply in do { - let result = try api.isSupported() + let result = try api.getReadinessState() reply(wrapResult(result)) } catch { reply(wrapError(error)) } } } else { - isSupportedChannel.setMessageHandler(nil) + getReadinessStateChannel.setMessageHandler(nil) } let stopAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { @@ -1724,7 +1772,7 @@ protocol UniversalBlePeripheralCallbackProtocol { func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) - func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) + func onAdvertisingStateChange(state stateArg: PeripheralAdvertisingState, error errorArg: String?, completion: @escaping (Result) -> Void) func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) func onMtuChange(deviceId deviceIdArg: String, mtu mtuArg: Int64, completion: @escaping (Result) -> Void) func onConnectionStateChange(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result) -> Void) @@ -1795,10 +1843,10 @@ class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { } } } - func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate\(messageChannelSuffix)" + func onAdvertisingStateChange(state stateArg: PeripheralAdvertisingState, error errorArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStateChange\(messageChannelSuffix)" let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([advertisingArg, errorArg] as [Any?]) { response in + channel.sendMessage([stateArg, errorArg] as [Any?]) { response in guard let listResponse = response as? [Any?] else { completion(.failure(createConnectionError(withChannelName: channelName))) return diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 8be383d5..a5aef060 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -11,6 +11,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne CBPeripheralManagerDelegate { private let callbackChannel: UniversalBlePeripheralCallback + private var advertisingState: PeripheralAdvertisingState = .idle private lazy var peripheralManager: CBPeripheralManager = .init(delegate: self, queue: nil, options: nil) private let centralsLock = NSLock() @@ -30,17 +31,37 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne clearCentrals() } - func isSupported() throws -> Bool { + func getAdvertisingState() throws -> PeripheralAdvertisingState { + advertisingState + } + + func isFeatureSupported() throws -> Bool { true } - func isAdvertising() throws -> Bool? { - peripheralManager.isAdvertising + func getReadinessState() throws -> PeripheralReadinessState { + switch peripheralManager.state { + case .poweredOn: + return .ready + case .poweredOff: + return .bluetoothOff + case .unauthorized: + return .unauthorized + case .unsupported: + return .unsupported + case .unknown, .resetting: + return .unknown + @unknown default: + return .unknown + } } func stopAdvertising() throws { + advertisingState = .stopping + callbackChannel.onAdvertisingStateChange(state: .stopping, error: nil) { _ in } peripheralManager.stopAdvertising() - callbackChannel.onAdvertisingStatusUpdate(advertising: false, error: nil) { _ in } + advertisingState = .idle + callbackChannel.onAdvertisingStateChange(state: .idle, error: nil) { _ in } } func addService(service: PeripheralService) throws { @@ -104,6 +125,8 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne manufacturerField.append(manufacturerData.data.data) advertisementData[CBAdvertisementDataManufacturerDataKey] = manufacturerField } + advertisingState = .starting + callbackChannel.onAdvertisingStateChange(state: .starting, error: nil) { _ in } peripheralManager.startAdvertising(advertisementData) } @@ -133,15 +156,17 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne _: CBPeripheralManager, error: Error? ) { - callbackChannel.onAdvertisingStatusUpdate( - advertising: error == nil, + advertisingState = error == nil ? .advertising : .error + callbackChannel.onAdvertisingStateChange( + state: advertisingState, error: error?.localizedDescription ) { _ in } } nonisolated func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { if peripheral.state != .poweredOn { - callbackChannel.onAdvertisingStatusUpdate(advertising: false, error: nil) { _ in } + advertisingState = .idle + callbackChannel.onAdvertisingStateChange(state: .idle, error: nil) { _ in } } } diff --git a/example/lib/peripheral/peripheral_home.dart b/example/lib/peripheral/peripheral_home.dart index d07946a5..64fcaeee 100644 --- a/example/lib/peripheral/peripheral_home.dart +++ b/example/lib/peripheral/peripheral_home.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; @@ -12,9 +13,12 @@ class PeripheralHome extends StatefulWidget { } class _PeripheralHomeState extends State { + final UniversalBlePeripheralClient _peripheral = UniversalBlePeripheralClient(); final List _logs = []; + StreamSubscription? _eventSub; bool _initialized = false; - bool _advertising = false; + UniversalBlePeripheralAdvertisingState _advertisingState = + UniversalBlePeripheralAdvertisingState.idle; static const String _serviceBattery = '0000180F-0000-1000-8000-00805F9B34FB'; static const String _charBattery = '00002A19-0000-1000-8000-00805F9B34FB'; @@ -24,39 +28,38 @@ class _PeripheralHomeState extends State { @override void initState() { super.initState(); - UniversalBlePeripheral.onAdvertisingStatusUpdate = (advertising, error) { - setState(() { - _advertising = advertising; - }); - _log('Advertising: $advertising ${error ?? ''}'.trim()); - }; - UniversalBlePeripheral.onServiceAdded = (serviceId, error) { - _log('Service added: $serviceId ${error ?? ''}'.trim()); - }; - UniversalBlePeripheral.onSubscriptionChange = ( - deviceId, - characteristicId, - isSubscribed, - name, - ) { - _log( - 'Subscription ${isSubscribed ? 'on' : 'off'}: ' - '${name ?? deviceId} -> $characteristicId', - ); - }; - UniversalBlePeripheral.onReadRequest = (deviceId, characteristicId, _, __) { + _eventSub = _peripheral.eventStream.listen((event) { + switch (event) { + case UniversalBlePeripheralAdvertisingStateChanged(): + setState(() { + _advertisingState = event.state; + }); + _log('Advertising state: ${event.state.name} ${event.error ?? ''}'.trim()); + case UniversalBlePeripheralServiceAdded(): + _log('Service added: ${event.serviceId} ${event.error ?? ''}'.trim()); + case UniversalBlePeripheralCharacteristicSubscriptionChanged(): + _log( + 'Subscription ${event.isSubscribed ? 'on' : 'off'}: ' + '${event.name ?? event.deviceId} -> ${event.characteristicId}', + ); + case UniversalBlePeripheralConnectionStateChanged(): + _log( + 'Connection: ${event.deviceId} connected=${event.connected}', + ); + case UniversalBlePeripheralMtuChanged(): + _log('MTU: ${event.deviceId} mtu=${event.mtu}'); + } + }); + _peripheral.setRequestHandlers( + onReadRequest: (deviceId, characteristicId, _, __) { _log('Read request: $deviceId $characteristicId'); return BleReadRequestResult(value: utf8.encode('Hello World')); - }; - UniversalBlePeripheral.onWriteRequest = ( - deviceId, - characteristicId, - _, - value, - ) { - _log('Write request: $deviceId $characteristicId $value'); - return const BleWriteRequestResult(); - }; + }, + onWriteRequest: (deviceId, characteristicId, _, value) { + _log('Write request: $deviceId $characteristicId $value'); + return const BleWriteRequestResult(); + }, + ); } void _log(String text) { @@ -66,15 +69,16 @@ class _PeripheralHomeState extends State { } Future _initialize() async { - final supported = await UniversalBlePeripheral.isSupported(); + final supported = await _peripheral.isFeatureSupported(); setState(() { _initialized = supported; }); - _log('Peripheral ready check. supported=$supported'); + final readiness = await _peripheral.getReadinessState(); + _log('Peripheral ready check. supported=$supported readiness=${readiness.name}'); } Future _addServices() async { - await UniversalBlePeripheral.addService( + await _peripheral.addService( BleService(_serviceBattery, [ BleCharacteristic( _charBattery, @@ -83,7 +87,7 @@ class _PeripheralHomeState extends State { ), ]), ); - await UniversalBlePeripheral.addService( + await _peripheral.addService( BleService(_serviceTest, [ BleCharacteristic( _charTest, @@ -100,8 +104,11 @@ class _PeripheralHomeState extends State { } Future _startAdvertising() async { - await UniversalBlePeripheral.startAdvertising( - services: [_serviceBattery, _serviceTest], + await _peripheral.startAdvertising( + services: [ + const PeripheralServiceId(_serviceBattery), + const PeripheralServiceId(_serviceTest), + ], localName: 'UniversalBlePeripheral', manufacturerData: ManufacturerData( 0x012D, @@ -137,9 +144,10 @@ class _PeripheralHomeState extends State { ElevatedButton( onPressed: _initialized ? () async { - await UniversalBlePeripheral.stopAdvertising(); + await _peripheral.stopAdvertising(); setState(() { - _advertising = false; + _advertisingState = + UniversalBlePeripheralAdvertisingState.idle; }); _log('Stop advertising requested'); } @@ -149,7 +157,7 @@ class _PeripheralHomeState extends State { ElevatedButton( onPressed: _initialized ? () async { - await UniversalBlePeripheral.updateCharacteristic( + await _peripheral.updateCharacteristicValue( characteristicId: _charTest, value: utf8.encode('Test Data'), ); @@ -167,7 +175,7 @@ class _PeripheralHomeState extends State { children: [ Text('Initialized: $_initialized'), const SizedBox(width: 16), - Text('Advertising: $_advertising'), + Text('Advertising: ${_advertisingState.name}'), ], ), ), @@ -184,4 +192,10 @@ class _PeripheralHomeState extends State { ], ); } + + @override + void dispose() { + _eventSub?.cancel(); + super.dispose(); + } } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart index f86bf0a9..b11df9f2 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -2,100 +2,167 @@ import 'package:flutter/foundation.dart'; import 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart'; import 'package:universal_ble/universal_ble.dart'; -class UniversalBlePeripheral { - static UniversalBlePeripheralPlatform _platform = _defaultPlatform(); +class UniversalBlePeripheralClient { + UniversalBlePeripheralPlatform _platform; - static UniversalBlePeripheralPlatform _defaultPlatform() { - if (kIsWeb || defaultTargetPlatform == TargetPlatform.linux) { - return UniversalBlePeripheralUnsupported(); - } - return UniversalBlePeripheralPigeon.instance; - } + UniversalBlePeripheralClient({UniversalBlePeripheralPlatform? platform}) + : _platform = platform ?? UniversalBlePeripheral._defaultPlatform(); - static void setInstance(UniversalBlePeripheralPlatform instance) { + void setPlatform(UniversalBlePeripheralPlatform platform) { _platform.dispose(); - _platform = instance; + _platform = platform; } - static Future isSupported() => _platform.isSupported(); - static Future isAdvertising() => _platform.isAdvertising(); + Stream get eventStream => _platform.eventStream; - static Future addService( + void setRequestHandlers({ + OnPeripheralReadRequest? onReadRequest, + OnPeripheralWriteRequest? onWriteRequest, + }) { + _platform.setRequestHandlers( + onReadRequest: onReadRequest, + onWriteRequest: onWriteRequest, + ); + } + + Future isFeatureSupported() => _platform.isFeatureSupported(); + + Future getReadinessState() => + _platform.getReadinessState(); + + Future getAdvertisingState() => + _platform.getAdvertisingState(); + + Future addService( BleService service, { bool primary = true, Duration? timeout, }) => _platform.addService(service, primary: primary, timeout: timeout); - static Future removeService(String serviceId) => - _platform.removeService(serviceId); - static Future clearServices() => _platform.clearServices(); - static Future> getServices() => _platform.getServices(); + Future removeService(PeripheralServiceId serviceId) => + _platform.removeService( + PeripheralServiceId(BleUuidParser.string(serviceId.value)), + ); - static Future startAdvertising({ - required List services, + Future clearServices() => _platform.clearServices(); + + Future> getServices() => _platform.getServices(); + + Future startAdvertising({ + required List services, String? localName, int? timeout, ManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse = false, }) => _platform.startAdvertising( - services: services.map(BleUuidParser.string).toList(), + services: services + .map((e) => PeripheralServiceId(BleUuidParser.string(e.value))) + .toList(), localName: localName, timeout: timeout, manufacturerData: manufacturerData, addManufacturerDataInScanResponse: addManufacturerDataInScanResponse, ); - static Future stopAdvertising() => _platform.stopAdvertising(); + Future stopAdvertising() => _platform.stopAdvertising(); - static Future updateCharacteristic({ + Future updateCharacteristicValue({ required String characteristicId, required Uint8List value, - String? deviceId, + PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }) => - _platform.updateCharacteristic( + _platform.updateCharacteristicValue( characteristicId: characteristicId, value: value, - deviceId: deviceId, + target: target, ); - /// Returns central device ids currently subscribed to [characteristicId] - /// (e.g. HID report characteristic). Used to restore in-app state after restart. - static Future> getSubscribedCentrals(String characteristicId) => + Future> getSubscribedCentrals(String characteristicId) => _platform.getSubscribedCentrals(BleUuidParser.string(characteristicId)); +} - static set onAdvertisingStatusUpdate( - OnPeripheralAdvertisingStatusUpdate? callback, - ) { - _platform.advertisingStatusUpdateCallback = callback; - } +class UniversalBlePeripheral { + static UniversalBlePeripheralClient? _clientInstance; + static UniversalBlePeripheralClient get _client => + _clientInstance ??= UniversalBlePeripheralClient(); - static set onSubscriptionChange( - OnPeripheralCharacteristicSubscriptionChange? callback, - ) { - _platform.subscriptionChangeCallback = callback; + static UniversalBlePeripheralPlatform _defaultPlatform() { + if (kIsWeb || defaultTargetPlatform == TargetPlatform.linux) { + return UniversalBlePeripheralUnsupported(); + } + return UniversalBlePeripheralPigeon.instance; } - static set onConnectionStateChange( - OnPeripheralConnectionStateChange? callback, - ) { - _platform.connectionStateChangeCallback = callback; + static void setInstance(UniversalBlePeripheralPlatform instance) { + if (_clientInstance == null) { + _clientInstance = UniversalBlePeripheralClient(platform: instance); + return; + } + _client.setPlatform(instance); } - static set onReadRequest(OnPeripheralReadRequest? callback) { - _platform.readRequestCallback = callback; + static Stream get eventStream => + _client.eventStream; + + static void setRequestHandlers({ + OnPeripheralReadRequest? onReadRequest, + OnPeripheralWriteRequest? onWriteRequest, + }) { + _client.setRequestHandlers( + onReadRequest: onReadRequest, + onWriteRequest: onWriteRequest, + ); } - static set onServiceAdded(OnPeripheralServiceAdded? callback) { - _platform.serviceAddedCallback = callback; - } + static Future isFeatureSupported() => _client.isFeatureSupported(); - static set onWriteRequest(OnPeripheralWriteRequest? callback) { - _platform.writeRequestCallback = callback; - } + static Future getReadinessState() => + _client.getReadinessState(); - static set onMtuChange(OnPeripheralMtuChange? callback) { - _platform.mtuChangeCallback = callback; - } + static Future getAdvertisingState() => + _client.getAdvertisingState(); + + static Future addService( + BleService service, { + bool primary = true, + Duration? timeout, + }) => + _client.addService(service, primary: primary, timeout: timeout); + + static Future removeService(PeripheralServiceId serviceId) => + _client.removeService(serviceId); + static Future clearServices() => _client.clearServices(); + static Future> getServices() => _client.getServices(); + + static Future startAdvertising({ + required List services, + String? localName, + int? timeout, + ManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse = false, + }) => + _client.startAdvertising( + services: services, + localName: localName, + timeout: timeout, + manufacturerData: manufacturerData, + addManufacturerDataInScanResponse: addManufacturerDataInScanResponse, + ); + + static Future stopAdvertising() => _client.stopAdvertising(); + + static Future updateCharacteristicValue({ + required String characteristicId, + required Uint8List value, + PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), + }) => + _client.updateCharacteristicValue( + characteristicId: characteristicId, value: value, target: target); + + /// Returns central device ids currently subscribed to [characteristicId] + /// (e.g. HID report characteristic). Used to restore in-app state after restart. + static Future> getSubscribedCentrals(String characteristicId) => + _client.getSubscribedCentrals(characteristicId); } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index 0678be48..fe3fe15e 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -20,14 +20,61 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform final StreamController<({String serviceId, String? error})> _serviceResultController = StreamController<({String serviceId, String? error})>.broadcast(); + final StreamController _eventController = + StreamController.broadcast(); bool _disposed = false; + OnPeripheralReadRequest? _readRequestHandler; + OnPeripheralWriteRequest? _writeRequestHandler; @override - Future isSupported() => _channel.isSupported(); + Stream get eventStream => + _eventController.stream; @override - Future isAdvertising() async => - (await _channel.isAdvertising()) ?? false; + void setRequestHandlers({ + OnPeripheralReadRequest? onReadRequest, + OnPeripheralWriteRequest? onWriteRequest, + }) { + _readRequestHandler = onReadRequest; + _writeRequestHandler = onWriteRequest; + } + + @override + Future isFeatureSupported() => _channel.isFeatureSupported(); + + @override + Future getReadinessState() async { + final state = await _channel.getReadinessState(); + return switch (state) { + pigeon.PeripheralReadinessState.ready => + UniversalBlePeripheralReadinessState.ready, + pigeon.PeripheralReadinessState.bluetoothOff => + UniversalBlePeripheralReadinessState.bluetoothOff, + pigeon.PeripheralReadinessState.unauthorized => + UniversalBlePeripheralReadinessState.unauthorized, + pigeon.PeripheralReadinessState.unsupported => + UniversalBlePeripheralReadinessState.unsupported, + pigeon.PeripheralReadinessState.unknown => + UniversalBlePeripheralReadinessState.unknown, + }; + } + + @override + Future getAdvertisingState() async { + final state = await _channel.getAdvertisingState(); + return switch (state) { + pigeon.PeripheralAdvertisingState.idle => + UniversalBlePeripheralAdvertisingState.idle, + pigeon.PeripheralAdvertisingState.starting => + UniversalBlePeripheralAdvertisingState.starting, + pigeon.PeripheralAdvertisingState.advertising => + UniversalBlePeripheralAdvertisingState.advertising, + pigeon.PeripheralAdvertisingState.stopping => + UniversalBlePeripheralAdvertisingState.stopping, + pigeon.PeripheralAdvertisingState.error => + UniversalBlePeripheralAdvertisingState.error, + }; + } @override Future addService( @@ -63,25 +110,26 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform } @override - Future removeService(String serviceId) => - _channel.removeService(BleUuidParser.string(serviceId)); + Future removeService(PeripheralServiceId serviceId) => + _channel.removeService(BleUuidParser.string(serviceId.value)); @override Future clearServices() => _channel.clearServices(); @override - Future> getServices() => _channel.getServices(); + Future> getServices() async => + (await _channel.getServices()).map(PeripheralServiceId.new).toList(); @override Future startAdvertising({ - required List services, + required List services, String? localName, int? timeout, ManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse = false, }) { return _channel.startAdvertising( - services.map(BleUuidParser.string).toList(), + services.map((e) => BleUuidParser.string(e.value)).toList(), localName, timeout, UniversalBlePeripheralMapper.toPigeonManufacturerData(manufacturerData), @@ -93,11 +141,15 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform Future stopAdvertising() => _channel.stopAdvertising(); @override - Future updateCharacteristic({ + Future updateCharacteristicValue({ required String characteristicId, required Uint8List value, - String? deviceId, + PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }) { + final String? deviceId = switch (target) { + PeripheralUpdateAllSubscribed() => null, + PeripheralUpdateSingleDevice(deviceId: final id) => id, + }; return _channel.updateCharacteristic( BleUuidParser.string(characteristicId), value, @@ -110,8 +162,27 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform _channel.getSubscribedCentrals(characteristicId); @override - void onAdvertisingStatusUpdate(bool advertising, String? error) { - super.advertisingStatusUpdateCallback?.call(advertising, error); + void onAdvertisingStateChange( + pigeon.PeripheralAdvertisingState state, + String? error, + ) { + final mapped = switch (state) { + pigeon.PeripheralAdvertisingState.idle => + UniversalBlePeripheralAdvertisingState.idle, + pigeon.PeripheralAdvertisingState.starting => + UniversalBlePeripheralAdvertisingState.starting, + pigeon.PeripheralAdvertisingState.advertising => + UniversalBlePeripheralAdvertisingState.advertising, + pigeon.PeripheralAdvertisingState.stopping => + UniversalBlePeripheralAdvertisingState.stopping, + pigeon.PeripheralAdvertisingState.error => + UniversalBlePeripheralAdvertisingState.error, + }; + if (!_eventController.isClosed) { + _eventController.add( + UniversalBlePeripheralAdvertisingStateChanged(mapped, error), + ); + } } @override @@ -121,22 +192,32 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform bool isSubscribed, String? name, ) { - super.subscriptionChangeCallback?.call( - deviceId, - characteristicId, - isSubscribed, - name, - ); + if (!_eventController.isClosed) { + _eventController.add( + UniversalBlePeripheralCharacteristicSubscriptionChanged( + deviceId: deviceId, + characteristicId: characteristicId, + isSubscribed: isSubscribed, + name: name, + ), + ); + } } @override void onConnectionStateChange(String deviceId, bool connected) { - super.connectionStateChangeCallback?.call(deviceId, connected); + if (!_eventController.isClosed) { + _eventController.add( + UniversalBlePeripheralConnectionStateChanged(deviceId, connected), + ); + } } @override void onMtuChange(String deviceId, int mtu) { - super.mtuChangeCallback?.call(deviceId, mtu); + if (!_eventController.isClosed) { + _eventController.add(UniversalBlePeripheralMtuChanged(deviceId, mtu)); + } } @override @@ -146,9 +227,12 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform int offset, Uint8List? value, ) { - final result = super - .readRequestCallback - ?.call(deviceId, characteristicId, offset, value); + final result = _readRequestHandler?.call( + deviceId, + characteristicId, + offset, + value, + ); if (result == null) return null; return pigeon.PeripheralReadRequestResult( value: result.value, @@ -159,7 +243,9 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform @override void onServiceAdded(String serviceId, String? error) { - super.serviceAddedCallback?.call(serviceId, error); + if (!_eventController.isClosed) { + _eventController.add(UniversalBlePeripheralServiceAdded(serviceId, error)); + } if (!_serviceResultController.isClosed) { _serviceResultController.add((serviceId: serviceId, error: error)); } @@ -172,7 +258,7 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform int offset, Uint8List? value, ) { - final result = super.writeRequestCallback?.call( + final result = _writeRequestHandler?.call( deviceId, characteristicId, offset, @@ -194,6 +280,9 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform if (!_serviceResultController.isClosed) { _serviceResultController.close(); } + if (!_eventController.isClosed) { + _eventController.close(); + } if (identical(_instance, this)) { _instance = null; } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart index 73976e40..8c76b939 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -2,45 +2,106 @@ import 'dart:typed_data'; import 'package:universal_ble/universal_ble.dart'; -typedef OnPeripheralAdvertisingStatusUpdate = void Function( - bool advertising, String? error); -typedef OnPeripheralCharacteristicSubscriptionChange = void Function( - String deviceId, - String characteristicId, - bool isSubscribed, - String? name, -); -typedef OnPeripheralConnectionStateChange = void Function( - String deviceId, - bool connected, -); typedef OnPeripheralReadRequest = BleReadRequestResult? Function( String deviceId, String characteristicId, int offset, Uint8List? value, ); -typedef OnPeripheralServiceAdded = void Function( - String serviceId, String? error); typedef OnPeripheralWriteRequest = BleWriteRequestResult? Function( String deviceId, String characteristicId, int offset, Uint8List? value, ); -typedef OnPeripheralMtuChange = void Function(String deviceId, int mtu); + +enum UniversalBlePeripheralReadinessState { + unknown, + ready, + bluetoothOff, + unauthorized, + unsupported, +} + +enum UniversalBlePeripheralAdvertisingState { + idle, + starting, + advertising, + stopping, + error, +} + +sealed class UniversalBlePeripheralEvent {} + +class UniversalBlePeripheralAdvertisingStateChanged + extends UniversalBlePeripheralEvent { + final UniversalBlePeripheralAdvertisingState state; + final String? error; + UniversalBlePeripheralAdvertisingStateChanged(this.state, this.error); +} + +class UniversalBlePeripheralCharacteristicSubscriptionChanged + extends UniversalBlePeripheralEvent { + final String deviceId; + final String characteristicId; + final bool isSubscribed; + final String? name; + UniversalBlePeripheralCharacteristicSubscriptionChanged({ + required this.deviceId, + required this.characteristicId, + required this.isSubscribed, + required this.name, + }); +} + +class UniversalBlePeripheralConnectionStateChanged + extends UniversalBlePeripheralEvent { + final String deviceId; + final bool connected; + UniversalBlePeripheralConnectionStateChanged(this.deviceId, this.connected); +} + +class UniversalBlePeripheralServiceAdded extends UniversalBlePeripheralEvent { + final String serviceId; + final String? error; + UniversalBlePeripheralServiceAdded(this.serviceId, this.error); +} + +class UniversalBlePeripheralMtuChanged extends UniversalBlePeripheralEvent { + final String deviceId; + final int mtu; + UniversalBlePeripheralMtuChanged(this.deviceId, this.mtu); +} + +class PeripheralServiceId { + final String value; + const PeripheralServiceId(this.value); +} + +sealed class PeripheralUpdateTarget { + const PeripheralUpdateTarget(); +} + +class PeripheralUpdateAllSubscribed extends PeripheralUpdateTarget { + const PeripheralUpdateAllSubscribed(); +} + +class PeripheralUpdateSingleDevice extends PeripheralUpdateTarget { + final String deviceId; + const PeripheralUpdateSingleDevice(this.deviceId); +} abstract class UniversalBlePeripheralPlatform { - OnPeripheralAdvertisingStatusUpdate? advertisingStatusUpdateCallback; - OnPeripheralCharacteristicSubscriptionChange? subscriptionChangeCallback; - OnPeripheralConnectionStateChange? connectionStateChangeCallback; - OnPeripheralReadRequest? readRequestCallback; - OnPeripheralServiceAdded? serviceAddedCallback; - OnPeripheralWriteRequest? writeRequestCallback; - OnPeripheralMtuChange? mtuChangeCallback; + Stream get eventStream; - Future isSupported(); - Future isAdvertising(); + void setRequestHandlers({ + OnPeripheralReadRequest? onReadRequest, + OnPeripheralWriteRequest? onWriteRequest, + }); + + Future isFeatureSupported(); + Future getReadinessState(); + Future getAdvertisingState(); Future addService( BleService service, { @@ -48,21 +109,21 @@ abstract class UniversalBlePeripheralPlatform { Duration? timeout, }); - Future removeService(String serviceId); + Future removeService(PeripheralServiceId serviceId); Future clearServices(); - Future> getServices(); + Future> getServices(); Future startAdvertising({ - required List services, + required List services, String? localName, int? timeout, ManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse = false, }); Future stopAdvertising(); - Future updateCharacteristic({ + Future updateCharacteristicValue({ required String characteristicId, required Uint8List value, - String? deviceId, + PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }); /// Returns GATT central device ids currently subscribed to [characteristicId]. @@ -78,6 +139,16 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { UnsupportedError _notSupported() => UnsupportedError('BLE peripheral mode is not supported on this platform'); + @override + Stream get eventStream => + const Stream.empty(); + + @override + void setRequestHandlers({ + OnPeripheralReadRequest? onReadRequest, + OnPeripheralWriteRequest? onWriteRequest, + }) {} + @override Future addService( BleService service, { @@ -93,26 +164,31 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { } @override - Future> getServices() async { + Future> getServices() async { throw _notSupported(); } @override - Future isAdvertising() async { + Future getAdvertisingState() async { throw _notSupported(); } @override - Future isSupported() async => false; + Future isFeatureSupported() async => false; + + @override + Future getReadinessState() async { + return UniversalBlePeripheralReadinessState.unsupported; + } @override - Future removeService(String serviceId) async { + Future removeService(PeripheralServiceId serviceId) async { throw _notSupported(); } @override Future startAdvertising({ - required List services, + required List services, String? localName, int? timeout, ManufacturerData? manufacturerData, @@ -127,10 +203,10 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { } @override - Future updateCharacteristic({ + Future updateCharacteristicValue({ required String characteristicId, required Uint8List value, - String? deviceId, + PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }) async { throw _notSupported(); } diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index 8bc0fefc..bc342943 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -124,6 +124,22 @@ enum AndroidScanMode { opportunistic, } +enum PeripheralReadinessState { + unknown, + ready, + bluetoothOff, + unauthorized, + unsupported, +} + +enum PeripheralAdvertisingState { + idle, + starting, + advertising, + stopping, + error, +} + /// Unified error codes for all platforms enum UniversalBleErrorCode { unknownError, @@ -960,53 +976,59 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is AndroidScanMode) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is UniversalBleErrorCode) { + } else if (value is PeripheralReadinessState) { buffer.putUint8(131); writeValue(buffer, value.index); - } else if (value is UniversalBleScanResult) { + } else if (value is PeripheralAdvertisingState) { buffer.putUint8(132); + writeValue(buffer, value.index); + } else if (value is UniversalBleErrorCode) { + buffer.putUint8(133); + writeValue(buffer, value.index); + } else if (value is UniversalBleScanResult) { + buffer.putUint8(134); writeValue(buffer, value.encode()); } else if (value is UniversalBleService) { - buffer.putUint8(133); + buffer.putUint8(135); writeValue(buffer, value.encode()); } else if (value is UniversalBleCharacteristic) { - buffer.putUint8(134); + buffer.putUint8(136); writeValue(buffer, value.encode()); } else if (value is UniversalBleDescriptor) { - buffer.putUint8(135); + buffer.putUint8(137); writeValue(buffer, value.encode()); } else if (value is AndroidOptions) { - buffer.putUint8(136); + buffer.putUint8(138); writeValue(buffer, value.encode()); } else if (value is UniversalScanConfig) { - buffer.putUint8(137); + buffer.putUint8(139); writeValue(buffer, value.encode()); } else if (value is UniversalScanFilter) { - buffer.putUint8(138); + buffer.putUint8(140); writeValue(buffer, value.encode()); } else if (value is UniversalManufacturerDataFilter) { - buffer.putUint8(139); + buffer.putUint8(141); writeValue(buffer, value.encode()); } else if (value is UniversalManufacturerData) { - buffer.putUint8(140); + buffer.putUint8(142); writeValue(buffer, value.encode()); } else if (value is PeripheralService) { - buffer.putUint8(141); + buffer.putUint8(143); writeValue(buffer, value.encode()); } else if (value is PeripheralCharacteristic) { - buffer.putUint8(142); + buffer.putUint8(144); writeValue(buffer, value.encode()); } else if (value is PeripheralDescriptor) { - buffer.putUint8(143); + buffer.putUint8(145); writeValue(buffer, value.encode()); } else if (value is PeripheralReadRequestResult) { - buffer.putUint8(144); + buffer.putUint8(146); writeValue(buffer, value.encode()); } else if (value is PeripheralWriteRequestResult) { - buffer.putUint8(145); + buffer.putUint8(147); writeValue(buffer, value.encode()); } else if (value is PeripheralManufacturerData) { - buffer.putUint8(146); + buffer.putUint8(148); writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); @@ -1024,36 +1046,42 @@ class _PigeonCodec extends StandardMessageCodec { return value == null ? null : AndroidScanMode.values[value]; case 131: final value = readValue(buffer) as int?; - return value == null ? null : UniversalBleErrorCode.values[value]; + return value == null ? null : PeripheralReadinessState.values[value]; case 132: - return UniversalBleScanResult.decode(readValue(buffer)!); + final value = readValue(buffer) as int?; + return value == null ? null : PeripheralAdvertisingState.values[value]; case 133: - return UniversalBleService.decode(readValue(buffer)!); + final value = readValue(buffer) as int?; + return value == null ? null : UniversalBleErrorCode.values[value]; case 134: - return UniversalBleCharacteristic.decode(readValue(buffer)!); + return UniversalBleScanResult.decode(readValue(buffer)!); case 135: - return UniversalBleDescriptor.decode(readValue(buffer)!); + return UniversalBleService.decode(readValue(buffer)!); case 136: - return AndroidOptions.decode(readValue(buffer)!); + return UniversalBleCharacteristic.decode(readValue(buffer)!); case 137: - return UniversalScanConfig.decode(readValue(buffer)!); + return UniversalBleDescriptor.decode(readValue(buffer)!); case 138: - return UniversalScanFilter.decode(readValue(buffer)!); + return AndroidOptions.decode(readValue(buffer)!); case 139: - return UniversalManufacturerDataFilter.decode(readValue(buffer)!); + return UniversalScanConfig.decode(readValue(buffer)!); case 140: - return UniversalManufacturerData.decode(readValue(buffer)!); + return UniversalScanFilter.decode(readValue(buffer)!); case 141: - return PeripheralService.decode(readValue(buffer)!); + return UniversalManufacturerDataFilter.decode(readValue(buffer)!); case 142: - return PeripheralCharacteristic.decode(readValue(buffer)!); + return UniversalManufacturerData.decode(readValue(buffer)!); case 143: - return PeripheralDescriptor.decode(readValue(buffer)!); + return PeripheralService.decode(readValue(buffer)!); case 144: - return PeripheralReadRequestResult.decode(readValue(buffer)!); + return PeripheralCharacteristic.decode(readValue(buffer)!); case 145: - return PeripheralWriteRequestResult.decode(readValue(buffer)!); + return PeripheralDescriptor.decode(readValue(buffer)!); case 146: + return PeripheralReadRequestResult.decode(readValue(buffer)!); + case 147: + return PeripheralWriteRequestResult.decode(readValue(buffer)!); + case 148: return PeripheralManufacturerData.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -1654,8 +1682,8 @@ class UniversalBlePeripheralChannel { final String pigeonVar_messageChannelSuffix; - Future isAdvertising() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising$pigeonVar_messageChannelSuffix'; + Future getAdvertisingState() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getAdvertisingState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1667,14 +1695,14 @@ class UniversalBlePeripheralChannel { final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( pigeonVar_replyList, pigeonVar_channelName, - isNullValid: true, + isNullValid: false, ) ; - return pigeonVar_replyValue as bool?; + return pigeonVar_replyValue! as PeripheralAdvertisingState; } - Future isSupported() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported$pigeonVar_messageChannelSuffix'; + Future isFeatureSupported() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1692,6 +1720,25 @@ class UniversalBlePeripheralChannel { return pigeonVar_replyValue! as bool; } + Future getReadinessState() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return pigeonVar_replyValue! as PeripheralReadinessState; + } + Future stopAdvertising() async { final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( @@ -1851,7 +1898,7 @@ abstract class UniversalBlePeripheralCallback { void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); - void onAdvertisingStatusUpdate(bool advertising, String? error); + void onAdvertisingStateChange(PeripheralAdvertisingState state, String? error); void onServiceAdded(String serviceId, String? error); @@ -1935,17 +1982,17 @@ abstract class UniversalBlePeripheralCallback { } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStateChange$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { final List args = message! as List; - final bool arg_advertising = args[0]! as bool; + final PeripheralAdvertisingState arg_state = args[0]! as PeripheralAdvertisingState; final String? arg_error = args[1] as String?; try { - api.onAdvertisingStatusUpdate(arg_advertising, arg_error); + api.onAdvertisingStateChange(arg_state, arg_error); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); diff --git a/pigeon/universal_ble.dart b/pigeon/universal_ble.dart index f81f8e7b..1442a797 100644 --- a/pigeon/universal_ble.dart +++ b/pigeon/universal_ble.dart @@ -290,11 +290,28 @@ class PeripheralManufacturerData { {required this.manufacturerId, required this.data}); } +enum PeripheralReadinessState { + unknown, + ready, + bluetoothOff, + unauthorized, + unsupported, +} + +enum PeripheralAdvertisingState { + idle, + starting, + advertising, + stopping, + error, +} + /// Flutter -> Native (peripheral) @HostApi() abstract class UniversalBlePeripheralChannel { - bool? isAdvertising(); - bool isSupported(); + PeripheralAdvertisingState getAdvertisingState(); + bool isFeatureSupported(); + PeripheralReadinessState getReadinessState(); void stopAdvertising(); void addService(PeripheralService service); void removeService(String serviceId); @@ -341,7 +358,7 @@ abstract class UniversalBlePeripheralCallback { bool isSubscribed, String? name, ); - void onAdvertisingStatusUpdate(bool advertising, String? error); + void onAdvertisingStateChange(PeripheralAdvertisingState state, String? error); void onServiceAdded(String serviceId, String? error); void onMtuChange(String deviceId, int mtu); void onConnectionStateChange(String deviceId, bool connected); diff --git a/test/universal_ble_peripheral_test.dart b/test/universal_ble_peripheral_test.dart index 6569218f..297bafa4 100644 --- a/test/universal_ble_peripheral_test.dart +++ b/test/universal_ble_peripheral_test.dart @@ -4,6 +4,81 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:universal_ble/src/universal_ble_peripheral/universal_ble_peripheral_mapper.dart'; import 'package:universal_ble/universal_ble.dart'; +class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { + int disposeCount = 0; + PeripheralServiceId? removedServiceId; + List? advertisedServices; + + @override + Stream get eventStream => + const Stream.empty(); + + @override + void setRequestHandlers({ + OnPeripheralReadRequest? onReadRequest, + OnPeripheralWriteRequest? onWriteRequest, + }) {} + + @override + Future addService( + BleService service, { + bool primary = true, + Duration? timeout, + }) async {} + + @override + Future clearServices() async {} + + @override + void dispose() { + disposeCount += 1; + } + + @override + Future getAdvertisingState() async => + UniversalBlePeripheralAdvertisingState.idle; + + @override + Future getReadinessState() async => + UniversalBlePeripheralReadinessState.ready; + + @override + Future> getServices() async => const []; + + @override + Future> getSubscribedCentrals(String characteristicId) async => + [characteristicId]; + + @override + Future isFeatureSupported() async => true; + + @override + Future removeService(PeripheralServiceId serviceId) async { + removedServiceId = serviceId; + } + + @override + Future startAdvertising({ + required List services, + String? localName, + int? timeout, + ManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse = false, + }) async { + advertisedServices = services; + } + + @override + Future stopAdvertising() async {} + + @override + Future updateCharacteristicValue({ + required String characteristicId, + required Uint8List value, + PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), + }) async {} +} + void main() { test('peripheral request result models store values', () { final read = BleReadRequestResult( @@ -110,4 +185,32 @@ void main() { expect(mapped!.manufacturerId, 0x004C); expect(mapped.data, Uint8List.fromList([0x01, 0x02])); }); + + test('instance client normalizes service IDs for remove/start', () async { + final fake = _FakePeripheralPlatform(); + final client = UniversalBlePeripheralClient(platform: fake); + + await client.removeService(const PeripheralServiceId('180f')); + await client.startAdvertising( + services: const [PeripheralServiceId('180f')], + ); + + expect( + fake.removedServiceId?.value, + BleUuidParser.string('180f'), + ); + expect( + fake.advertisedServices?.single.value, + BleUuidParser.string('180f'), + ); + }); + + test('static setInstance disposes previous platform', () async { + final first = _FakePeripheralPlatform(); + final second = _FakePeripheralPlatform(); + UniversalBlePeripheral.setInstance(first); + UniversalBlePeripheral.setInstance(second); + + expect(first.disposeCount, 1); + }); } diff --git a/windows/src/generated/universal_ble.g.cpp b/windows/src/generated/universal_ble.g.cpp index e3dd43af..3f0fecde 100644 --- a/windows/src/generated/universal_ble.g.cpp +++ b/windows/src/generated/universal_ble.g.cpp @@ -1551,51 +1551,61 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( case 131: { 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(enum_arg_value)); + return encodable_enum_arg.IsNull() ? EncodableValue() : CustomEncodableValue(static_cast(enum_arg_value)); } case 132: { - return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get(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(enum_arg_value)); } case 133: { - return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get(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(enum_arg_value)); } case 134: { - return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get(ReadValue(stream)))); } case 135: { - return CustomEncodableValue(UniversalBleDescriptor::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get(ReadValue(stream)))); } case 136: { - return CustomEncodableValue(AndroidOptions::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); } case 137: { - return CustomEncodableValue(UniversalScanConfig::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalBleDescriptor::FromEncodableList(std::get(ReadValue(stream)))); } case 138: { - return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(AndroidOptions::FromEncodableList(std::get(ReadValue(stream)))); } case 139: { - return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalScanConfig::FromEncodableList(std::get(ReadValue(stream)))); } case 140: { - return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get(ReadValue(stream)))); } case 141: { - return CustomEncodableValue(PeripheralService::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get(ReadValue(stream)))); } case 142: { - return CustomEncodableValue(PeripheralCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); } case 143: { - return CustomEncodableValue(PeripheralDescriptor::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(PeripheralService::FromEncodableList(std::get(ReadValue(stream)))); } case 144: { - return CustomEncodableValue(PeripheralReadRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(PeripheralCharacteristic::FromEncodableList(std::get(ReadValue(stream)))); } case 145: { - return CustomEncodableValue(PeripheralWriteRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(PeripheralDescriptor::FromEncodableList(std::get(ReadValue(stream)))); } case 146: { + return CustomEncodableValue(PeripheralReadRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + } + case 147: { + return CustomEncodableValue(PeripheralWriteRequestResult::FromEncodableList(std::get(ReadValue(stream)))); + } + case 148: { return CustomEncodableValue(PeripheralManufacturerData::FromEncodableList(std::get(ReadValue(stream)))); } default: @@ -1617,83 +1627,93 @@ void PigeonInternalCodecSerializer::WriteValue( WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); return; } - if (custom_value->type() == typeid(UniversalBleErrorCode)) { + if (custom_value->type() == typeid(PeripheralReadinessState)) { stream->WriteByte(131); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(PeripheralAdvertisingState)) { + stream->WriteByte(132); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(UniversalBleErrorCode)) { + stream->WriteByte(133); WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); return; } if (custom_value->type() == typeid(UniversalBleScanResult)) { - stream->WriteByte(132); + stream->WriteByte(134); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(UniversalBleService)) { - stream->WriteByte(133); + stream->WriteByte(135); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(UniversalBleCharacteristic)) { - stream->WriteByte(134); + stream->WriteByte(136); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(UniversalBleDescriptor)) { - stream->WriteByte(135); + stream->WriteByte(137); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(AndroidOptions)) { - stream->WriteByte(136); + stream->WriteByte(138); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(UniversalScanConfig)) { - stream->WriteByte(137); + stream->WriteByte(139); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(UniversalScanFilter)) { - stream->WriteByte(138); + stream->WriteByte(140); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(UniversalManufacturerDataFilter)) { - stream->WriteByte(139); + stream->WriteByte(141); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(UniversalManufacturerData)) { - stream->WriteByte(140); + stream->WriteByte(142); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(PeripheralService)) { - stream->WriteByte(141); + stream->WriteByte(143); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(PeripheralCharacteristic)) { - stream->WriteByte(142); + stream->WriteByte(144); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(PeripheralDescriptor)) { - stream->WriteByte(143); + stream->WriteByte(145); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(PeripheralReadRequestResult)) { - stream->WriteByte(144); + stream->WriteByte(146); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(PeripheralWriteRequestResult)) { - stream->WriteByte(145); + stream->WriteByte(147); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(PeripheralManufacturerData)) { - stream->WriteByte(146); + stream->WriteByte(148); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } @@ -2603,22 +2623,17 @@ void UniversalBlePeripheralChannel::SetUp( const std::string& message_channel_suffix) { const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isAdvertising" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getAdvertisingState" + prepended_suffix, &GetCodec()); if (api != nullptr) { channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - ErrorOr> output = api->IsAdvertising(); + ErrorOr output = api->GetAdvertisingState(); if (output.has_error()) { reply(WrapError(output.error())); return; } EncodableList wrapped; - auto output_optional = std::move(output).TakeValue(); - if (output_optional) { - wrapped.push_back(EncodableValue(std::move(output_optional).value())); - } else { - wrapped.push_back(EncodableValue()); - } + wrapped.push_back(CustomEncodableValue(std::move(output).TakeValue())); reply(EncodableValue(std::move(wrapped))); } catch (const std::exception& exception) { reply(WrapError(exception.what())); @@ -2629,11 +2644,11 @@ void UniversalBlePeripheralChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isSupported" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported" + prepended_suffix, &GetCodec()); if (api != nullptr) { channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { - ErrorOr output = api->IsSupported(); + ErrorOr output = api->IsFeatureSupported(); if (output.has_error()) { reply(WrapError(output.error())); return; @@ -2649,6 +2664,27 @@ void UniversalBlePeripheralChannel::SetUp( channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + ErrorOr output = api->GetReadinessState(); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(CustomEncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising" + prepended_suffix, &GetCodec()); if (api != nullptr) { @@ -3000,15 +3036,15 @@ void UniversalBlePeripheralCallback::OnCharacteristicSubscriptionChange( }); } -void UniversalBlePeripheralCallback::OnAdvertisingStatusUpdate( - bool advertising_arg, +void UniversalBlePeripheralCallback::OnAdvertisingStateChange( + const PeripheralAdvertisingState& state_arg, const std::string* error_arg, std::function&& on_success, std::function&& on_error) { - const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStatusUpdate" + message_channel_suffix_; + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStateChange" + message_channel_suffix_; BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - EncodableValue(advertising_arg), + CustomEncodableValue(state_arg), error_arg ? EncodableValue(*error_arg) : EncodableValue(), }); channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { diff --git a/windows/src/generated/universal_ble.g.h b/windows/src/generated/universal_ble.g.h index b09764fb..b58b47aa 100644 --- a/windows/src/generated/universal_ble.g.h +++ b/windows/src/generated/universal_ble.g.h @@ -76,6 +76,22 @@ enum class AndroidScanMode { kOpportunistic = 3 }; +enum class PeripheralReadinessState { + kUnknown = 0, + kReady = 1, + kBluetoothOff = 2, + kUnauthorized = 3, + kUnsupported = 4 +}; + +enum class PeripheralAdvertisingState { + kIdle = 0, + kStarting = 1, + kAdvertising = 2, + kStopping = 3, + kError = 4 +}; + // Unified error codes for all platforms enum class UniversalBleErrorCode { kUnknownError = 0, @@ -900,8 +916,9 @@ class UniversalBlePeripheralChannel { UniversalBlePeripheralChannel(const UniversalBlePeripheralChannel&) = delete; UniversalBlePeripheralChannel& operator=(const UniversalBlePeripheralChannel&) = delete; virtual ~UniversalBlePeripheralChannel() {} - virtual ErrorOr> IsAdvertising() = 0; - virtual ErrorOr IsSupported() = 0; + virtual ErrorOr GetAdvertisingState() = 0; + virtual ErrorOr IsFeatureSupported() = 0; + virtual ErrorOr GetReadinessState() = 0; virtual std::optional StopAdvertising() = 0; virtual std::optional AddService(const PeripheralService& service) = 0; virtual std::optional RemoveService(const std::string& service_id) = 0; @@ -967,8 +984,8 @@ class UniversalBlePeripheralCallback { const std::string* name, std::function&& on_success, std::function&& on_error); - void OnAdvertisingStatusUpdate( - bool advertising, + void OnAdvertisingStateChange( + const PeripheralAdvertisingState& state, const std::string* error, std::function&& on_success, std::function&& on_error); diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index 8e81c183..11cfb8d5 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -1619,23 +1619,25 @@ void UniversalBlePlugin::GattCharacteristicValueChanged( } } -std::optional UniversalBlePlugin::Initialize() { - if (!bluetooth_radio_) { - return create_flutter_error(UniversalBleErrorCode::kBluetoothNotAvailable, - "Bluetooth is not available"); - } - return std::nullopt; -} - -ErrorOr> UniversalBlePlugin::IsAdvertising() { +ErrorOr UniversalBlePlugin::GetAdvertisingState() { std::lock_guard lock(peripheral_mutex_); if (peripheral_service_provider_map_.empty()) { - return std::optional(false); + return PeripheralAdvertisingState::kIdle; } - return std::optional(AreAllPeripheralServicesStarted()); + return AreAllPeripheralServicesStarted() ? PeripheralAdvertisingState::kAdvertising + : PeripheralAdvertisingState::kIdle; } -ErrorOr UniversalBlePlugin::IsSupported() { return bluetooth_radio_ != nullptr; } +ErrorOr UniversalBlePlugin::IsFeatureSupported() { + return bluetooth_radio_ != nullptr; +} + +ErrorOr UniversalBlePlugin::GetReadinessState() { + if (!bluetooth_radio_) { + return PeripheralReadinessState::kUnsupported; + } + return PeripheralReadinessState::kReady; +} std::optional UniversalBlePlugin::StopAdvertising() { std::lock_guard lock(peripheral_mutex_); @@ -1646,8 +1648,9 @@ std::optional UniversalBlePlugin::StopAdvertising() { } } ui_thread_handler_.Post([this] { - peripheral_callback_channel_->OnAdvertisingStatusUpdate( - false, nullptr, SuccessCallback, ErrorCallback); + peripheral_callback_channel_->OnAdvertisingStateChange( + PeripheralAdvertisingState::kIdle, nullptr, SuccessCallback, + ErrorCallback); }); return std::nullopt; } @@ -2138,15 +2141,17 @@ void UniversalBlePlugin::PeripheralAdvertisementStatusChanged( if (args.Error() != BluetoothError::Success) { auto error_str = ParsePeripheralBluetoothError(args.Error()); ui_thread_handler_.Post([this, error_str] { - peripheral_callback_channel_->OnAdvertisingStatusUpdate( - false, &error_str, SuccessCallback, ErrorCallback); + peripheral_callback_channel_->OnAdvertisingStateChange( + PeripheralAdvertisingState::kError, &error_str, SuccessCallback, + ErrorCallback); }); return; } if (AreAllPeripheralServicesStarted()) { ui_thread_handler_.Post([this] { - peripheral_callback_channel_->OnAdvertisingStatusUpdate( - true, nullptr, SuccessCallback, ErrorCallback); + peripheral_callback_channel_->OnAdvertisingStateChange( + PeripheralAdvertisingState::kAdvertising, nullptr, SuccessCallback, + ErrorCallback); }); } } diff --git a/windows/src/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h index 6f7fd6c1..45f2575f 100644 --- a/windows/src/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -281,9 +281,9 @@ class UniversalBlePlugin : public flutter::Plugin, result) override; // UniversalBlePeripheralChannel implementation. - std::optional Initialize() override; - ErrorOr> IsAdvertising() override; - ErrorOr IsSupported() override; + ErrorOr GetAdvertisingState() override; + ErrorOr IsFeatureSupported() override; + ErrorOr GetReadinessState() override; std::optional StopAdvertising() override; std::optional AddService(const PeripheralService &service) override; std::optional RemoveService(const std::string &service_id) override; From ef0e623e85602ad5a217b9b67ecd0ceee89e04b2 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 16:07:50 +0200 Subject: [PATCH 17/23] Refactor Bluetooth availability methods for consistency and clarity - Renamed `getBluetoothAvailabilityState()` to `getAvailabilityState()` across all relevant files for uniformity. - Updated method calls in documentation and example code to reflect the new naming convention. - Adjusted permission checking method from `hasPermissions()` to `isPermissionGranted()` for improved readability. - Changed `receivesAdvertisements()` to `isReceivingAdvertisements()` to enhance clarity in intent. --- README.md | 8 ++++---- example/lib/data/mock_universal_ble.dart | 2 +- example/lib/home/home.dart | 7 ++++--- lib/src/models/ble_device.dart | 4 ++-- lib/src/universal_ble.dart | 16 ++++++++-------- .../universal_ble_linux/universal_ble_linux.dart | 2 +- .../universal_ble_pigeon_channel.dart | 6 ++++-- lib/src/universal_ble_platform_interface.dart | 10 ++++++---- lib/src/universal_ble_web/universal_ble_web.dart | 4 ++-- test/universal_ble_test_mock.dart | 2 +- 10 files changed, 33 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index a46477b5..29095d98 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | unpair | ✔️ | ❌ | ❌ | ✔️ | ✔️ | ❌ | | isPaired | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | | onPairingStateChange | ✔️ | ⏺ | ⏺ | ✔️ | ✔️ | ⏺ | -| getBluetoothAvailabilityState | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | +| getAvailabilityState | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | | enable/disable Bluetooth | ✔️ | ❌ | ❌ | ✔️ | ✔️ | ❌ | | onAvailabilityChange | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | | requestMtu | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | @@ -135,7 +135,7 @@ UniversalBle.isScanning(); Before initiating a scan, ensure that Bluetooth is available: ```dart -AvailabilityState state = await UniversalBle.getBluetoothAvailabilityState(); +AvailabilityState state = await UniversalBle.getAvailabilityState(); // Start scan only if Bluetooth is powered on if (state == AvailabilityState.poweredOn) { UniversalBle.startScan(); @@ -427,7 +427,7 @@ bleDevice.unpair(); ```dart // Get current Bluetooth availability state -AvailabilityState availabilityState = UniversalBle.getBluetoothAvailabilityState(); // e.g. poweredOff or poweredOn, +AvailabilityState availabilityState = UniversalBle.getAvailabilityState(); // e.g. poweredOff or poweredOn, // Receive Bluetooth availability changes UniversalBle.onAvailabilityChange = (state) { @@ -918,7 +918,7 @@ Future resetBleState() async { // Check Bluetooth availability AvailabilityState availabilityState = - await UniversalBle.getBluetoothAvailabilityState(); + await UniversalBle.getAvailabilityState(); // Skip if Bluetooth is not powered on if (availabilityState != AvailabilityState.poweredOn) { diff --git a/example/lib/data/mock_universal_ble.dart b/example/lib/data/mock_universal_ble.dart index 44a681ac..63413d4b 100644 --- a/example/lib/data/mock_universal_ble.dart +++ b/example/lib/data/mock_universal_ble.dart @@ -66,7 +66,7 @@ class MockUniversalBle extends UniversalBlePlatform { } @override - Future getBluetoothAvailabilityState() async { + Future getAvailabilityState() async { return AvailabilityState.poweredOn; } diff --git a/example/lib/home/home.dart b/example/lib/home/home.dart index d3daea1f..b6affb7e 100644 --- a/example/lib/home/home.dart +++ b/example/lib/home/home.dart @@ -221,13 +221,14 @@ class _CentralHomeState extends State { ), if (BleCapabilities.requiresRuntimePermission) ...[ PlatformButton( - text: 'Has Permissions', + text: 'Is Permission Granted', onPressed: () async { try { - bool hasPermissions = await UniversalBle.hasPermissions( + bool granted = + await UniversalBle.isPermissionGranted( withAndroidFineLocation: false, ); - showSnackbar("Has Permissions: $hasPermissions"); + showSnackbar("Is Permission Granted: $granted"); } catch (e) { showSnackbar(e.toString()); } diff --git a/lib/src/models/ble_device.dart b/lib/src/models/ble_device.dart index 87aefbda..17c41320 100644 --- a/lib/src/models/ble_device.dart +++ b/lib/src/models/ble_device.dart @@ -42,8 +42,8 @@ class BleDevice { /// On web, it returns true if the web browser supports receiving advertisements from this device. /// The rest of the platforms will always return true. - bool get receivesAdvertisements => - UniversalBle.receivesAdvertisements(deviceId); + bool get isReceivingAdvertisements => + UniversalBle.isReceivingAdvertisements(deviceId); BleDevice({ required this.deviceId, diff --git a/lib/src/universal_ble.dart b/lib/src/universal_ble.dart index 91b71798..4f826127 100644 --- a/lib/src/universal_ble.dart +++ b/lib/src/universal_ble.dart @@ -67,9 +67,9 @@ class UniversalBle { /// Get Bluetooth availability state. /// To be notified of updates, set [onAvailabilityChange] listener. - static Future getBluetoothAvailabilityState() async { + static Future getAvailabilityState() async { return await _bleCommandQueue.queueCommand( - () => _platform.getBluetoothAvailabilityState(), + () => _platform.getAvailabilityState(), ); } @@ -77,10 +77,10 @@ class UniversalBle { /// [withAndroidFineLocation] is used to check fine location permission on Android 12+ (API 31+). /// On Android lower than 12, this method will check location permission regardless of the [withAndroidFineLocation] value. /// `Windows`, `Linux` and `Web` will always return true. - static Future hasPermissions({ + static Future isPermissionGranted({ bool withAndroidFineLocation = false, }) async { - return _platform.hasPermissions( + return _platform.isPermissionGranted( withAndroidFineLocation: withAndroidFineLocation, ); } @@ -534,21 +534,21 @@ class UniversalBle { /// If no [id] is provided, all queues will be cleared. static void clearQueue([String? id]) => _bleCommandQueue.clearQueue(id); - /// [receivesAdvertisements] returns true on web if the browser supports receiving advertisements from a certain `deviceId`. + /// [isReceivingAdvertisements] returns true on web if the browser supports receiving advertisements from a certain `deviceId`. /// The rest of the platforms will always return true. /// If true, then you will be getting scanResult updates for this device. /// /// For this feature to work, you need to enable the `chrome://flags/#enable-experimental-web-platform-features` flag. /// Not every browser supports this API yet. /// Even if the browser supports it, sometimes it won't fire any advertisement events even though the device may be sending them. - static bool receivesAdvertisements(String deviceId) => - _platform.receivesAdvertisements(deviceId); + static bool isReceivingAdvertisements(String deviceId) => + _platform.isReceivingAdvertisements(deviceId); /// Get Bluetooth state availability. static set onAvailabilityChange(OnAvailabilityChange? onAvailabilityChange) { _platform.onAvailabilityChange = onAvailabilityChange; if (onAvailabilityChange != null) { - getBluetoothAvailabilityState().then((value) { + getAvailabilityState().then((value) { onAvailabilityChange(value); }).onError((error, stackTrace) => null); } diff --git a/lib/src/universal_ble_linux/universal_ble_linux.dart b/lib/src/universal_ble_linux/universal_ble_linux.dart index 66a3398f..3ade9bad 100644 --- a/lib/src/universal_ble_linux/universal_ble_linux.dart +++ b/lib/src/universal_ble_linux/universal_ble_linux.dart @@ -31,7 +31,7 @@ class UniversalBleLinux extends UniversalBlePlatform { {}; @override - Future getBluetoothAvailabilityState() async { + Future getAvailabilityState() async { await _ensureInitialized(); BlueZAdapter? adapter = _activeAdapter; diff --git a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart index df1b0798..8fadea35 100644 --- a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart +++ b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart @@ -16,7 +16,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { final _channel = UniversalBlePlatformChannel(); @override - Future getBluetoothAvailabilityState() async { + Future getAvailabilityState() async { int state = await _executeWithErrorHandling( () => _channel.getBluetoothAvailabilityState(), ); @@ -180,7 +180,9 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { _executeWithErrorHandling(() => _channel.unPair(deviceId)); @override - Future hasPermissions({bool withAndroidFineLocation = false}) async { + Future isPermissionGranted({ + bool withAndroidFineLocation = false, + }) async { return await _executeWithErrorHandling( () => _channel.hasPermissions(withAndroidFineLocation), ); diff --git a/lib/src/universal_ble_platform_interface.dart b/lib/src/universal_ble_platform_interface.dart index 23907440..885b005c 100644 --- a/lib/src/universal_ble_platform_interface.dart +++ b/lib/src/universal_ble_platform_interface.dart @@ -28,16 +28,18 @@ abstract class UniversalBlePlatform { /// Send latest availability state upon subscribing late final _availabilityStreamController = UniversalBleStreamController( - initialEvent: getBluetoothAvailabilityState, + initialEvent: getAvailabilityState, ); - Future getBluetoothAvailabilityState(); + Future getAvailabilityState(); Future enableBluetooth(); Future disableBluetooth(); - Future hasPermissions({bool withAndroidFineLocation = false}) async { + Future isPermissionGranted({ + bool withAndroidFineLocation = false, + }) async { return true; } @@ -111,7 +113,7 @@ abstract class UniversalBlePlatform { Future setLogLevel(BleLogLevel logLevel) async => UniversalLogger.setLogLevel(logLevel); - bool receivesAdvertisements(String deviceId) => true; + bool isReceivingAdvertisements(String deviceId) => true; /// Streams Stream get scanStream => _scanStreamController.stream; diff --git a/lib/src/universal_ble_web/universal_ble_web.dart b/lib/src/universal_ble_web/universal_ble_web.dart index 2b7f870e..c46b50dd 100644 --- a/lib/src/universal_ble_web/universal_ble_web.dart +++ b/lib/src/universal_ble_web/universal_ble_web.dart @@ -75,7 +75,7 @@ class UniversalBleWeb extends UniversalBlePlatform { } @override - Future getBluetoothAvailabilityState() async { + Future getAvailabilityState() async { bool isSupported = FlutterWebBluetooth.instance.isBluetoothApiSupported; if (!isSupported) return AvailabilityState.unsupported; bool isAvailable = await FlutterWebBluetooth.instance.getAvailability(); @@ -114,7 +114,7 @@ class UniversalBleWeb extends UniversalBlePlatform { } @override - bool receivesAdvertisements(String deviceId) { + bool isReceivingAdvertisements(String deviceId) { // Advertisements do not work on Linux/Web even with the "Experimental Web Platform features" flag enabled. Verified with Chrome Version 128.0.6613.138 if (kIsWeb && defaultTargetPlatform == TargetPlatform.linux) { return false; diff --git a/test/universal_ble_test_mock.dart b/test/universal_ble_test_mock.dart index e8dd54a7..9676a398 100644 --- a/test/universal_ble_test_mock.dart +++ b/test/universal_ble_test_mock.dart @@ -30,7 +30,7 @@ abstract class UniversalBlePlatformMock extends UniversalBlePlatform { } @override - Future getBluetoothAvailabilityState() { + Future getAvailabilityState() { throw UnimplementedError(); } From 4971c5e3fd226a73900bbc18327ce023ee088385 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 17:19:56 +0200 Subject: [PATCH 18/23] Refactor BLE peripheral API to improve clarity and functionality - Replaced `isFeatureSupported()` with `getCapabilities().supportsPeripheralMode()` for better clarity in feature checks. - Renamed `getSubscribedCentrals()` to `getSubscribedClients()` to accurately reflect the terminology used in BLE communication. - Updated documentation and example code to align with the new method names and capabilities structure. - Enhanced the capabilities API to provide detailed support information for peripheral mode and advertising features. --- README.md | 14 ++++--- .../navideck/universal_ble/UniversalBle.g.kt | 24 ++--------- .../UniversalBlePeripheralPlugin.kt | 11 +---- .../universal_ble/UniversalBle.g.swift | 28 ++++--------- .../UniversalBlePeripheralPlugin.swift | 6 +-- example/lib/peripheral/peripheral_home.dart | 2 +- .../universal_ble_peripheral.dart | 20 +++++----- .../universal_ble_peripheral_pigeon.dart | 30 +++++++++++--- ...sal_ble_peripheral_platform_interface.dart | 40 ++++++++++++++++--- .../universal_ble_pigeon/universal_ble.g.dart | 25 ++---------- pigeon/universal_ble.dart | 5 +-- test/universal_ble_peripheral_test.dart | 27 +++++++++++-- windows/src/generated/universal_ble.g.cpp | 25 +----------- windows/src/generated/universal_ble.g.h | 5 +-- windows/src/universal_ble_plugin.cpp | 6 +-- windows/src/universal_ble_plugin.h | 3 +- 16 files changed, 128 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 29095d98..05a8a835 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | API | Android | iOS | macOS | Windows | Linux | Web | | :----------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | -| isFeatureSupported | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getCapabilities | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | getReadinessState\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | getAdvertisingState | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | addService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | @@ -75,11 +75,11 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | startAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | stopAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | updateCharacteristicValue\*\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | -| getSubscribedCentrals | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getSubscribedClients | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | events stream\*\*\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | \* `getReadinessState` returns a snapshot state. Use `eventStream` for ongoing runtime changes. -\*\* `updateCharacteristicValue` supports broadcast to all subscribed centrals or a specific central via `PeripheralUpdateTarget`. +\*\* `updateCharacteristicValue` supports broadcast to all subscribed devices or a specific device via `PeripheralUpdateTarget`. \*\*\* events include advertising state changes, read/write requests, subscription changes, and related peripheral events. ## Getting Started @@ -641,8 +641,8 @@ The error parser automatically converts platform-specific error formats (strings import 'package:universal_ble/universal_ble.dart'; final peripheral = UniversalBlePeripheralClient(); -final ready = await peripheral.isFeatureSupported(); -if (!ready) return; +final caps = await peripheral.getCapabilities(); +if (!caps.supportsPeripheralMode) return; await peripheral.addService( BleService("0000180F-0000-1000-8000-00805F9B34FB", [ @@ -658,6 +658,8 @@ await peripheral.addService( await peripheral.startAdvertising( services: [PeripheralServiceId("0000180F-0000-1000-8000-00805F9B34FB")], localName: "UniversalBlePeripheral", + addManufacturerDataInScanResponse: + caps.supportsManufacturerDataInScanResponse, ); final sub = peripheral.eventStream.listen((event) { @@ -674,7 +676,7 @@ peripheral.setRequestHandlers( ### Breaking changes -- `isSupported()` was replaced by `isFeatureSupported()`. +- `isSupported()` was replaced by `getCapabilities().supportsPeripheralMode`. - `isAdvertising()` was replaced by `getAdvertisingState()`. - Static callback setters were replaced by `eventStream` + `setRequestHandlers(...)`. - `UniversalBlePeripheralClient` is the recommended API; `UniversalBlePeripheral` remains as a singleton facade. diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt index e0448e9f..1fd87c09 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt @@ -1745,7 +1745,6 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger, */ interface UniversalBlePeripheralChannel { fun getAdvertisingState(): PeripheralAdvertisingState - fun isFeatureSupported(): Boolean fun getReadinessState(): PeripheralReadinessState fun stopAdvertising() fun addService(service: PeripheralService) @@ -1755,10 +1754,10 @@ interface UniversalBlePeripheralChannel { fun startAdvertising(services: List, localName: String?, timeout: Long?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Boolean) fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) /** - * Returns peripheral-central device ids currently subscribed to [characteristicId] + * Returns peripheral-client device ids currently subscribed to [characteristicId] * (e.g. HID report characteristic). Used to restore app state after restart. */ - fun getSubscribedCentrals(characteristicId: String): List + fun getSubscribedClients(characteristicId: String): List companion object { /** The codec used by UniversalBlePeripheralChannel. */ @@ -1784,21 +1783,6 @@ interface UniversalBlePeripheralChannel { channel.setMessageHandler(null) } } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - listOf(api.isFeatureSupported()) - } catch (exception: Throwable) { - UniversalBlePigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState$separatedMessageChannelSuffix", codec) if (api != null) { @@ -1940,13 +1924,13 @@ interface UniversalBlePeripheralChannel { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$separatedMessageChannelSuffix", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedClients$separatedMessageChannelSuffix", codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List val characteristicIdArg = args[0] as String val wrapped: List = try { - listOf(api.getSubscribedCentrals(characteristicIdArg)) + listOf(api.getSubscribedClients(characteristicIdArg)) } catch (exception: Throwable) { UniversalBlePigeonUtils.wrapError(exception) } diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index d9f72764..bbebf23f 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -104,16 +104,9 @@ class UniversalBlePeripheralPlugin( override fun getAdvertisingState(): PeripheralAdvertisingState = advertisingState - override fun isFeatureSupported(): Boolean { - val adapter = bluetoothManager.adapter ?: return false - if (!adapter.isMultipleAdvertisementSupported) { - return false - } - return true - } - override fun getReadinessState(): PeripheralReadinessState { val adapter = bluetoothManager.adapter ?: return PeripheralReadinessState.UNSUPPORTED + if (!adapter.isMultipleAdvertisementSupported) return PeripheralReadinessState.UNSUPPORTED if (!adapter.isEnabled) return PeripheralReadinessState.BLUETOOTH_OFF return PeripheralReadinessState.READY } @@ -236,7 +229,7 @@ class UniversalBlePeripheralPlugin( } } - override fun getSubscribedCentrals(characteristicId: String): List { + override fun getSubscribedClients(characteristicId: String): List { synchronized(subscribedCharDevicesMap) { return subscribedCharDevicesMap.entries .filter { (_, chars) -> diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift index 4adee68e..69acc0ea 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift @@ -1582,7 +1582,6 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol { /// Generated protocol from Pigeon that represents a handler of messages from Flutter. protocol UniversalBlePeripheralChannel { func getAdvertisingState() throws -> PeripheralAdvertisingState - func isFeatureSupported() throws -> Bool func getReadinessState() throws -> PeripheralReadinessState func stopAdvertising() throws func addService(service: PeripheralService) throws @@ -1591,9 +1590,9 @@ protocol UniversalBlePeripheralChannel { func getServices() throws -> [String] func startAdvertising(services: [String], localName: String?, timeout: Int64?, manufacturerData: PeripheralManufacturerData?, addManufacturerDataInScanResponse: Bool) throws func updateCharacteristic(characteristicId: String, value: FlutterStandardTypedData, deviceId: String?) throws - /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// Returns peripheral-client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. - func getSubscribedCentrals(characteristicId: String) throws -> [String] + func getSubscribedClients(characteristicId: String) throws -> [String] } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -1615,19 +1614,6 @@ class UniversalBlePeripheralChannelSetup { } else { getAdvertisingStateChannel.setMessageHandler(nil) } - let isFeatureSupportedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - isFeatureSupportedChannel.setMessageHandler { _, reply in - do { - let result = try api.isFeatureSupported() - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - isFeatureSupportedChannel.setMessageHandler(nil) - } let getReadinessStateChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { getReadinessStateChannel.setMessageHandler { _, reply in @@ -1746,22 +1732,22 @@ class UniversalBlePeripheralChannelSetup { } else { updateCharacteristicChannel.setMessageHandler(nil) } - /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// Returns peripheral-client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. - let getSubscribedCentralsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + let getSubscribedClientsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedClients\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { - getSubscribedCentralsChannel.setMessageHandler { message, reply in + getSubscribedClientsChannel.setMessageHandler { message, reply in let args = message as! [Any?] let characteristicIdArg = args[0] as! String do { - let result = try api.getSubscribedCentrals(characteristicId: characteristicIdArg) + let result = try api.getSubscribedClients(characteristicId: characteristicIdArg) reply(wrapResult(result)) } catch { reply(wrapError(error)) } } } else { - getSubscribedCentralsChannel.setMessageHandler(nil) + getSubscribedClientsChannel.setMessageHandler(nil) } } } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index a5aef060..0299c509 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -35,10 +35,6 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne advertisingState } - func isFeatureSupported() throws -> Bool { - true - } - func getReadinessState() throws -> PeripheralReadinessState { switch peripheralManager.state { case .poweredOn: @@ -305,7 +301,7 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne centralsLock.unlock() } - func getSubscribedCentrals(characteristicId: String) throws -> [String] { + func getSubscribedClients(characteristicId: String) throws -> [String] { let target = characteristicId.uppercased() centralsLock.lock() defer { centralsLock.unlock() } diff --git a/example/lib/peripheral/peripheral_home.dart b/example/lib/peripheral/peripheral_home.dart index 64fcaeee..d581ac67 100644 --- a/example/lib/peripheral/peripheral_home.dart +++ b/example/lib/peripheral/peripheral_home.dart @@ -69,7 +69,7 @@ class _PeripheralHomeState extends State { } Future _initialize() async { - final supported = await _peripheral.isFeatureSupported(); + final supported = (await _peripheral.getCapabilities()).supportsPeripheralMode; setState(() { _initialized = supported; }); diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart index b11df9f2..ea8a841b 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -25,14 +25,15 @@ class UniversalBlePeripheralClient { ); } - Future isFeatureSupported() => _platform.isFeatureSupported(); - Future getReadinessState() => _platform.getReadinessState(); Future getAdvertisingState() => _platform.getAdvertisingState(); + Future getCapabilities() => + _platform.getCapabilities(); + Future addService( BleService service, { bool primary = true, @@ -79,8 +80,8 @@ class UniversalBlePeripheralClient { target: target, ); - Future> getSubscribedCentrals(String characteristicId) => - _platform.getSubscribedCentrals(BleUuidParser.string(characteristicId)); + Future> getSubscribedClients(String characteristicId) => + _platform.getSubscribedClients(BleUuidParser.string(characteristicId)); } class UniversalBlePeripheral { @@ -116,14 +117,15 @@ class UniversalBlePeripheral { ); } - static Future isFeatureSupported() => _client.isFeatureSupported(); - static Future getReadinessState() => _client.getReadinessState(); static Future getAdvertisingState() => _client.getAdvertisingState(); + static Future getCapabilities() => + _client.getCapabilities(); + static Future addService( BleService service, { bool primary = true, @@ -161,8 +163,8 @@ class UniversalBlePeripheral { _client.updateCharacteristicValue( characteristicId: characteristicId, value: value, target: target); - /// Returns central device ids currently subscribed to [characteristicId] + /// Returns client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore in-app state after restart. - static Future> getSubscribedCentrals(String characteristicId) => - _client.getSubscribedCentrals(characteristicId); + static Future> getSubscribedClients(String characteristicId) => + _client.getSubscribedClients(characteristicId); } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index fe3fe15e..934cd102 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:universal_ble/src/universal_ble_pigeon/universal_ble.g.dart' as pigeon; @@ -39,9 +40,6 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform _writeRequestHandler = onWriteRequest; } - @override - Future isFeatureSupported() => _channel.isFeatureSupported(); - @override Future getReadinessState() async { final state = await _channel.getReadinessState(); @@ -76,6 +74,28 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform }; } + @override + Future getCapabilities() async { + final readiness = await getReadinessState(); + final platform = defaultTargetPlatform; + final supported = readiness != UniversalBlePeripheralReadinessState.unsupported; + + final supportsManufacturerDataInScanResponse = + platform == TargetPlatform.android; + final supportsAdvertisingTimeout = platform == TargetPlatform.android; + + return UniversalBlePeripheralCapabilities( + supportsPeripheralMode: supported, + supportsManufacturerDataInAdvertisement: supported, + supportsManufacturerDataInScanResponse: + supported && supportsManufacturerDataInScanResponse, + supportsServiceDataInAdvertisement: false, + supportsServiceDataInScanResponse: false, + supportsTargetedCharacteristicUpdate: supported, + supportsAdvertisingTimeout: supported && supportsAdvertisingTimeout, + ); + } + @override Future addService( BleService service, { @@ -158,8 +178,8 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform } @override - Future> getSubscribedCentrals(String characteristicId) => - _channel.getSubscribedCentrals(characteristicId); + Future> getSubscribedClients(String characteristicId) => + _channel.getSubscribedClients(characteristicId); @override void onAdvertisingStateChange( diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart index 8c76b939..b62935c9 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -73,6 +73,26 @@ class UniversalBlePeripheralMtuChanged extends UniversalBlePeripheralEvent { UniversalBlePeripheralMtuChanged(this.deviceId, this.mtu); } +class UniversalBlePeripheralCapabilities { + final bool supportsPeripheralMode; + final bool supportsManufacturerDataInAdvertisement; + final bool supportsManufacturerDataInScanResponse; + final bool supportsServiceDataInAdvertisement; + final bool supportsServiceDataInScanResponse; + final bool supportsTargetedCharacteristicUpdate; + final bool supportsAdvertisingTimeout; + + const UniversalBlePeripheralCapabilities({ + required this.supportsPeripheralMode, + required this.supportsManufacturerDataInAdvertisement, + required this.supportsManufacturerDataInScanResponse, + required this.supportsServiceDataInAdvertisement, + required this.supportsServiceDataInScanResponse, + required this.supportsTargetedCharacteristicUpdate, + required this.supportsAdvertisingTimeout, + }); +} + class PeripheralServiceId { final String value; const PeripheralServiceId(this.value); @@ -99,9 +119,9 @@ abstract class UniversalBlePeripheralPlatform { OnPeripheralWriteRequest? onWriteRequest, }); - Future isFeatureSupported(); Future getReadinessState(); Future getAdvertisingState(); + Future getCapabilities(); Future addService( BleService service, { @@ -126,8 +146,8 @@ abstract class UniversalBlePeripheralPlatform { PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }); - /// Returns GATT central device ids currently subscribed to [characteristicId]. - Future> getSubscribedCentrals(String characteristicId); + /// Returns GATT client device ids currently subscribed to [characteristicId]. + Future> getSubscribedClients(String characteristicId); /// Called when this platform implementation is being replaced. /// @@ -174,7 +194,17 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { } @override - Future isFeatureSupported() async => false; + Future getCapabilities() async { + return const UniversalBlePeripheralCapabilities( + supportsPeripheralMode: false, + supportsManufacturerDataInAdvertisement: false, + supportsManufacturerDataInScanResponse: false, + supportsServiceDataInAdvertisement: false, + supportsServiceDataInScanResponse: false, + supportsTargetedCharacteristicUpdate: false, + supportsAdvertisingTimeout: false, + ); + } @override Future getReadinessState() async { @@ -212,7 +242,7 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { } @override - Future> getSubscribedCentrals(String characteristicId) async { + Future> getSubscribedClients(String characteristicId) async { throw _notSupported(); } } diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index bc342943..6fcd6bba 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -1701,25 +1701,6 @@ class UniversalBlePeripheralChannel { return pigeonVar_replyValue! as PeripheralAdvertisingState; } - Future isFeatureSupported() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - - final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; - return pigeonVar_replyValue! as bool; - } - Future getReadinessState() async { final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( @@ -1866,10 +1847,10 @@ class UniversalBlePeripheralChannel { ; } - /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// Returns peripheral-client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. - Future> getSubscribedCentrals(String characteristicId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals$pigeonVar_messageChannelSuffix'; + Future> getSubscribedClients(String characteristicId) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedClients$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, diff --git a/pigeon/universal_ble.dart b/pigeon/universal_ble.dart index 1442a797..d2014e54 100644 --- a/pigeon/universal_ble.dart +++ b/pigeon/universal_ble.dart @@ -310,7 +310,6 @@ enum PeripheralAdvertisingState { @HostApi() abstract class UniversalBlePeripheralChannel { PeripheralAdvertisingState getAdvertisingState(); - bool isFeatureSupported(); PeripheralReadinessState getReadinessState(); void stopAdvertising(); void addService(PeripheralService service); @@ -330,9 +329,9 @@ abstract class UniversalBlePeripheralChannel { String? deviceId, ); - /// Returns peripheral-central device ids currently subscribed to [characteristicId] + /// Returns peripheral-client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. - List getSubscribedCentrals(String characteristicId); + List getSubscribedClients(String characteristicId); } /// Native -> Flutter (peripheral) diff --git a/test/universal_ble_peripheral_test.dart b/test/universal_ble_peripheral_test.dart index 297bafa4..af3387f9 100644 --- a/test/universal_ble_peripheral_test.dart +++ b/test/universal_ble_peripheral_test.dart @@ -38,6 +38,18 @@ class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { Future getAdvertisingState() async => UniversalBlePeripheralAdvertisingState.idle; + @override + Future getCapabilities() async => + const UniversalBlePeripheralCapabilities( + supportsPeripheralMode: true, + supportsManufacturerDataInAdvertisement: true, + supportsManufacturerDataInScanResponse: true, + supportsServiceDataInAdvertisement: false, + supportsServiceDataInScanResponse: false, + supportsTargetedCharacteristicUpdate: true, + supportsAdvertisingTimeout: true, + ); + @override Future getReadinessState() async => UniversalBlePeripheralReadinessState.ready; @@ -46,12 +58,9 @@ class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { Future> getServices() async => const []; @override - Future> getSubscribedCentrals(String characteristicId) async => + Future> getSubscribedClients(String characteristicId) async => [characteristicId]; - @override - Future isFeatureSupported() async => true; - @override Future removeService(PeripheralServiceId serviceId) async { removedServiceId = serviceId; @@ -213,4 +222,14 @@ void main() { expect(first.disposeCount, 1); }); + + test('instance client exposes platform capabilities', () async { + final fake = _FakePeripheralPlatform(); + final client = UniversalBlePeripheralClient(platform: fake); + final caps = await client.getCapabilities(); + + expect(caps.supportsPeripheralMode, isTrue); + expect(caps.supportsManufacturerDataInAdvertisement, isTrue); + expect(caps.supportsTargetedCharacteristicUpdate, isTrue); + }); } diff --git a/windows/src/generated/universal_ble.g.cpp b/windows/src/generated/universal_ble.g.cpp index 3f0fecde..c8eb3b51 100644 --- a/windows/src/generated/universal_ble.g.cpp +++ b/windows/src/generated/universal_ble.g.cpp @@ -2643,27 +2643,6 @@ void UniversalBlePeripheralChannel::SetUp( channel.SetMessageHandler(nullptr); } } - { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.isFeatureSupported" + prepended_suffix, &GetCodec()); - if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { - try { - ErrorOr output = api->IsFeatureSupported(); - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); - } - }); - } else { - channel.SetMessageHandler(nullptr); - } - } { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState" + prepended_suffix, &GetCodec()); if (api != nullptr) { @@ -2881,7 +2860,7 @@ void UniversalBlePeripheralChannel::SetUp( } } { - BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedCentrals" + prepended_suffix, &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedClients" + prepended_suffix, &GetCodec()); if (api != nullptr) { channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { @@ -2892,7 +2871,7 @@ void UniversalBlePeripheralChannel::SetUp( return; } const auto& characteristic_id_arg = std::get(encodable_characteristic_id_arg); - ErrorOr output = api->GetSubscribedCentrals(characteristic_id_arg); + ErrorOr output = api->GetSubscribedClients(characteristic_id_arg); if (output.has_error()) { reply(WrapError(output.error())); return; diff --git a/windows/src/generated/universal_ble.g.h b/windows/src/generated/universal_ble.g.h index b58b47aa..7c194528 100644 --- a/windows/src/generated/universal_ble.g.h +++ b/windows/src/generated/universal_ble.g.h @@ -917,7 +917,6 @@ class UniversalBlePeripheralChannel { UniversalBlePeripheralChannel& operator=(const UniversalBlePeripheralChannel&) = delete; virtual ~UniversalBlePeripheralChannel() {} virtual ErrorOr GetAdvertisingState() = 0; - virtual ErrorOr IsFeatureSupported() = 0; virtual ErrorOr GetReadinessState() = 0; virtual std::optional StopAdvertising() = 0; virtual std::optional AddService(const PeripheralService& service) = 0; @@ -934,9 +933,9 @@ class UniversalBlePeripheralChannel { const std::string& characteristic_id, const std::vector& value, const std::string* device_id) = 0; - // Returns peripheral-central device ids currently subscribed to [characteristicId] + // Returns peripheral-client device ids currently subscribed to [characteristicId] // (e.g. HID report characteristic). Used to restore app state after restart. - virtual ErrorOr<::flutter::EncodableList> GetSubscribedCentrals(const std::string& characteristic_id) = 0; + virtual ErrorOr<::flutter::EncodableList> GetSubscribedClients(const std::string& characteristic_id) = 0; // The codec used by UniversalBlePeripheralChannel. static const ::flutter::StandardMessageCodec& GetCodec(); diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index 11cfb8d5..fdbeb992 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -1628,10 +1628,6 @@ ErrorOr UniversalBlePlugin::GetAdvertisingState() { : PeripheralAdvertisingState::kIdle; } -ErrorOr UniversalBlePlugin::IsFeatureSupported() { - return bluetooth_radio_ != nullptr; -} - ErrorOr UniversalBlePlugin::GetReadinessState() { if (!bluetooth_radio_) { return PeripheralReadinessState::kUnsupported; @@ -1692,7 +1688,7 @@ ErrorOr UniversalBlePlugin::GetServices() { return services; } -ErrorOr UniversalBlePlugin::GetSubscribedCentrals( +ErrorOr UniversalBlePlugin::GetSubscribedClients( const std::string &characteristic_id) { std::lock_guard lock(peripheral_mutex_); flutter::EncodableList out; diff --git a/windows/src/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h index 45f2575f..2047987b 100644 --- a/windows/src/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -282,7 +282,6 @@ class UniversalBlePlugin : public flutter::Plugin, // UniversalBlePeripheralChannel implementation. ErrorOr GetAdvertisingState() override; - ErrorOr IsFeatureSupported() override; ErrorOr GetReadinessState() override; std::optional StopAdvertising() override; std::optional AddService(const PeripheralService &service) override; @@ -297,7 +296,7 @@ class UniversalBlePlugin : public flutter::Plugin, std::optional UpdateCharacteristic( const std::string &characteristic_id, const std::vector &value, const std::string *device_id) override; - ErrorOr GetSubscribedCentrals( + ErrorOr GetSubscribedClients( const std::string &characteristic_id) override; }; From 1aca78df2201f5d33f7dd7d856fa6cd4626377e1 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 17:41:10 +0200 Subject: [PATCH 19/23] Enhance BLE peripheral API with new methods and improved functionality - Introduced `getMaximumNotifyLength()` to retrieve the maximum characteristic notify payload length for connected clients. - Added support for descriptor read and write requests through `onDescriptorReadRequest()` and `onDescriptorWriteRequest()` methods. - Updated existing methods to use `PeripheralCharacteristicId` and `PeripheralDescriptorId` for better type safety and clarity. - Refactored request handler setup to accommodate new descriptor request handlers. - Adjusted documentation and example code to reflect the new API capabilities and changes. --- README.md | 25 +++-- .../navideck/universal_ble/UniversalBle.g.kt | 55 ++++++++++ .../UniversalBlePeripheralPlugin.kt | 59 ++++++++-- .../universal_ble/UniversalBle.g.swift | 58 ++++++++++ .../UniversalBlePeripheralPlugin.swift | 7 ++ example/lib/peripheral/peripheral_home.dart | 25 +++-- .../universal_ble_peripheral.dart | 52 +++++---- .../universal_ble_peripheral_pigeon.dart | 77 ++++++++++--- ...sal_ble_peripheral_platform_interface.dart | 70 +++++++++--- .../universal_ble_pigeon/universal_ble.g.dart | 74 +++++++++++++ pigeon/universal_ble.dart | 19 ++++ test/universal_ble_peripheral_test.dart | 56 ++++++++-- windows/src/generated/universal_ble.g.cpp | 101 ++++++++++++++++++ windows/src/generated/universal_ble.g.h | 18 ++++ windows/src/universal_ble_plugin.cpp | 24 +++++ windows/src/universal_ble_plugin.h | 2 + 16 files changed, 629 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 05a8a835..c107e215 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | API | Android | iOS | macOS | Windows | Linux | Web | | :----------------------- | :-----: | :-: | :---: | :-----: | :---: | :-: | -| getCapabilities | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getStaticCapabilities | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | getReadinessState\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | getAdvertisingState | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | addService | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | @@ -76,11 +76,12 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE | stopAdvertising | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | updateCharacteristicValue\*\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | getSubscribedClients | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | +| getMaximumNotifyLength | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | | events stream\*\*\* | ✔️ | ✔️ | ✔️ | ✔️ | 🚧 | ❌ | \* `getReadinessState` returns a snapshot state. Use `eventStream` for ongoing runtime changes. \*\* `updateCharacteristicValue` supports broadcast to all subscribed devices or a specific device via `PeripheralUpdateTarget`. -\*\*\* events include advertising state changes, read/write requests, subscription changes, and related peripheral events. +\*\*\* events include advertising state changes, MTU changes, subscription changes, and related peripheral events. ## Getting Started @@ -641,7 +642,7 @@ The error parser automatically converts platform-specific error formats (strings import 'package:universal_ble/universal_ble.dart'; final peripheral = UniversalBlePeripheralClient(); -final caps = await peripheral.getCapabilities(); +final caps = await peripheral.getStaticCapabilities(); if (!caps.supportsPeripheralMode) return; await peripheral.addService( @@ -667,16 +668,24 @@ final sub = peripheral.eventStream.listen((event) { }); peripheral.setRequestHandlers( - onReadRequest: (deviceId, characteristicId, offset, value) => - BleReadRequestResult(value: value ?? Uint8List(0)), - onWriteRequest: (deviceId, characteristicId, offset, value) => - const BleWriteRequestResult(), + PeripheralRequestHandlers( + onReadRequest: (deviceId, characteristicId, offset, value) => + BleReadRequestResult(value: value ?? Uint8List(0)), + onWriteRequest: (deviceId, characteristicId, offset, value) => + const BleWriteRequestResult(), + onDescriptorReadRequest: + (deviceId, characteristicId, descriptorId, offset, value) => + BleReadRequestResult(value: value ?? Uint8List(0)), + onDescriptorWriteRequest: + (deviceId, characteristicId, descriptorId, offset, value) => + const BleWriteRequestResult(), + ), ); ``` ### Breaking changes -- `isSupported()` was replaced by `getCapabilities().supportsPeripheralMode`. +- `isSupported()` was replaced by `getStaticCapabilities().supportsPeripheralMode`. - `isAdvertising()` was replaced by `getAdvertisingState()`. - Static callback setters were replaced by `eventStream` + `setRequestHandlers(...)`. - `UniversalBlePeripheralClient` is the recommended API; `UniversalBlePeripheral` remains as a singleton facade. diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt index 1fd87c09..3e6f6bb6 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt @@ -1758,6 +1758,8 @@ interface UniversalBlePeripheralChannel { * (e.g. HID report characteristic). Used to restore app state after restart. */ fun getSubscribedClients(characteristicId: String): List + /** Returns max characteristic notify payload length for a connected client. */ + fun getMaximumNotifyLength(deviceId: String): Long? companion object { /** The codec used by UniversalBlePeripheralChannel. */ @@ -1940,6 +1942,23 @@ interface UniversalBlePeripheralChannel { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getMaximumNotifyLength$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val deviceIdArg = args[0] as String + val wrapped: List = try { + listOf(api.getMaximumNotifyLength(deviceIdArg)) + } catch (exception: Throwable) { + UniversalBlePigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } } } } @@ -1991,6 +2010,42 @@ class UniversalBlePeripheralCallback(private val binaryMessenger: BinaryMessenge } } } + fun onDescriptorReadRequest(deviceIdArg: String, characteristicIdArg: String, descriptorIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorReadRequest$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, descriptorIdArg, offsetArg, valueArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + val output = it[0] as PeripheralReadRequestResult? + callback(Result.success(output)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } + fun onDescriptorWriteRequest(deviceIdArg: String, characteristicIdArg: String, descriptorIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorWriteRequest$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(deviceIdArg, characteristicIdArg, descriptorIdArg, offsetArg, valueArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + val output = it[0] as PeripheralWriteRequestResult? + callback(Result.success(output)) + } + } else { + callback(Result.failure(UniversalBlePigeonUtils.createConnectionError(channelName))) + } + } + } fun onCharacteristicSubscriptionChange(deviceIdArg: String, characteristicIdArg: String, isSubscribedArg: Boolean, nameArg: String?, callback: (Result) -> Unit) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index bbebf23f..98458e54 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -42,6 +42,7 @@ class UniversalBlePeripheralPlugin( private var bluetoothLeAdvertiser: BluetoothLeAdvertiser? = null private var gattServer: BluetoothGattServer? = null private val bluetoothDevicesMap: MutableMap = HashMap() + private val mtuByDeviceId: MutableMap = HashMap() private val listOfDevicesWaitingForBond = mutableListOf() private val emptyBytes = byteArrayOf() private var advertisingState: PeripheralAdvertisingState = PeripheralAdvertisingState.IDLE @@ -72,6 +73,7 @@ class UniversalBlePeripheralPlugin( synchronized(listOfDevicesWaitingForBond) { listOfDevicesWaitingForBond.clear() } + synchronized(mtuByDeviceId) { mtuByDeviceId.clear() } clearPeripheralCaches() } @@ -239,6 +241,11 @@ class UniversalBlePeripheralPlugin( } } + override fun getMaximumNotifyLength(deviceId: String): Long? { + val mtu = synchronized(mtuByDeviceId) { mtuByDeviceId[deviceId] } ?: return null + return (mtu - 3).coerceAtLeast(0).toLong() + } + private fun isBluetoothEnabled(): Boolean = bluetoothManager.adapter?.isEnabled ?: false @@ -328,6 +335,7 @@ class UniversalBlePeripheralPlugin( override fun onMtuChanged(device: BluetoothDevice?, mtu: Int) { super.onMtuChanged(device, mtu) device?.address?.let { address -> + synchronized(mtuByDeviceId) { mtuByDeviceId[address] = mtu } handler.post { callback.onMtuChange(address, mtu.toLong()) {} } } } @@ -412,11 +420,31 @@ class UniversalBlePeripheralPlugin( ) { super.onDescriptorReadRequest(device, requestId, offset, descriptor) handler.post { - val value = descriptor.getCacheValue() - if (value != null) { - gattServer?.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value) - } else { - gattServer?.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, emptyBytes) + callback.onDescriptorReadRequest( + deviceIdArg = device.address, + characteristicIdArg = descriptor.characteristic.uuid.toString(), + descriptorIdArg = descriptor.uuid.toString(), + offsetArg = offset.toLong(), + valueArg = descriptor.getCacheValue(), + ) { result -> + val readResult = result.getOrNull() + if (readResult == null) { + gattServer?.sendResponse( + device, + requestId, + BluetoothGatt.GATT_FAILURE, + offset, + emptyBytes, + ) + } else { + gattServer?.sendResponse( + device, + requestId, + readResult.status?.toInt() ?: BluetoothGatt.GATT_SUCCESS, + readResult.offset?.toInt() ?: offset, + readResult.value, + ) + } } } } @@ -457,9 +485,24 @@ class UniversalBlePeripheralPlugin( } } if (responseNeeded) { - gattServer?.sendResponse( - device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value ?: emptyBytes, - ) + handler.post { + callback.onDescriptorWriteRequest( + deviceIdArg = device?.address ?: "", + characteristicIdArg = descriptor.characteristic.uuid.toString(), + descriptorIdArg = descriptor.uuid.toString(), + offsetArg = offset.toLong(), + valueArg = value, + ) { writeResponse -> + val writeResult = writeResponse.getOrNull() + gattServer?.sendResponse( + device, + requestId, + writeResult?.status?.toInt() ?: BluetoothGatt.GATT_SUCCESS, + writeResult?.offset?.toInt() ?: offset, + writeResult?.value ?: value ?: emptyBytes, + ) + } + } } } } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift index 69acc0ea..d252608a 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift @@ -1593,6 +1593,8 @@ protocol UniversalBlePeripheralChannel { /// Returns peripheral-client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. func getSubscribedClients(characteristicId: String) throws -> [String] + /// Returns max characteristic notify payload length for a connected client. + func getMaximumNotifyLength(deviceId: String) throws -> Int64? } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -1749,6 +1751,22 @@ class UniversalBlePeripheralChannelSetup { } else { getSubscribedClientsChannel.setMessageHandler(nil) } + /// Returns max characteristic notify payload length for a connected client. + let getMaximumNotifyLengthChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getMaximumNotifyLength\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getMaximumNotifyLengthChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let deviceIdArg = args[0] as! String + do { + let result = try api.getMaximumNotifyLength(deviceId: deviceIdArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getMaximumNotifyLengthChannel.setMessageHandler(nil) + } } } /// Native -> Flutter (peripheral) @@ -1757,6 +1775,8 @@ class UniversalBlePeripheralChannelSetup { protocol UniversalBlePeripheralCallbackProtocol { func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) + func onDescriptorReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, descriptorId descriptorIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) + func onDescriptorWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, descriptorId descriptorIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) func onAdvertisingStateChange(state stateArg: PeripheralAdvertisingState, error errorArg: String?, completion: @escaping (Result) -> Void) func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) @@ -1811,6 +1831,44 @@ class UniversalBlePeripheralCallback: UniversalBlePeripheralCallbackProtocol { } } } + func onDescriptorReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, descriptorId descriptorIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorReadRequest\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, descriptorIdArg, offsetArg, valueArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + let result: PeripheralReadRequestResult? = nilOrValue(listResponse[0]) + completion(.success(result)) + } + } + } + func onDescriptorWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, descriptorId descriptorIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorWriteRequest\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, descriptorIdArg, offsetArg, valueArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + let result: PeripheralWriteRequestResult? = nilOrValue(listResponse[0]) + completion(.success(result)) + } + } + } func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) { let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange\(messageChannelSuffix)" let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 0299c509..4c82a795 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -309,4 +309,11 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne chars.contains(where: { $0.uppercased() == target }) ? centralId : nil } } + + func getMaximumNotifyLength(deviceId: String) throws -> Int64? { + guard let central = central(for: deviceId) else { + return nil + } + return Int64(central.maximumUpdateValueLength) + } } diff --git a/example/lib/peripheral/peripheral_home.dart b/example/lib/peripheral/peripheral_home.dart index d581ac67..209e4f8f 100644 --- a/example/lib/peripheral/peripheral_home.dart +++ b/example/lib/peripheral/peripheral_home.dart @@ -51,14 +51,16 @@ class _PeripheralHomeState extends State { } }); _peripheral.setRequestHandlers( - onReadRequest: (deviceId, characteristicId, _, __) { - _log('Read request: $deviceId $characteristicId'); - return BleReadRequestResult(value: utf8.encode('Hello World')); - }, - onWriteRequest: (deviceId, characteristicId, _, value) { - _log('Write request: $deviceId $characteristicId $value'); - return const BleWriteRequestResult(); - }, + PeripheralRequestHandlers( + onReadRequest: (deviceId, characteristicId, _, __) { + _log('Read request: $deviceId ${characteristicId.value}'); + return BleReadRequestResult(value: utf8.encode('Hello World')); + }, + onWriteRequest: (deviceId, characteristicId, _, value) { + _log('Write request: $deviceId ${characteristicId.value} $value'); + return const BleWriteRequestResult(); + }, + ), ); } @@ -69,7 +71,8 @@ class _PeripheralHomeState extends State { } Future _initialize() async { - final supported = (await _peripheral.getCapabilities()).supportsPeripheralMode; + final supported = + (await _peripheral.getStaticCapabilities()).supportsPeripheralMode; setState(() { _initialized = supported; }); @@ -158,7 +161,9 @@ class _PeripheralHomeState extends State { onPressed: _initialized ? () async { await _peripheral.updateCharacteristicValue( - characteristicId: _charTest, + characteristicId: const PeripheralCharacteristicId( + _charTest, + ), value: utf8.encode('Test Data'), ); _log('Characteristic updated'); diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart index ea8a841b..44672e2a 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral.dart @@ -15,15 +15,8 @@ class UniversalBlePeripheralClient { Stream get eventStream => _platform.eventStream; - void setRequestHandlers({ - OnPeripheralReadRequest? onReadRequest, - OnPeripheralWriteRequest? onWriteRequest, - }) { - _platform.setRequestHandlers( - onReadRequest: onReadRequest, - onWriteRequest: onWriteRequest, - ); - } + void setRequestHandlers(PeripheralRequestHandlers handlers) => + _platform.setRequestHandlers(handlers); Future getReadinessState() => _platform.getReadinessState(); @@ -31,8 +24,8 @@ class UniversalBlePeripheralClient { Future getAdvertisingState() => _platform.getAdvertisingState(); - Future getCapabilities() => - _platform.getCapabilities(); + Future getStaticCapabilities() => + _platform.getStaticCapabilities(); Future addService( BleService service, { @@ -70,18 +63,25 @@ class UniversalBlePeripheralClient { Future stopAdvertising() => _platform.stopAdvertising(); Future updateCharacteristicValue({ - required String characteristicId, + required PeripheralCharacteristicId characteristicId, required Uint8List value, PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }) => _platform.updateCharacteristicValue( - characteristicId: characteristicId, + characteristicId: PeripheralCharacteristicId( + BleUuidParser.string(characteristicId.value), + ), value: value, target: target, ); - Future> getSubscribedClients(String characteristicId) => - _platform.getSubscribedClients(BleUuidParser.string(characteristicId)); + Future> getSubscribedClients(PeripheralCharacteristicId characteristicId) => + _platform.getSubscribedClients( + PeripheralCharacteristicId(BleUuidParser.string(characteristicId.value)), + ); + + Future getMaximumNotifyLength(String deviceId) => + _platform.getMaximumNotifyLength(deviceId); } class UniversalBlePeripheral { @@ -107,15 +107,8 @@ class UniversalBlePeripheral { static Stream get eventStream => _client.eventStream; - static void setRequestHandlers({ - OnPeripheralReadRequest? onReadRequest, - OnPeripheralWriteRequest? onWriteRequest, - }) { - _client.setRequestHandlers( - onReadRequest: onReadRequest, - onWriteRequest: onWriteRequest, - ); - } + static void setRequestHandlers(PeripheralRequestHandlers handlers) => + _client.setRequestHandlers(handlers); static Future getReadinessState() => _client.getReadinessState(); @@ -123,8 +116,8 @@ class UniversalBlePeripheral { static Future getAdvertisingState() => _client.getAdvertisingState(); - static Future getCapabilities() => - _client.getCapabilities(); + static Future getStaticCapabilities() => + _client.getStaticCapabilities(); static Future addService( BleService service, { @@ -156,7 +149,7 @@ class UniversalBlePeripheral { static Future stopAdvertising() => _client.stopAdvertising(); static Future updateCharacteristicValue({ - required String characteristicId, + required PeripheralCharacteristicId characteristicId, required Uint8List value, PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }) => @@ -165,6 +158,9 @@ class UniversalBlePeripheral { /// Returns client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore in-app state after restart. - static Future> getSubscribedClients(String characteristicId) => + static Future> getSubscribedClients(PeripheralCharacteristicId characteristicId) => _client.getSubscribedClients(characteristicId); + + static Future getMaximumNotifyLength(String deviceId) => + _client.getMaximumNotifyLength(deviceId); } diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart index 934cd102..92e4a6ae 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_pigeon.dart @@ -26,18 +26,19 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform bool _disposed = false; OnPeripheralReadRequest? _readRequestHandler; OnPeripheralWriteRequest? _writeRequestHandler; + OnPeripheralDescriptorReadRequest? _descriptorReadRequestHandler; + OnPeripheralDescriptorWriteRequest? _descriptorWriteRequestHandler; @override Stream get eventStream => _eventController.stream; @override - void setRequestHandlers({ - OnPeripheralReadRequest? onReadRequest, - OnPeripheralWriteRequest? onWriteRequest, - }) { - _readRequestHandler = onReadRequest; - _writeRequestHandler = onWriteRequest; + void setRequestHandlers(PeripheralRequestHandlers handlers) { + _readRequestHandler = handlers.onReadRequest; + _writeRequestHandler = handlers.onWriteRequest; + _descriptorReadRequestHandler = handlers.onDescriptorReadRequest; + _descriptorWriteRequestHandler = handlers.onDescriptorWriteRequest; } @override @@ -75,7 +76,7 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform } @override - Future getCapabilities() async { + Future getStaticCapabilities() async { final readiness = await getReadinessState(); final platform = defaultTargetPlatform; final supported = readiness != UniversalBlePeripheralReadinessState.unsupported; @@ -162,7 +163,7 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform @override Future updateCharacteristicValue({ - required String characteristicId, + required PeripheralCharacteristicId characteristicId, required Uint8List value, PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }) { @@ -171,15 +172,19 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform PeripheralUpdateSingleDevice(deviceId: final id) => id, }; return _channel.updateCharacteristic( - BleUuidParser.string(characteristicId), + BleUuidParser.string(characteristicId.value), value, deviceId, ); } @override - Future> getSubscribedClients(String characteristicId) => - _channel.getSubscribedClients(characteristicId); + Future> getSubscribedClients(PeripheralCharacteristicId characteristicId) => + _channel.getSubscribedClients(characteristicId.value); + + @override + Future getMaximumNotifyLength(String deviceId) => + _channel.getMaximumNotifyLength(deviceId); @override void onAdvertisingStateChange( @@ -249,7 +254,7 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform ) { final result = _readRequestHandler?.call( deviceId, - characteristicId, + PeripheralCharacteristicId(characteristicId), offset, value, ); @@ -280,7 +285,7 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform ) { final result = _writeRequestHandler?.call( deviceId, - characteristicId, + PeripheralCharacteristicId(characteristicId), offset, value, ); @@ -292,6 +297,52 @@ class UniversalBlePeripheralPigeon extends UniversalBlePeripheralPlatform ); } + @override + pigeon.PeripheralReadRequestResult? onDescriptorReadRequest( + String deviceId, + String characteristicId, + String descriptorId, + int offset, + Uint8List? value, + ) { + final result = _descriptorReadRequestHandler?.call( + deviceId, + PeripheralCharacteristicId(characteristicId), + PeripheralDescriptorId(descriptorId), + offset, + value, + ); + if (result == null) return null; + return pigeon.PeripheralReadRequestResult( + value: result.value, + offset: result.offset, + status: result.status, + ); + } + + @override + pigeon.PeripheralWriteRequestResult? onDescriptorWriteRequest( + String deviceId, + String characteristicId, + String descriptorId, + int offset, + Uint8List? value, + ) { + final result = _descriptorWriteRequestHandler?.call( + deviceId, + PeripheralCharacteristicId(characteristicId), + PeripheralDescriptorId(descriptorId), + offset, + value, + ); + if (result == null) return null; + return pigeon.PeripheralWriteRequestResult( + value: result.value, + offset: result.offset, + status: result.status, + ); + } + @override void dispose() { if (_disposed) return; diff --git a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart index b62935c9..9be35a8a 100644 --- a/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart +++ b/lib/src/universal_ble_peripheral/universal_ble_peripheral_platform_interface.dart @@ -4,13 +4,27 @@ import 'package:universal_ble/universal_ble.dart'; typedef OnPeripheralReadRequest = BleReadRequestResult? Function( String deviceId, - String characteristicId, + PeripheralCharacteristicId characteristicId, int offset, Uint8List? value, ); typedef OnPeripheralWriteRequest = BleWriteRequestResult? Function( String deviceId, - String characteristicId, + PeripheralCharacteristicId characteristicId, + int offset, + Uint8List? value, +); +typedef OnPeripheralDescriptorReadRequest = BleReadRequestResult? Function( + String deviceId, + PeripheralCharacteristicId characteristicId, + PeripheralDescriptorId descriptorId, + int offset, + Uint8List? value, +); +typedef OnPeripheralDescriptorWriteRequest = BleWriteRequestResult? Function( + String deviceId, + PeripheralCharacteristicId characteristicId, + PeripheralDescriptorId descriptorId, int offset, Uint8List? value, ); @@ -98,6 +112,30 @@ class PeripheralServiceId { const PeripheralServiceId(this.value); } +class PeripheralCharacteristicId { + final String value; + const PeripheralCharacteristicId(this.value); +} + +class PeripheralDescriptorId { + final String value; + const PeripheralDescriptorId(this.value); +} + +class PeripheralRequestHandlers { + final OnPeripheralReadRequest? onReadRequest; + final OnPeripheralWriteRequest? onWriteRequest; + final OnPeripheralDescriptorReadRequest? onDescriptorReadRequest; + final OnPeripheralDescriptorWriteRequest? onDescriptorWriteRequest; + + const PeripheralRequestHandlers({ + this.onReadRequest, + this.onWriteRequest, + this.onDescriptorReadRequest, + this.onDescriptorWriteRequest, + }); +} + sealed class PeripheralUpdateTarget { const PeripheralUpdateTarget(); } @@ -114,14 +152,11 @@ class PeripheralUpdateSingleDevice extends PeripheralUpdateTarget { abstract class UniversalBlePeripheralPlatform { Stream get eventStream; - void setRequestHandlers({ - OnPeripheralReadRequest? onReadRequest, - OnPeripheralWriteRequest? onWriteRequest, - }); + void setRequestHandlers(PeripheralRequestHandlers handlers); Future getReadinessState(); Future getAdvertisingState(); - Future getCapabilities(); + Future getStaticCapabilities(); Future addService( BleService service, { @@ -141,13 +176,14 @@ abstract class UniversalBlePeripheralPlatform { }); Future stopAdvertising(); Future updateCharacteristicValue({ - required String characteristicId, + required PeripheralCharacteristicId characteristicId, required Uint8List value, PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }); /// Returns GATT client device ids currently subscribed to [characteristicId]. - Future> getSubscribedClients(String characteristicId); + Future> getSubscribedClients(PeripheralCharacteristicId characteristicId); + Future getMaximumNotifyLength(String deviceId); /// Called when this platform implementation is being replaced. /// @@ -164,10 +200,7 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { const Stream.empty(); @override - void setRequestHandlers({ - OnPeripheralReadRequest? onReadRequest, - OnPeripheralWriteRequest? onWriteRequest, - }) {} + void setRequestHandlers(PeripheralRequestHandlers handlers) {} @override Future addService( @@ -194,7 +227,7 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { } @override - Future getCapabilities() async { + Future getStaticCapabilities() async { return const UniversalBlePeripheralCapabilities( supportsPeripheralMode: false, supportsManufacturerDataInAdvertisement: false, @@ -234,7 +267,7 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { @override Future updateCharacteristicValue({ - required String characteristicId, + required PeripheralCharacteristicId characteristicId, required Uint8List value, PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), }) async { @@ -242,7 +275,12 @@ class UniversalBlePeripheralUnsupported extends UniversalBlePeripheralPlatform { } @override - Future> getSubscribedClients(String characteristicId) async { + Future> getSubscribedClients(PeripheralCharacteristicId characteristicId) async { throw _notSupported(); } + + @override + Future getMaximumNotifyLength(String deviceId) async { + return null; + } } diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index 6fcd6bba..6e04e50b 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -1867,6 +1867,26 @@ class UniversalBlePeripheralChannel { ; return (pigeonVar_replyValue! as List).cast(); } + + /// Returns max characteristic notify payload length for a connected client. + Future getMaximumNotifyLength(String deviceId) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getMaximumNotifyLength$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + return pigeonVar_replyValue as int?; + } } /// Native -> Flutter (peripheral) @@ -1877,6 +1897,10 @@ abstract class UniversalBlePeripheralCallback { PeripheralWriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralReadRequestResult? onDescriptorReadRequest(String deviceId, String characteristicId, String descriptorId, int offset, Uint8List? value); + + PeripheralWriteRequestResult? onDescriptorWriteRequest(String deviceId, String characteristicId, String descriptorId, int offset, Uint8List? value); + void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); void onAdvertisingStateChange(PeripheralAdvertisingState state, String? error); @@ -1937,6 +1961,56 @@ abstract class UniversalBlePeripheralCallback { }); } } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorReadRequest$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final String arg_descriptorId = args[2]! as String; + final int arg_offset = args[3]! as int; + final Uint8List? arg_value = args[4] as Uint8List?; + try { + final PeripheralReadRequestResult? output = api.onDescriptorReadRequest(arg_deviceId, arg_characteristicId, arg_descriptorId, arg_offset, arg_value); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorWriteRequest$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_deviceId = args[0]! as String; + final String arg_characteristicId = args[1]! as String; + final String arg_descriptorId = args[2]! as String; + final int arg_offset = args[3]! as int; + final Uint8List? arg_value = args[4] as Uint8List?; + try { + final PeripheralWriteRequestResult? output = api.onDescriptorWriteRequest(arg_deviceId, arg_characteristicId, arg_descriptorId, arg_offset, arg_value); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } { final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', pigeonChannelCodec, diff --git a/pigeon/universal_ble.dart b/pigeon/universal_ble.dart index d2014e54..694e835b 100644 --- a/pigeon/universal_ble.dart +++ b/pigeon/universal_ble.dart @@ -332,6 +332,9 @@ abstract class UniversalBlePeripheralChannel { /// Returns peripheral-client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. List getSubscribedClients(String characteristicId); + + /// Returns max characteristic notify payload length for a connected client. + int? getMaximumNotifyLength(String deviceId); } /// Native -> Flutter (peripheral) @@ -351,6 +354,22 @@ abstract class UniversalBlePeripheralCallback { Uint8List? value, ); + PeripheralReadRequestResult? onDescriptorReadRequest( + String deviceId, + String characteristicId, + String descriptorId, + int offset, + Uint8List? value, + ); + + PeripheralWriteRequestResult? onDescriptorWriteRequest( + String deviceId, + String characteristicId, + String descriptorId, + int offset, + Uint8List? value, + ); + void onCharacteristicSubscriptionChange( String deviceId, String characteristicId, diff --git a/test/universal_ble_peripheral_test.dart b/test/universal_ble_peripheral_test.dart index af3387f9..fb5e06d7 100644 --- a/test/universal_ble_peripheral_test.dart +++ b/test/universal_ble_peripheral_test.dart @@ -7,6 +7,9 @@ import 'package:universal_ble/universal_ble.dart'; class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { int disposeCount = 0; PeripheralServiceId? removedServiceId; + PeripheralCharacteristicId? updatedCharacteristicId; + PeripheralCharacteristicId? subscribedCharacteristicId; + String? maxNotifyLengthDeviceId; List? advertisedServices; @override @@ -14,10 +17,7 @@ class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { const Stream.empty(); @override - void setRequestHandlers({ - OnPeripheralReadRequest? onReadRequest, - OnPeripheralWriteRequest? onWriteRequest, - }) {} + void setRequestHandlers(PeripheralRequestHandlers handlers) {} @override Future addService( @@ -39,7 +39,7 @@ class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { UniversalBlePeripheralAdvertisingState.idle; @override - Future getCapabilities() async => + Future getStaticCapabilities() async => const UniversalBlePeripheralCapabilities( supportsPeripheralMode: true, supportsManufacturerDataInAdvertisement: true, @@ -58,8 +58,18 @@ class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { Future> getServices() async => const []; @override - Future> getSubscribedClients(String characteristicId) async => - [characteristicId]; + Future> getSubscribedClients( + PeripheralCharacteristicId characteristicId, + ) async { + subscribedCharacteristicId = characteristicId; + return [characteristicId.value]; + } + + @override + Future getMaximumNotifyLength(String deviceId) async { + maxNotifyLengthDeviceId = deviceId; + return 20; + } @override Future removeService(PeripheralServiceId serviceId) async { @@ -82,10 +92,12 @@ class _FakePeripheralPlatform extends UniversalBlePeripheralPlatform { @override Future updateCharacteristicValue({ - required String characteristicId, + required PeripheralCharacteristicId characteristicId, required Uint8List value, PeripheralUpdateTarget target = const PeripheralUpdateAllSubscribed(), - }) async {} + }) async { + updatedCharacteristicId = characteristicId; + } } void main() { @@ -226,10 +238,34 @@ void main() { test('instance client exposes platform capabilities', () async { final fake = _FakePeripheralPlatform(); final client = UniversalBlePeripheralClient(platform: fake); - final caps = await client.getCapabilities(); + final caps = await client.getStaticCapabilities(); expect(caps.supportsPeripheralMode, isTrue); expect(caps.supportsManufacturerDataInAdvertisement, isTrue); expect(caps.supportsTargetedCharacteristicUpdate, isTrue); }); + + test('instance client normalizes characteristic IDs in APIs', () async { + final fake = _FakePeripheralPlatform(); + final client = UniversalBlePeripheralClient(platform: fake); + + await client.updateCharacteristicValue( + characteristicId: const PeripheralCharacteristicId('2a19'), + value: Uint8List.fromList([1]), + ); + await client.getSubscribedClients(const PeripheralCharacteristicId('2a19')); + + expect(fake.updatedCharacteristicId?.value, BleUuidParser.string('2a19')); + expect(fake.subscribedCharacteristicId?.value, BleUuidParser.string('2a19')); + }); + + test('instance client forwards max notify length deviceId', () async { + final fake = _FakePeripheralPlatform(); + final client = UniversalBlePeripheralClient(platform: fake); + + final maxLen = await client.getMaximumNotifyLength('aa:bb:cc'); + + expect(maxLen, 20); + expect(fake.maxNotifyLengthDeviceId, 'aa:bb:cc'); + }); } diff --git a/windows/src/generated/universal_ble.g.cpp b/windows/src/generated/universal_ble.g.cpp index c8eb3b51..c0315e12 100644 --- a/windows/src/generated/universal_ble.g.cpp +++ b/windows/src/generated/universal_ble.g.cpp @@ -2887,6 +2887,39 @@ void UniversalBlePeripheralChannel::SetUp( channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getMaximumNotifyLength" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_device_id_arg = args.at(0); + if (encodable_device_id_arg.IsNull()) { + reply(WrapError("device_id_arg unexpectedly null.")); + return; + } + const auto& device_id_arg = std::get(encodable_device_id_arg); + ErrorOr> output = api->GetMaximumNotifyLength(device_id_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back(EncodableValue(std::move(output_optional).value())); + } else { + wrapped.push_back(EncodableValue()); + } + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } } EncodableValue UniversalBlePeripheralChannel::WrapError(std::string_view error_message) { @@ -2984,6 +3017,74 @@ void UniversalBlePeripheralCallback::OnWriteRequest( }); } +void UniversalBlePeripheralCallback::OnDescriptorReadRequest( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + const std::string& descriptor_id_arg, + int64_t offset_arg, + const std::vector* value_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorReadRequest" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(descriptor_id_arg), + EncodableValue(offset_arg), + value_arg ? EncodableValue(*value_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); + on_success(return_value); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + +void UniversalBlePeripheralCallback::OnDescriptorWriteRequest( + const std::string& device_id_arg, + const std::string& characteristic_id_arg, + const std::string& descriptor_id_arg, + int64_t offset_arg, + const std::vector* value_arg, + std::function&& on_success, + std::function&& on_error) { + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorWriteRequest" + message_channel_suffix_; + BasicMessageChannel<> channel(binary_messenger_, channel_name, &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(device_id_arg), + EncodableValue(characteristic_id_arg), + EncodableValue(descriptor_id_arg), + EncodableValue(offset_arg), + value_arg ? EncodableValue(*value_arg) : EncodableValue(), + }); + channel.Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto* list_return_value = std::get_if(&encodable_return_value); + if (list_return_value) { + if (list_return_value->size() > 1) { + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + } else { + const auto* return_value = list_return_value->at(0).IsNull() ? nullptr : &(std::any_cast(std::get(list_return_value->at(0)))); + on_success(return_value); + } + } else { + on_error(CreateConnectionError(channel_name)); + } + }); +} + void UniversalBlePeripheralCallback::OnCharacteristicSubscriptionChange( const std::string& device_id_arg, const std::string& characteristic_id_arg, diff --git a/windows/src/generated/universal_ble.g.h b/windows/src/generated/universal_ble.g.h index 7c194528..1602d1ce 100644 --- a/windows/src/generated/universal_ble.g.h +++ b/windows/src/generated/universal_ble.g.h @@ -936,6 +936,8 @@ class UniversalBlePeripheralChannel { // Returns peripheral-client device ids currently subscribed to [characteristicId] // (e.g. HID report characteristic). Used to restore app state after restart. virtual ErrorOr<::flutter::EncodableList> GetSubscribedClients(const std::string& characteristic_id) = 0; + // Returns max characteristic notify payload length for a connected client. + virtual ErrorOr> GetMaximumNotifyLength(const std::string& device_id) = 0; // The codec used by UniversalBlePeripheralChannel. static const ::flutter::StandardMessageCodec& GetCodec(); @@ -976,6 +978,22 @@ class UniversalBlePeripheralCallback { const std::vector* value, std::function&& on_success, std::function&& on_error); + void OnDescriptorReadRequest( + const std::string& device_id, + const std::string& characteristic_id, + const std::string& descriptor_id, + int64_t offset, + const std::vector* value, + std::function&& on_success, + std::function&& on_error); + void OnDescriptorWriteRequest( + const std::string& device_id, + const std::string& characteristic_id, + const std::string& descriptor_id, + int64_t offset, + const std::vector* value, + std::function&& on_success, + std::function&& on_error); void OnCharacteristicSubscriptionChange( const std::string& device_id, const std::string& characteristic_id, diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index fdbeb992..cad43d35 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -1708,6 +1708,30 @@ ErrorOr UniversalBlePlugin::GetSubscribedClients( return out; } +ErrorOr> UniversalBlePlugin::GetMaximumNotifyLength( + const std::string &device_id) { + std::lock_guard lock(peripheral_mutex_); + for (auto const &[_, service_provider] : peripheral_service_provider_map_) { + for (auto const &[_, characteristic_object] : + service_provider->characteristics) { + try { + auto clients = characteristic_object->obj.SubscribedClients(); + for (uint32_t i = 0; i < clients.Size(); ++i) { + auto client = clients.GetAt(i); + auto id = ParsePeripheralBluetoothClientId(client.Session().DeviceId().Id()); + if (to_lower_case(id) != to_lower_case(device_id)) { + continue; + } + const int64_t pdu_size = static_cast(client.Session().MaxPduSize()); + return std::max(0, pdu_size - 3); + } + } catch (...) { + } + } + } + return std::optional{}; +} + std::optional UniversalBlePlugin::StartAdvertising( const flutter::EncodableList &services, const std::string *local_name, const int64_t *timeout, diff --git a/windows/src/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h index 2047987b..a3e5179c 100644 --- a/windows/src/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -298,6 +298,8 @@ class UniversalBlePlugin : public flutter::Plugin, const std::string *device_id) override; ErrorOr GetSubscribedClients( const std::string &characteristic_id) override; + ErrorOr> GetMaximumNotifyLength( + const std::string &device_id) override; }; } // namespace universal_ble From 5ab1881a76683334c735c27b0a1f80da6ab7d90c Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Mon, 30 Mar 2026 20:24:32 +0200 Subject: [PATCH 20/23] Enhance README documentation for BLE peripheral API - Updated setup instructions to include new methods for service management and advertising. - Added examples for characteristic updates, subscribed clients, and event stream handling. - Improved clarity and organization of sections to better guide users through the API functionalities. - Included breaking changes related to the `isSupported()` method replacement. --- README.md | 123 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c107e215..4f6ef372 100644 --- a/README.md +++ b/README.md @@ -636,53 +636,148 @@ The error parser automatically converts platform-specific error formats (strings `universal_ble` provides peripheral mode through `UniversalBlePeripheralClient`, so your app can advertise as a peripheral "server" in addition to client mode. -### Basic setup +### Setup ```dart +import 'dart:typed_data'; import 'package:universal_ble/universal_ble.dart'; final peripheral = UniversalBlePeripheralClient(); + final caps = await peripheral.getStaticCapabilities(); if (!caps.supportsPeripheralMode) return; +final readiness = await peripheral.getReadinessState(); +if (readiness != UniversalBlePeripheralReadinessState.ready) return; +``` + +### Service Management + +```dart await peripheral.addService( BleService("0000180F-0000-1000-8000-00805F9B34FB", [ BleCharacteristic( "00002A19-0000-1000-8000-00805F9B34FB", [CharacteristicProperty.read, CharacteristicProperty.notify], - [], + [BleDescriptor("00002902-0000-1000-8000-00805F9B34FB")], ), ]), primary: true, ); +await peripheral.addService( + BleService("0000180D-0000-1000-8000-00805F9B34FB", [ + BleCharacteristic( + "00002A37-0000-1000-8000-00805F9B34FB", + [ + CharacteristicProperty.read, + CharacteristicProperty.notify, + CharacteristicProperty.write, + ], + [], + ), + ]), +); + +final services = await peripheral.getServices(); +await peripheral.removeService(const PeripheralServiceId("0000180D-0000-1000-8000-00805F9B34FB")); +``` + +### Advertising + +```dart await peripheral.startAdvertising( - services: [PeripheralServiceId("0000180F-0000-1000-8000-00805F9B34FB")], + services: const [ + PeripheralServiceId("0000180F-0000-1000-8000-00805F9B34FB"), + ], localName: "UniversalBlePeripheral", + manufacturerData: ManufacturerData( + 0x012D, + Uint8List.fromList([0x03, 0x00, 0x64, 0x00]), + ), addManufacturerDataInScanResponse: caps.supportsManufacturerDataInScanResponse, ); -final sub = peripheral.eventStream.listen((event) { - // Handle UniversalBlePeripheralEvent subtypes. -}); +final advertisingState = await peripheral.getAdvertisingState(); +if (advertisingState == UniversalBlePeripheralAdvertisingState.advertising) { + // Peripheral is advertising. +} + +await peripheral.stopAdvertising(); +``` + +### Request Handlers +```dart peripheral.setRequestHandlers( PeripheralRequestHandlers( - onReadRequest: (deviceId, characteristicId, offset, value) => - BleReadRequestResult(value: value ?? Uint8List(0)), - onWriteRequest: (deviceId, characteristicId, offset, value) => - const BleWriteRequestResult(), + onReadRequest: (deviceId, characteristicId, offset, value) { + return BleReadRequestResult(value: value ?? Uint8List(0)); + }, + onWriteRequest: (deviceId, characteristicId, offset, value) { + return const BleWriteRequestResult(); + }, onDescriptorReadRequest: - (deviceId, characteristicId, descriptorId, offset, value) => - BleReadRequestResult(value: value ?? Uint8List(0)), + (deviceId, characteristicId, descriptorId, offset, value) { + return BleReadRequestResult(value: value ?? Uint8List(0)); + }, onDescriptorWriteRequest: - (deviceId, characteristicId, descriptorId, offset, value) => - const BleWriteRequestResult(), + (deviceId, characteristicId, descriptorId, offset, value) { + return const BleWriteRequestResult(); + }, ), ); ``` +### Characteristic Updates + +```dart +await peripheral.updateCharacteristicValue( + characteristicId: const PeripheralCharacteristicId( + "00002A19-0000-1000-8000-00805F9B34FB", + ), + value: Uint8List.fromList([92]), +); +``` + +### Subscribed Clients and Notify Length + +```dart +final subscribers = await peripheral.getSubscribedClients( + const PeripheralCharacteristicId("00002A19-0000-1000-8000-00805F9B34FB"), +); + +for (final deviceId in subscribers) { + final maxNotifyLength = await peripheral.getMaximumNotifyLength(deviceId); + // maxNotifyLength can be null when unknown for this device. +} +``` + +### Event Stream + +```dart +final sub = peripheral.eventStream.listen((event) { + switch (event) { + case UniversalBlePeripheralAdvertisingStateChanged(): + // event.state / event.error + break; + case UniversalBlePeripheralCharacteristicSubscriptionChanged(): + // event.deviceId / event.characteristicId / event.isSubscribed + break; + case UniversalBlePeripheralConnectionStateChanged(): + // event.deviceId / event.connected + break; + case UniversalBlePeripheralMtuChanged(): + // event.deviceId / event.mtu + break; + case UniversalBlePeripheralServiceAdded(): + // event.serviceId / event.error + break; + } +}); +``` + ### Breaking changes - `isSupported()` was replaced by `getStaticCapabilities().supportsPeripheralMode`. From a25ffcdd12b202794293aeb72395cd076ad11f34 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Wed, 1 Apr 2026 21:12:32 +0200 Subject: [PATCH 21/23] Update CHANGELOG and add CONTRIBUTING guidelines; refactor permission methods - Enhanced CHANGELOG for version 2.0.0 with details on the new `UniversalBlePeripheralClient` API and breaking changes. - Added CONTRIBUTING.md to outline contribution guidelines, issue reporting, and pull request processes. - Refactored permission-related methods: renamed `isPermissionGranted()` to `hasPermissions()` and `isReceivingAdvertisements()` to `receivesAdvertisements()` for improved clarity and consistency across the codebase. --- CHANGELOG.md | 6 +- CONTRIBUTING.md | 71 ++ .../navideck/universal_ble/UniversalBle.g.kt | 2 +- .../universal_ble/UniversalBle.g.swift | 2 +- example/lib/home/home.dart | 2 +- lib/src/models/ble_device.dart | 4 +- lib/src/universal_ble.dart | 10 +- .../universal_ble_pigeon/universal_ble.g.dart | 919 ++++++++++-------- .../universal_ble_pigeon_channel.dart | 2 +- lib/src/universal_ble_platform_interface.dart | 4 +- .../universal_ble_web/universal_ble_web.dart | 2 +- windows/src/generated/universal_ble.g.cpp | 4 +- windows/src/generated/universal_ble.g.h | 2 +- 13 files changed, 630 insertions(+), 400 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eab3694..26bc38c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,7 @@ ## 2.0.0 -* Add first-party `UniversalBlePeripheral` API to integrate peripheral mode directly in `universal_ble` -* Add peripheral pigeon channels and platform hooks for Android/iOS/macOS/Windows -* Reuse shared `universal_ble` models for peripheral workflows where applicable -* Merge central and peripheral demos into a single tabbed example app +* Add peripheral mode on Android, iOS, macOS, and Windows * Add `requestConnectionPriority` to allow tuning BLE connection intervals on Android +* BREAKING CHANGE: `getBluetoothAvailabilityState` renamed to `getAvailabilityState` * Add SPM support on Apple ## 1.2.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..db1daf57 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,71 @@ +# Contributing + +Thank you for helping improve Universal BLE. This document describes how we work in this repository and what we expect from contributions. + +## Reporting issues + +Use [GitHub Issues](https://github.com/Navideck/universal_ble/issues). Include the platform (Android, iOS, macOS, Windows, Linux, Web), Flutter/Dart versions, and a minimal way to reproduce the problem when possible. + +## Pull requests + +- Open PRs against the `main` branch. +- Keep changes focused: one logical concern per PR is easier to review than a large mixed refactor. +- Update `CHANGELOG.md` when the change is user-visible (new behavior, fixes, or breaking API changes). Follow the existing bullet style (`* …`, `* BREAKING CHANGE: …` where appropriate). +- Do not commit secrets, local paths, or generated build artifacts unrelated to the change. + +## Environment + +Requirements are defined in `pubspec.yaml` (Dart SDK and Flutter). Use a stable Flutter channel unless a maintainer asks otherwise. + +From the repo root: + +```sh +flutter pub get +``` + +## Checks to run before opening a PR + +These mirror [.github/workflows/pull_request.yml](.github/workflows/pull_request.yml): + +```sh +flutter analyze +flutter test +flutter test --platform chrome +``` + +Fix any analyzer issues. The project uses [flutter_lints](https://pub.dev/packages/flutter_lints) via [analysis_options.yaml](analysis_options.yaml) (which includes `package:flutter_lints/flutter.yaml`). + +Format Dart code with the SDK formatter: + +```sh +dart format . +``` + +If you only touched specific files, you may format those paths instead of the whole tree. + +## Pigeon and generated code + +Host–native APIs are defined in [pigeon/universal_ble.dart](pigeon/universal_ble.dart). If you change that file, regenerate outputs and include them in the same PR: + +```sh +./build_pigeon.sh +``` + +That runs `dart run pigeon --input pigeon/universal_ble.dart` and formats `lib/src/universal_ble_pigeon/universal_ble.g.dart`. Regenerated Kotlin, Swift, and C++ files land under `android/`, `darwin/`, and `windows/` as configured in the Pigeon `@ConfigurePigeon` block—keep those in sync with the Dart definitions. + +## Code conventions + +- **Dart:** Follow effective Dart style, existing naming in `lib/`, and analyzer rules. Prefer extending existing patterns (platform interface → pigeon channel → native implementations) over new parallel abstractions unless discussed first. +- **Native:** Match the style and structure of the surrounding file on each platform (Kotlin, Swift, C++). When a Pigeon API changes, update every generated implementation and any hand-written glue so all targets stay consistent. +- **Tests:** Add or extend tests under `test/` when behavior is non-trivial or regression-prone. Use `flutter_test` like the existing suite. +- **Example:** If the change affects how integrators use the plugin, consider updating the `example/` app so it stays a working reference. + +## Platform-specific APIs and parameters + +- **Single-platform features:** Prefer not adding a new public API when only one platform can implement it, unless none of the existing APIs can be extended or adapted to cover the behavior. For example, something like Android-only `requestConnectionPriority` should only become its own method if `connect`, `platformConfig`, or another existing entry point cannot reasonably subsume it. +- **Single-platform parameters:** When a value applies to one platform only, attach it via a platform-scoped bag (for example `startScan` takes an optional `platformConfig` object for options that only affect a given OS). That keeps the main method signature stable and makes it obvious which settings are platform-specific. +- **Shared parameters:** If more than one platform supports the same option, add it as a normal method parameter on the shared API. Document that implementations on platforms without that capability must ignore the parameter (no-op or documented limitation). + +## License + +By contributing, you agree that your contributions will be licensed under the same terms as the project: [BSD 3-Clause License](LICENSE). diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt index 3e6f6bb6..946b2d51 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.3), do not edit directly. // See also: https://pub.dev/packages/pigeon @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift index d252608a..45a74ea2 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.3), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation diff --git a/example/lib/home/home.dart b/example/lib/home/home.dart index b6affb7e..28117c1b 100644 --- a/example/lib/home/home.dart +++ b/example/lib/home/home.dart @@ -225,7 +225,7 @@ class _CentralHomeState extends State { onPressed: () async { try { bool granted = - await UniversalBle.isPermissionGranted( + await UniversalBle.hasPermissions( withAndroidFineLocation: false, ); showSnackbar("Is Permission Granted: $granted"); diff --git a/lib/src/models/ble_device.dart b/lib/src/models/ble_device.dart index 17c41320..87aefbda 100644 --- a/lib/src/models/ble_device.dart +++ b/lib/src/models/ble_device.dart @@ -42,8 +42,8 @@ class BleDevice { /// On web, it returns true if the web browser supports receiving advertisements from this device. /// The rest of the platforms will always return true. - bool get isReceivingAdvertisements => - UniversalBle.isReceivingAdvertisements(deviceId); + bool get receivesAdvertisements => + UniversalBle.receivesAdvertisements(deviceId); BleDevice({ required this.deviceId, diff --git a/lib/src/universal_ble.dart b/lib/src/universal_ble.dart index 4f826127..52ccff08 100644 --- a/lib/src/universal_ble.dart +++ b/lib/src/universal_ble.dart @@ -77,10 +77,10 @@ class UniversalBle { /// [withAndroidFineLocation] is used to check fine location permission on Android 12+ (API 31+). /// On Android lower than 12, this method will check location permission regardless of the [withAndroidFineLocation] value. /// `Windows`, `Linux` and `Web` will always return true. - static Future isPermissionGranted({ + static Future hasPermissions({ bool withAndroidFineLocation = false, }) async { - return _platform.isPermissionGranted( + return _platform.hasPermissions( withAndroidFineLocation: withAndroidFineLocation, ); } @@ -534,15 +534,15 @@ class UniversalBle { /// If no [id] is provided, all queues will be cleared. static void clearQueue([String? id]) => _bleCommandQueue.clearQueue(id); - /// [isReceivingAdvertisements] returns true on web if the browser supports receiving advertisements from a certain `deviceId`. + /// [receivesAdvertisements] returns true on web if the browser supports receiving advertisements from a certain `deviceId`. /// The rest of the platforms will always return true. /// If true, then you will be getting scanResult updates for this device. /// /// For this feature to work, you need to enable the `chrome://flags/#enable-experimental-web-platform-features` flag. /// Not every browser supports this API yet. /// Even if the browser supports it, sometimes it won't fire any advertisement events even though the device may be sending them. - static bool isReceivingAdvertisements(String deviceId) => - _platform.isReceivingAdvertisements(deviceId); + static bool receivesAdvertisements(String deviceId) => + _platform.receivesAdvertisements(deviceId); /// Get Bluetooth state availability. static set onAvailabilityChange(OnAvailabilityChange? onAvailabilityChange) { diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index 6e04e50b..33864118 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.3), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: unused_import, unused_shown_name // ignore_for_file: type=lint @@ -10,9 +10,9 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; Object? _extractReplyValueOrThrow( - List? replyList, - String channelName, { - required bool isNullValid, + List? replyList, + String channelName, { + required bool isNullValid, }) { if (replyList == null) { throw PlatformException( @@ -34,8 +34,8 @@ Object? _extractReplyValueOrThrow( return replyList.firstOrNull; } - -List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -44,6 +44,7 @@ List wrapResponse({Object? result, PlatformException? error, bool empty } return [error.code, error.message, error.details]; } + bool _deepEquals(Object? a, Object? b) { if (identical(a, b)) { return true; @@ -106,7 +107,6 @@ int _deepHash(Object? value) { return value.hashCode; } - enum UniversalBleLogLevel { none, error, @@ -247,7 +247,8 @@ class UniversalBleScanResult { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalBleScanResult decode(Object result) { result as List; @@ -256,8 +257,10 @@ class UniversalBleScanResult { name: result[1] as String?, isPaired: result[2] as bool?, rssi: result[3] as int?, - manufacturerDataList: (result[4] as List?)?.cast(), - serviceData: (result[5] as Map?)?.cast(), + manufacturerDataList: + (result[4] as List?)?.cast(), + serviceData: + (result[5] as Map?)?.cast(), services: (result[6] as List?)?.cast(), timestamp: result[7] as int?, ); @@ -272,7 +275,14 @@ class UniversalBleScanResult { if (identical(this, other)) { return true; } - return _deepEquals(deviceId, other.deviceId) && _deepEquals(name, other.name) && _deepEquals(isPaired, other.isPaired) && _deepEquals(rssi, other.rssi) && _deepEquals(manufacturerDataList, other.manufacturerDataList) && _deepEquals(serviceData, other.serviceData) && _deepEquals(services, other.services) && _deepEquals(timestamp, other.timestamp); + return _deepEquals(deviceId, other.deviceId) && + _deepEquals(name, other.name) && + _deepEquals(isPaired, other.isPaired) && + _deepEquals(rssi, other.rssi) && + _deepEquals(manufacturerDataList, other.manufacturerDataList) && + _deepEquals(serviceData, other.serviceData) && + _deepEquals(services, other.services) && + _deepEquals(timestamp, other.timestamp); } @override @@ -298,13 +308,15 @@ class UniversalBleService { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalBleService decode(Object result) { result as List; return UniversalBleService( uuid: result[0]! as String, - characteristics: (result[1] as List?)?.cast(), + characteristics: + (result[1] as List?)?.cast(), ); } @@ -317,7 +329,8 @@ class UniversalBleService { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(characteristics, other.characteristics); + return _deepEquals(uuid, other.uuid) && + _deepEquals(characteristics, other.characteristics); } @override @@ -347,7 +360,8 @@ class UniversalBleCharacteristic { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalBleCharacteristic decode(Object result) { result as List; @@ -361,13 +375,16 @@ class UniversalBleCharacteristic { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! UniversalBleCharacteristic || other.runtimeType != runtimeType) { + if (other is! UniversalBleCharacteristic || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(descriptors, other.descriptors); + return _deepEquals(uuid, other.uuid) && + _deepEquals(properties, other.properties) && + _deepEquals(descriptors, other.descriptors); } @override @@ -389,7 +406,8 @@ class UniversalBleDescriptor { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalBleDescriptor decode(Object result) { result as List; @@ -443,7 +461,8 @@ class AndroidOptions { } Object encode() { - return _toList(); } + return _toList(); + } static AndroidOptions decode(Object result) { result as List; @@ -463,7 +482,10 @@ class AndroidOptions { if (identical(this, other)) { return true; } - return _deepEquals(requestLocationPermission, other.requestLocationPermission) && _deepEquals(scanMode, other.scanMode) && _deepEquals(reportDelayMillis, other.reportDelayMillis); + return _deepEquals( + requestLocationPermission, other.requestLocationPermission) && + _deepEquals(scanMode, other.scanMode) && + _deepEquals(reportDelayMillis, other.reportDelayMillis); } @override @@ -485,7 +507,8 @@ class UniversalScanConfig { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalScanConfig decode(Object result) { result as List; @@ -534,14 +557,16 @@ class UniversalScanFilter { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalScanFilter decode(Object result) { result as List; return UniversalScanFilter( withServices: (result[0]! as List).cast(), withNamePrefix: (result[1]! as List).cast(), - withManufacturerData: (result[2]! as List).cast(), + withManufacturerData: + (result[2]! as List).cast(), ); } @@ -554,7 +579,9 @@ class UniversalScanFilter { if (identical(this, other)) { return true; } - return _deepEquals(withServices, other.withServices) && _deepEquals(withNamePrefix, other.withNamePrefix) && _deepEquals(withManufacturerData, other.withManufacturerData); + return _deepEquals(withServices, other.withServices) && + _deepEquals(withNamePrefix, other.withNamePrefix) && + _deepEquals(withManufacturerData, other.withManufacturerData); } @override @@ -584,7 +611,8 @@ class UniversalManufacturerDataFilter { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalManufacturerDataFilter decode(Object result) { result as List; @@ -598,13 +626,16 @@ class UniversalManufacturerDataFilter { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! UniversalManufacturerDataFilter || other.runtimeType != runtimeType) { + if (other is! UniversalManufacturerDataFilter || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(companyIdentifier, other.companyIdentifier) && _deepEquals(data, other.data) && _deepEquals(mask, other.mask); + return _deepEquals(companyIdentifier, other.companyIdentifier) && + _deepEquals(data, other.data) && + _deepEquals(mask, other.mask); } @override @@ -630,7 +661,8 @@ class UniversalManufacturerData { } Object encode() { - return _toList(); } + return _toList(); + } static UniversalManufacturerData decode(Object result) { result as List; @@ -643,13 +675,15 @@ class UniversalManufacturerData { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! UniversalManufacturerData || other.runtimeType != runtimeType) { + if (other is! UniversalManufacturerData || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(companyIdentifier, other.companyIdentifier) && _deepEquals(data, other.data); + return _deepEquals(companyIdentifier, other.companyIdentifier) && + _deepEquals(data, other.data); } @override @@ -679,14 +713,16 @@ class PeripheralService { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralService decode(Object result) { result as List; return PeripheralService( uuid: result[0]! as String, primary: result[1]! as bool, - characteristics: (result[2]! as List).cast(), + characteristics: + (result[2]! as List).cast(), ); } @@ -699,7 +735,9 @@ class PeripheralService { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(primary, other.primary) && _deepEquals(characteristics, other.characteristics); + return _deepEquals(uuid, other.uuid) && + _deepEquals(primary, other.primary) && + _deepEquals(characteristics, other.characteristics); } @override @@ -737,7 +775,8 @@ class PeripheralCharacteristic { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralCharacteristic decode(Object result) { result as List; @@ -753,13 +792,18 @@ class PeripheralCharacteristic { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralCharacteristic || other.runtimeType != runtimeType) { + if (other is! PeripheralCharacteristic || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(properties, other.properties) && _deepEquals(permissions, other.permissions) && _deepEquals(descriptors, other.descriptors) && _deepEquals(value, other.value); + return _deepEquals(uuid, other.uuid) && + _deepEquals(properties, other.properties) && + _deepEquals(permissions, other.permissions) && + _deepEquals(descriptors, other.descriptors) && + _deepEquals(value, other.value); } @override @@ -789,7 +833,8 @@ class PeripheralDescriptor { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralDescriptor decode(Object result) { result as List; @@ -809,7 +854,9 @@ class PeripheralDescriptor { if (identical(this, other)) { return true; } - return _deepEquals(uuid, other.uuid) && _deepEquals(value, other.value) && _deepEquals(permissions, other.permissions); + return _deepEquals(uuid, other.uuid) && + _deepEquals(value, other.value) && + _deepEquals(permissions, other.permissions); } @override @@ -839,7 +886,8 @@ class PeripheralReadRequestResult { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralReadRequestResult decode(Object result) { result as List; @@ -853,13 +901,16 @@ class PeripheralReadRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralReadRequestResult || other.runtimeType != runtimeType) { + if (other is! PeripheralReadRequestResult || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); + return _deepEquals(value, other.value) && + _deepEquals(offset, other.offset) && + _deepEquals(status, other.status); } @override @@ -889,7 +940,8 @@ class PeripheralWriteRequestResult { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralWriteRequestResult decode(Object result) { result as List; @@ -903,13 +955,16 @@ class PeripheralWriteRequestResult { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralWriteRequestResult || other.runtimeType != runtimeType) { + if (other is! PeripheralWriteRequestResult || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(value, other.value) && _deepEquals(offset, other.offset) && _deepEquals(status, other.status); + return _deepEquals(value, other.value) && + _deepEquals(offset, other.offset) && + _deepEquals(status, other.status); } @override @@ -935,7 +990,8 @@ class PeripheralManufacturerData { } Object encode() { - return _toList(); } + return _toList(); + } static PeripheralManufacturerData decode(Object result) { result as List; @@ -948,13 +1004,15 @@ class PeripheralManufacturerData { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! PeripheralManufacturerData || other.runtimeType != runtimeType) { + if (other is! PeripheralManufacturerData || + other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { return true; } - return _deepEquals(manufacturerId, other.manufacturerId) && _deepEquals(data, other.data); + return _deepEquals(manufacturerId, other.manufacturerId) && + _deepEquals(data, other.data); } @override @@ -962,7 +1020,6 @@ class PeripheralManufacturerData { int get hashCode => _deepHash([runtimeType, ..._toList()]); } - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -970,64 +1027,64 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is UniversalBleLogLevel) { + } else if (value is UniversalBleLogLevel) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is AndroidScanMode) { + } else if (value is AndroidScanMode) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is PeripheralReadinessState) { + } else if (value is PeripheralReadinessState) { buffer.putUint8(131); writeValue(buffer, value.index); - } else if (value is PeripheralAdvertisingState) { + } else if (value is PeripheralAdvertisingState) { buffer.putUint8(132); writeValue(buffer, value.index); - } else if (value is UniversalBleErrorCode) { + } else if (value is UniversalBleErrorCode) { buffer.putUint8(133); writeValue(buffer, value.index); - } else if (value is UniversalBleScanResult) { + } else if (value is UniversalBleScanResult) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is UniversalBleService) { + } else if (value is UniversalBleService) { buffer.putUint8(135); writeValue(buffer, value.encode()); - } else if (value is UniversalBleCharacteristic) { + } else if (value is UniversalBleCharacteristic) { buffer.putUint8(136); writeValue(buffer, value.encode()); - } else if (value is UniversalBleDescriptor) { + } else if (value is UniversalBleDescriptor) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is AndroidOptions) { + } else if (value is AndroidOptions) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is UniversalScanConfig) { + } else if (value is UniversalScanConfig) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is UniversalScanFilter) { + } else if (value is UniversalScanFilter) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is UniversalManufacturerDataFilter) { + } else if (value is UniversalManufacturerDataFilter) { buffer.putUint8(141); writeValue(buffer, value.encode()); - } else if (value is UniversalManufacturerData) { + } else if (value is UniversalManufacturerData) { buffer.putUint8(142); writeValue(buffer, value.encode()); - } else if (value is PeripheralService) { + } else if (value is PeripheralService) { buffer.putUint8(143); writeValue(buffer, value.encode()); - } else if (value is PeripheralCharacteristic) { + } else if (value is PeripheralCharacteristic) { buffer.putUint8(144); writeValue(buffer, value.encode()); - } else if (value is PeripheralDescriptor) { + } else if (value is PeripheralDescriptor) { buffer.putUint8(145); writeValue(buffer, value.encode()); - } else if (value is PeripheralReadRequestResult) { + } else if (value is PeripheralReadRequestResult) { buffer.putUint8(146); writeValue(buffer, value.encode()); - } else if (value is PeripheralWriteRequestResult) { + } else if (value is PeripheralWriteRequestResult) { buffer.putUint8(147); writeValue(buffer, value.encode()); - } else if (value is PeripheralManufacturerData) { + } else if (value is PeripheralManufacturerData) { buffer.putUint8(148); writeValue(buffer, value.encode()); } else { @@ -1094,9 +1151,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 pigeonChannelCodec = _PigeonCodec(); @@ -1104,7 +1163,8 @@ class UniversalBlePlatformChannel { final String pigeonVar_messageChannelSuffix; Future getBluetoothAvailabilityState() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1114,53 +1174,55 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as int; } Future hasPermissions(bool withAndroidFineLocation) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.hasPermissions$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.hasPermissions$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([withAndroidFineLocation]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([withAndroidFineLocation]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future requestPermissions(bool withAndroidFineLocation) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestPermissions$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestPermissions$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([withAndroidFineLocation]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([withAndroidFineLocation]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future enableBluetooth() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1170,16 +1232,16 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future disableBluetooth() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disableBluetooth$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1189,34 +1251,36 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } - Future startScan(UniversalScanFilter? filter, UniversalScanConfig? config) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix'; + Future startScan( + UniversalScanFilter? filter, UniversalScanConfig? config) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([filter, config]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([filter, config]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future stopScan() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1226,15 +1290,15 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future isScanning() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isScanning$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1244,253 +1308,271 @@ class UniversalBlePlatformChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future connect(String deviceId, {bool? autoConnect}) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, autoConnect]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, autoConnect]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future disconnect(String deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future setNotifiable(String deviceId, String service, String characteristic, int bleInputProperty) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix'; + Future setNotifiable(String deviceId, String service, + String characteristic, int bleInputProperty) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, service, characteristic, bleInputProperty]); + final Future pigeonVar_sendFuture = pigeonVar_channel + .send([deviceId, service, characteristic, bleInputProperty]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future> discoverServices(String deviceId, bool withDescriptors) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix'; + Future> discoverServices( + String deviceId, bool withDescriptors) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, withDescriptors]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, withDescriptors]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return (pigeonVar_replyValue! as List).cast(); } - Future readValue(String deviceId, String service, String characteristic) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix'; + Future readValue( + String deviceId, String service, String characteristic) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, service, characteristic]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, service, characteristic]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as Uint8List; } Future requestMtu(String deviceId, int expectedMtu) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, expectedMtu]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId, expectedMtu]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as int; } - Future writeValue(String deviceId, String service, String characteristic, Uint8List value, int bleOutputProperty) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix'; + Future writeValue(String deviceId, String service, + String characteristic, Uint8List value, int bleOutputProperty) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, service, characteristic, value, bleOutputProperty]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [deviceId, service, characteristic, value, bleOutputProperty]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future isPaired(String deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future pair(String deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future unPair(String deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future> getSystemDevices(List withServices) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix'; + Future> getSystemDevices( + List withServices) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getSystemDevices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([withServices]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([withServices]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; - return (pigeonVar_replyValue! as List).cast(); + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List) + .cast(); } Future getConnectionState(String deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectionState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as int; } Future readRssi(String deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as int; } @@ -1498,42 +1580,38 @@ class UniversalBlePlatformChannel { final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestConnectionPriority$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger); + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId, priority]); - final pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future setLogLevel(UniversalBleLogLevel logLevel) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([logLevel]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([logLevel]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } } @@ -1547,15 +1625,22 @@ abstract class UniversalBleCallbackChannel { void onScanResult(UniversalBleScanResult result); - void onValueChanged(String deviceId, String characteristicId, Uint8List value, int? timestamp); + void onValueChanged(String deviceId, String characteristicId, Uint8List value, + int? timestamp); 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 pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1568,15 +1653,17 @@ abstract class UniversalBleCallbackChannel { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1591,36 +1678,41 @@ abstract class UniversalBleCallbackChannel { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { final List args = message! as List; - final UniversalBleScanResult arg_result = args[0]! as UniversalBleScanResult; + final UniversalBleScanResult arg_result = + args[0]! as UniversalBleScanResult; try { api.onScanResult(arg_result); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1632,19 +1724,22 @@ abstract class UniversalBleCallbackChannel { final Uint8List arg_value = args[2]! as Uint8List; final int? arg_timestamp = args[3] as int?; try { - api.onValueChanged(arg_deviceId, arg_characteristicId, arg_value, arg_timestamp); + api.onValueChanged( + arg_deviceId, arg_characteristicId, arg_value, arg_timestamp); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1659,8 +1754,9 @@ abstract class UniversalBleCallbackChannel { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } @@ -1673,9 +1769,11 @@ class UniversalBlePeripheralChannel { /// Constructor for [UniversalBlePeripheralChannel]. 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. - UniversalBlePeripheralChannel({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + UniversalBlePeripheralChannel( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -1683,7 +1781,8 @@ class UniversalBlePeripheralChannel { final String pigeonVar_messageChannelSuffix; Future getAdvertisingState() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getAdvertisingState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getAdvertisingState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1693,16 +1792,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as PeripheralAdvertisingState; } Future getReadinessState() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getReadinessState$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1712,16 +1811,16 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as PeripheralReadinessState; } Future stopAdvertising() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.stopAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1731,51 +1830,53 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future addService(PeripheralService service) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.addService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([service]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([service]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future removeService(String serviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.removeService$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([serviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([serviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future clearServices() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.clearServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1785,15 +1886,15 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future> getServices() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getServices$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -1803,88 +1904,103 @@ class UniversalBlePeripheralChannel { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return (pigeonVar_replyValue! as List).cast(); } - Future startAdvertising(List services, String? localName, int? timeout, PeripheralManufacturerData? manufacturerData, bool addManufacturerDataInScanResponse) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; + Future startAdvertising( + List services, + String? localName, + int? timeout, + PeripheralManufacturerData? manufacturerData, + bool addManufacturerDataInScanResponse) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.startAdvertising$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([services, localName, timeout, manufacturerData, addManufacturerDataInScanResponse]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([ + services, + localName, + timeout, + manufacturerData, + addManufacturerDataInScanResponse + ]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } - Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; + Future updateCharacteristic( + String characteristicId, Uint8List value, String? deviceId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId, value, deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([characteristicId, value, deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns peripheral-client device ids currently subscribed to [characteristicId] /// (e.g. HID report characteristic). Used to restore app state after restart. Future> getSubscribedClients(String characteristicId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedClients$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getSubscribedClients$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([characteristicId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([characteristicId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return (pigeonVar_replyValue! as List).cast(); } /// Returns max characteristic notify payload length for a connected client. Future getMaximumNotifyLength(String deviceId) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getMaximumNotifyLength$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralChannel.getMaximumNotifyLength$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([deviceId]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([deviceId]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); return pigeonVar_replyValue as int?; } } @@ -1893,17 +2009,31 @@ class UniversalBlePeripheralChannel { abstract class UniversalBlePeripheralCallback { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - PeripheralReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralReadRequestResult? onReadRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); - PeripheralWriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); + PeripheralWriteRequestResult? onWriteRequest( + String deviceId, String characteristicId, int offset, Uint8List? value); - PeripheralReadRequestResult? onDescriptorReadRequest(String deviceId, String characteristicId, String descriptorId, int offset, Uint8List? value); + PeripheralReadRequestResult? onDescriptorReadRequest( + String deviceId, + String characteristicId, + String descriptorId, + int offset, + Uint8List? value); - PeripheralWriteRequestResult? onDescriptorWriteRequest(String deviceId, String characteristicId, String descriptorId, int offset, Uint8List? value); + PeripheralWriteRequestResult? onDescriptorWriteRequest( + String deviceId, + String characteristicId, + String descriptorId, + int offset, + Uint8List? value); - void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); + void onCharacteristicSubscriptionChange(String deviceId, + String characteristicId, bool isSubscribed, String? name); - void onAdvertisingStateChange(PeripheralAdvertisingState state, String? error); + void onAdvertisingStateChange( + PeripheralAdvertisingState state, String? error); void onServiceAdded(String serviceId, String? error); @@ -1911,11 +2041,17 @@ abstract class UniversalBlePeripheralCallback { void onConnectionStateChange(String deviceId, bool connected); - static void setUp(UniversalBlePeripheralCallback? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp( + UniversalBlePeripheralCallback? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onReadRequest$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1927,19 +2063,22 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralReadRequestResult? output = api.onReadRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralReadRequestResult? output = api.onReadRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onWriteRequest$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1951,19 +2090,22 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[2]! as int; final Uint8List? arg_value = args[3] as Uint8List?; try { - final PeripheralWriteRequestResult? output = api.onWriteRequest(arg_deviceId, arg_characteristicId, arg_offset, arg_value); + final PeripheralWriteRequestResult? output = api.onWriteRequest( + arg_deviceId, arg_characteristicId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorReadRequest$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorReadRequest$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -1976,19 +2118,23 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[3]! as int; final Uint8List? arg_value = args[4] as Uint8List?; try { - final PeripheralReadRequestResult? output = api.onDescriptorReadRequest(arg_deviceId, arg_characteristicId, arg_descriptorId, arg_offset, arg_value); + final PeripheralReadRequestResult? output = + api.onDescriptorReadRequest(arg_deviceId, arg_characteristicId, + arg_descriptorId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorWriteRequest$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onDescriptorWriteRequest$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2001,19 +2147,23 @@ abstract class UniversalBlePeripheralCallback { final int arg_offset = args[3]! as int; final Uint8List? arg_value = args[4] as Uint8List?; try { - final PeripheralWriteRequestResult? output = api.onDescriptorWriteRequest(arg_deviceId, arg_characteristicId, arg_descriptorId, arg_offset, arg_value); + final PeripheralWriteRequestResult? output = + api.onDescriptorWriteRequest(arg_deviceId, arg_characteristicId, + arg_descriptorId, arg_offset, arg_value); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onCharacteristicSubscriptionChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2025,41 +2175,47 @@ abstract class UniversalBlePeripheralCallback { final bool arg_isSubscribed = args[2]! as bool; final String? arg_name = args[3] as String?; try { - api.onCharacteristicSubscriptionChange(arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); + api.onCharacteristicSubscriptionChange( + arg_deviceId, arg_characteristicId, arg_isSubscribed, arg_name); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStateChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onAdvertisingStateChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { final List args = message! as List; - final PeripheralAdvertisingState arg_state = args[0]! as PeripheralAdvertisingState; + final PeripheralAdvertisingState arg_state = + args[0]! as PeripheralAdvertisingState; final String? arg_error = args[1] as String?; try { api.onAdvertisingStateChange(arg_state, arg_error); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onServiceAdded$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2073,15 +2229,17 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onMtuChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2095,15 +2253,17 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.universal_ble.UniversalBlePeripheralCallback.onConnectionStateChange$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); @@ -2117,8 +2277,9 @@ abstract class UniversalBlePeripheralCallback { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart index 8fadea35..f406dca4 100644 --- a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart +++ b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart @@ -180,7 +180,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { _executeWithErrorHandling(() => _channel.unPair(deviceId)); @override - Future isPermissionGranted({ + Future hasPermissions({ bool withAndroidFineLocation = false, }) async { return await _executeWithErrorHandling( diff --git a/lib/src/universal_ble_platform_interface.dart b/lib/src/universal_ble_platform_interface.dart index 885b005c..cd4a8c5c 100644 --- a/lib/src/universal_ble_platform_interface.dart +++ b/lib/src/universal_ble_platform_interface.dart @@ -37,7 +37,7 @@ abstract class UniversalBlePlatform { Future disableBluetooth(); - Future isPermissionGranted({ + Future hasPermissions({ bool withAndroidFineLocation = false, }) async { return true; @@ -113,7 +113,7 @@ abstract class UniversalBlePlatform { Future setLogLevel(BleLogLevel logLevel) async => UniversalLogger.setLogLevel(logLevel); - bool isReceivingAdvertisements(String deviceId) => true; + bool receivesAdvertisements(String deviceId) => true; /// Streams Stream get scanStream => _scanStreamController.stream; diff --git a/lib/src/universal_ble_web/universal_ble_web.dart b/lib/src/universal_ble_web/universal_ble_web.dart index c46b50dd..ac5b1d2e 100644 --- a/lib/src/universal_ble_web/universal_ble_web.dart +++ b/lib/src/universal_ble_web/universal_ble_web.dart @@ -114,7 +114,7 @@ class UniversalBleWeb extends UniversalBlePlatform { } @override - bool isReceivingAdvertisements(String deviceId) { + bool receivesAdvertisements(String deviceId) { // Advertisements do not work on Linux/Web even with the "Experimental Web Platform features" flag enabled. Verified with Chrome Version 128.0.6613.138 if (kIsWeb && defaultTargetPlatform == TargetPlatform.linux) { return false; diff --git a/windows/src/generated/universal_ble.g.cpp b/windows/src/generated/universal_ble.g.cpp index c0315e12..25b1abea 100644 --- a/windows/src/generated/universal_ble.g.cpp +++ b/windows/src/generated/universal_ble.g.cpp @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.3), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS @@ -2373,7 +2373,7 @@ void UniversalBlePlatformChannel::SetUp( { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestConnectionPriority" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_device_id_arg = args.at(0); diff --git a/windows/src/generated/universal_ble.g.h b/windows/src/generated/universal_ble.g.h index 1602d1ce..8951dfcc 100644 --- a/windows/src/generated/universal_ble.g.h +++ b/windows/src/generated/universal_ble.g.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.3), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_UNIVERSAL_BLE_G_H_ From 278f0230d1b2e54cc7bb05873f8face0be60b707 Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Wed, 1 Apr 2026 23:15:43 +0200 Subject: [PATCH 22/23] Enhance BLE peripheral functionality and documentation - Updated README to clarify advertising behavior on Android and Windows, including handling of `localName` and manufacturer data. - Modified advertising logic to conditionally set parameters based on the platform. - Improved string comparison in Swift for peripheral characteristics and services to be case-insensitive. - Enhanced error handling in the Windows plugin for advertising and characteristic updates. - Refactored BLE service equality checks to use list comparison for better accuracy. --- README.md | 24 ++-- .../UniversalBlePeripheralPlugin.kt | 1 + .../UniversalBlePeripheralExtensions.swift | 10 +- .../UniversalBlePeripheralPlugin.swift | 15 ++- example/ios/Podfile.lock | 7 -- example/lib/peripheral/peripheral_home.dart | 23 ++-- lib/src/models/ble_service.dart | 8 +- windows/src/universal_ble_plugin.cpp | 108 ++++++++++++------ windows/src/universal_ble_plugin.h | 6 +- 9 files changed, 138 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 4f6ef372..acf1c78f 100644 --- a/README.md +++ b/README.md @@ -640,6 +640,7 @@ The error parser automatically converts platform-specific error formats (strings ```dart import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:universal_ble/universal_ble.dart'; final peripheral = UniversalBlePeripheralClient(); @@ -685,18 +686,27 @@ await peripheral.removeService(const PeripheralServiceId("0000180D-0000-1000-800 ### Advertising +On **Android**, passing `localName` may temporarily change the system Bluetooth device name (so it can appear in the advertisement). The plugin restores the previous name when advertising stops, if starting advertising fails, or when the plugin is disposed. + +On **Windows**, `GattServiceProvider`-based advertising does not support `localName`, manufacturer data, or a scan-response flag; omit them (as below) or the call will return a not-supported error. + ```dart +final isWindows = !kIsWeb && defaultTargetPlatform == TargetPlatform.windows; + await peripheral.startAdvertising( services: const [ PeripheralServiceId("0000180F-0000-1000-8000-00805F9B34FB"), ], - localName: "UniversalBlePeripheral", - manufacturerData: ManufacturerData( - 0x012D, - Uint8List.fromList([0x03, 0x00, 0x64, 0x00]), - ), - addManufacturerDataInScanResponse: - caps.supportsManufacturerDataInScanResponse, + localName: isWindows ? null : "UniversalBlePeripheral", + manufacturerData: isWindows + ? null + : ManufacturerData( + 0x012D, + Uint8List.fromList([0x03, 0x00, 0x64, 0x00]), + ), + addManufacturerDataInScanResponse: isWindows + ? false + : caps.supportsManufacturerDataInScanResponse, ); final advertisingState = await peripheral.getAdvertisingState(); diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt index 98458e54..0a2fe387 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBlePeripheralPlugin.kt @@ -283,6 +283,7 @@ class UniversalBlePeripheralPlugin( override fun onStartFailure(errorCode: Int) { super.onStartFailure(errorCode) handler.post { + restoreAdapterNameIfNeeded() val errorMessage = when (errorCode) { ADVERTISE_FAILED_ALREADY_STARTED -> "Already started" ADVERTISE_FAILED_DATA_TOO_LARGE -> "Data too large" diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift index a361c6fd..3d3fd86b 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralExtensions.swift @@ -64,11 +64,17 @@ extension PeripheralCharacteristic { extension String { func findPeripheralCharacteristic() -> CBMutableCharacteristic? { - peripheralCharacteristicsList.first { $0.uuid.uuidString == self } + let target = lowercased() + return peripheralCharacteristicsList.first { + $0.uuid.uuidString.lowercased() == target + } } func findPeripheralService() -> CBMutableService? { - peripheralServicesList.first { $0.uuid.uuidString == self } + let target = lowercased() + return peripheralServicesList.first { + $0.uuid.uuidString.lowercased() == target + } } } diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift index 4c82a795..c97cbee6 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePeripheralPlugin.swift @@ -227,11 +227,22 @@ final class UniversalBlePeripheralPlugin: NSObject, UniversalBlePeripheralChanne ) { readReq in do { let result = try readReq.get() - guard let data = result?.value.toData() as Data? else { + let status = result?.status?.toCBATTErrorCode() ?? .success + guard status == .success else { + self.peripheralManager.respond(to: request, withResult: status) + return + } + guard let fullData = result?.value.toData() as Data? else { self.peripheralManager.respond(to: request, withResult: .requestNotSupported) return } - request.value = data + let offset = Int(request.offset) + guard offset <= fullData.count else { + self.peripheralManager.respond(to: request, withResult: .invalidOffset) + return + } + let sliced = fullData.subdata(in: offset.. { PeripheralRequestHandlers( onReadRequest: (deviceId, characteristicId, _, __) { _log('Read request: $deviceId ${characteristicId.value}'); - return BleReadRequestResult(value: utf8.encode('Hello World')); + return BleReadRequestResult( + value: Uint8List.fromList(utf8.encode('Hello World')), + ); }, onWriteRequest: (deviceId, characteristicId, _, value) { _log('Write request: $deviceId ${characteristicId.value} $value'); @@ -107,17 +109,20 @@ class _PeripheralHomeState extends State { } Future _startAdvertising() async { + final isWindows = !kIsWeb && defaultTargetPlatform == TargetPlatform.windows; await _peripheral.startAdvertising( services: [ const PeripheralServiceId(_serviceBattery), const PeripheralServiceId(_serviceTest), ], - localName: 'UniversalBlePeripheral', - manufacturerData: ManufacturerData( - 0x012D, - Uint8List.fromList([0x03, 0x00, 0x64, 0x00]), - ), - addManufacturerDataInScanResponse: true, + localName: isWindows ? null : 'UniversalBlePeripheral', + manufacturerData: isWindows + ? null + : ManufacturerData( + 0x012D, + Uint8List.fromList([0x03, 0x00, 0x64, 0x00]), + ), + addManufacturerDataInScanResponse: !isWindows, ); _log('Start advertising requested'); } @@ -164,7 +169,7 @@ class _PeripheralHomeState extends State { characteristicId: const PeripheralCharacteristicId( _charTest, ), - value: utf8.encode('Test Data'), + value: Uint8List.fromList(utf8.encode('Test Data')), ); _log('Characteristic updated'); } diff --git a/lib/src/models/ble_service.dart b/lib/src/models/ble_service.dart index c4c41083..c1a97c8c 100644 --- a/lib/src/models/ble_service.dart +++ b/lib/src/models/ble_service.dart @@ -1,5 +1,4 @@ -import 'dart:typed_data'; - +import 'package:flutter/foundation.dart'; import 'package:universal_ble/universal_ble.dart'; class BleService { @@ -68,11 +67,12 @@ class BleDescriptor { @override bool operator ==(Object other) { if (other is! BleDescriptor) return false; - return other.uuid == uuid && other.value == value; + return other.uuid == uuid && listEquals(other.value, value); } @override - int get hashCode => Object.hash(uuid, value); + int get hashCode => + Object.hash(uuid, value == null ? null : Object.hashAll(value!)); } enum CharacteristicProperty { diff --git a/windows/src/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp index cad43d35..b3baf409 100644 --- a/windows/src/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -1624,8 +1625,9 @@ ErrorOr UniversalBlePlugin::GetAdvertisingState() { if (peripheral_service_provider_map_.empty()) { return PeripheralAdvertisingState::kIdle; } - return AreAllPeripheralServicesStarted() ? PeripheralAdvertisingState::kAdvertising - : PeripheralAdvertisingState::kIdle; + return ArePeripheralAdvertisingTargetsStarted() + ? PeripheralAdvertisingState::kAdvertising + : PeripheralAdvertisingState::kIdle; } ErrorOr UniversalBlePlugin::GetReadinessState() { @@ -1637,6 +1639,7 @@ ErrorOr UniversalBlePlugin::GetReadinessState() { std::optional UniversalBlePlugin::StopAdvertising() { std::lock_guard lock(peripheral_mutex_); + peripheral_advertising_targets_lc_.clear(); for (auto const &[key, provider] : peripheral_service_provider_map_) { try { provider->obj.StopAdvertising(); @@ -1661,6 +1664,10 @@ std::optional UniversalBlePlugin::RemoveService( const std::string &service_id) { std::lock_guard lock(peripheral_mutex_); const std::string service_id_lc = to_lower_case(service_id); + peripheral_advertising_targets_lc_.erase( + std::remove(peripheral_advertising_targets_lc_.begin(), + peripheral_advertising_targets_lc_.end(), service_id_lc), + peripheral_advertising_targets_lc_.end()); const auto it = peripheral_service_provider_map_.find(service_id_lc); if (it == peripheral_service_provider_map_.end()) { return FlutterError("not-found", "Service not found", nullptr); @@ -1672,6 +1679,7 @@ std::optional UniversalBlePlugin::RemoveService( std::optional UniversalBlePlugin::ClearServices() { std::lock_guard lock(peripheral_mutex_); + peripheral_advertising_targets_lc_.clear(); for (auto const &[_, provider] : peripheral_service_provider_map_) { DisposePeripheralServiceProvider(provider.get()); } @@ -1791,6 +1799,7 @@ std::optional UniversalBlePlugin::StartAdvertising( provider->obj.StartAdvertising(params); } } + peripheral_advertising_targets_lc_ = std::move(selected_services_lc); return std::nullopt; } catch (...) { return FlutterError("failed", "Failed to start advertising", nullptr); @@ -1800,32 +1809,50 @@ std::optional UniversalBlePlugin::StartAdvertising( std::optional UniversalBlePlugin::UpdateCharacteristic( const std::string &characteristic_id, const std::vector &value, const std::string *device_id) { - std::lock_guard lock(peripheral_mutex_); - if (device_id != nullptr) { - return FlutterError( - "not-supported", - "Windows does not support targeting a specific device for notifications", - nullptr); - } - bool ambiguous_match = false; - auto *characteristic_object = - FindPeripheralGattCharacteristicObject(characteristic_id, &ambiguous_match); - if (ambiguous_match) { - return FlutterError( - "ambiguous-characteristic", - "Characteristic UUID exists in multiple services; cannot update uniquely", - nullptr); - } - if (characteristic_object == nullptr) { - return FlutterError("not-found", "Characteristic not found", nullptr); + GattLocalCharacteristic local_char = nullptr; + IBuffer buffer = nullptr; + { + std::lock_guard lock(peripheral_mutex_); + if (device_id != nullptr) { + return FlutterError( + "not-supported", + "Windows does not support targeting a specific device for notifications", + nullptr); + } + bool ambiguous_match = false; + auto *characteristic_object = + FindPeripheralGattCharacteristicObject(characteristic_id, &ambiguous_match); + if (ambiguous_match) { + return FlutterError( + "ambiguous-characteristic", + "Characteristic UUID exists in multiple services; cannot update uniquely", + nullptr); + } + if (characteristic_object == nullptr) { + return FlutterError("not-found", "Characteristic not found", nullptr); + } + IBuffer bytes = from_bytevc(value); + DataWriter writer; + writer.ByteOrder(ByteOrder::LittleEndian); + writer.WriteBuffer(bytes); + local_char = characteristic_object->obj; + buffer = writer.DetachBuffer(); } - IBuffer bytes = from_bytevc(value); - DataWriter writer; - writer.ByteOrder(ByteOrder::LittleEndian); - writer.WriteBuffer(bytes); - auto notify_result = - characteristic_object->obj.NotifyValueAsync(writer.DetachBuffer()).get(); - if (!notify_result) { + + try { + std::future notify_future = std::async( + std::launch::async, [local_char, buffer]() { + auto op = local_char.NotifyValueAsync(buffer); + return op.get(); + }); + const bool notify_result = notify_future.get(); + if (!notify_result) { + return FlutterError( + "failed", + "Failed to notify subscribed clients for characteristic update", + nullptr); + } + } catch (...) { return FlutterError( "failed", "Failed to notify subscribed clients for characteristic update", @@ -2167,7 +2194,8 @@ void UniversalBlePlugin::PeripheralAdvertisementStatusChanged( }); return; } - if (AreAllPeripheralServicesStarted()) { + std::lock_guard lock(peripheral_mutex_); + if (ArePeripheralAdvertisingTargetsStarted()) { ui_thread_handler_.Post([this] { peripheral_callback_channel_->OnAdvertisingStateChange( PeripheralAdvertisingState::kAdvertising, nullptr, SuccessCallback, @@ -2230,14 +2258,30 @@ UniversalBlePlugin::FindPeripheralGattCharacteristicObject( return first_match; } -bool UniversalBlePlugin::AreAllPeripheralServicesStarted() const { - for (auto const &[_, service_provider] : peripheral_service_provider_map_) { - if (service_provider->obj.AdvertisementStatus() != +bool UniversalBlePlugin::ArePeripheralAdvertisingTargetsStarted() const { + if (peripheral_service_provider_map_.empty()) { + return false; + } + if (peripheral_advertising_targets_lc_.empty()) { + for (auto const &[_, service_provider] : peripheral_service_provider_map_) { + if (service_provider->obj.AdvertisementStatus() != + GattServiceProviderAdvertisementStatus::Started) { + return false; + } + } + return true; + } + for (const auto &target_id : peripheral_advertising_targets_lc_) { + const auto it = peripheral_service_provider_map_.find(target_id); + if (it == peripheral_service_provider_map_.end()) { + return false; + } + if (it->second->obj.AdvertisementStatus() != GattServiceProviderAdvertisementStatus::Started) { return false; } } - return !peripheral_service_provider_map_.empty(); + return true; } GattCharacteristicProperties diff --git a/windows/src/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h index a3e5179c..00ddf620 100644 --- a/windows/src/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -22,6 +22,7 @@ #include "ui_thread_handler.hpp" #include "universal_ble_thread_safe.h" #include +#include namespace universal_ble { struct GattCharacteristicObject { @@ -194,6 +195,9 @@ class UniversalBlePlugin : public flutter::Plugin, // Peripheral runtime state std::unordered_map> peripheral_service_provider_map_{}; + /// Lowercased service UUIDs from the last successful `StartAdvertising` call. + /// Empty means all registered services were selected. + std::vector peripheral_advertising_targets_lc_{}; event_revoker peripheral_radio_state_changed_revoker_; std::unique_ptr peripheral_callback_channel_; std::mutex peripheral_mutex_; @@ -216,7 +220,7 @@ class UniversalBlePlugin : public flutter::Plugin, PeripheralGattCharacteristicObject *FindPeripheralGattCharacteristicObject( const std::string &characteristic_id, bool *ambiguous_match = nullptr); - bool AreAllPeripheralServicesStarted() const; + bool ArePeripheralAdvertisingTargetsStarted() const; static uint8_t ToGattProtocolError(int64_t status_code); static GattCharacteristicProperties ToPeripheralGattCharacteristicProperties( int property); From 32891589a0b1f68541e3a10497537c241a89c8aa Mon Sep 17 00:00:00 2001 From: Foti Dim Date: Thu, 2 Apr 2026 14:20:03 +0200 Subject: [PATCH 23/23] Add Podfile for iOS and macOS; update xcconfig includes - Created Podfile for both iOS and macOS to manage dependencies and build settings. - Updated Debug and Release xcconfig files to include necessary Pod support files. - Ensured compatibility with Flutter's pod installation process and project structure. --- example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + example/ios/Podfile | 43 +++++++++++++++++++ example/ios/Podfile.lock | 4 +- example/macos/Flutter/Flutter-Debug.xcconfig | 1 + .../macos/Flutter/Flutter-Release.xcconfig | 1 + example/macos/Podfile | 42 ++++++++++++++++++ 7 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 example/ios/Podfile create mode 100644 example/macos/Podfile diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index 592ceee8..ec97fc6f 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 592ceee8..c4855bfe 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 00000000..620e46eb --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 79ce2ead..0b74389f 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -22,8 +22,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e - universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914 + universal_ble: a322ebabee64f0ec27a313e89a5dd6967f37a60f -PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694 +PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e COCOAPODS: 1.16.2 diff --git a/example/macos/Flutter/Flutter-Debug.xcconfig b/example/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b6..4b81f9b2 100644 --- a/example/macos/Flutter/Flutter-Debug.xcconfig +++ b/example/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Flutter/Flutter-Release.xcconfig b/example/macos/Flutter/Flutter-Release.xcconfig index c2efd0b6..5caa9d15 100644 --- a/example/macos/Flutter/Flutter-Release.xcconfig +++ b/example/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Podfile b/example/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/example/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end