Add error in connection updates (#89)

* Add error in connection updates

* implement windows

* Update changelog and Docs

* minor fix in connect()

* Add default timeout in connect

* Document new pair and connect API

* Fix Connect and Pair apis to throw proper errors and Improve logging

* remove import

* Rename PairingException and update Exception doc

* Update changelog

* Update comments

---------

Co-authored-by: Foti Dim <fdimanidis@gmail.com>
This commit is contained in:
Rohit Sangwan
2024-09-27 02:38:25 +05:30
committed by GitHub
parent f41aceaa0e
commit b77d0aaeb4
26 changed files with 851 additions and 698 deletions
+6 -3
View File
@@ -1,8 +1,11 @@
## 0.13.0 ## 0.13.0
* BREAKING CHANGE: `scanFilter` filters are now in OR relation * BREAKING CHANGE: `scanFilter` filters are now in OR relation
* BREAKING CHANGE: `manufacturerDataHead` is removed from `BleDevice` * BREAKING CHANGE: `manufacturerDataHead` is removed from `BleDevice`
* BREAKING CHANGE: rename `WebConfig` to `WebOptions` * BREAKING CHANGE: `WebConfig` is now `WebOptions`
* BREAKING CHANGE: rename `ManufacturerDataFilter.data` to `ManufacturerDataFilter.payload` * BREAKING CHANGE: `ManufacturerDataFilter.data` is now `ManufacturerDataFilter.payload`
* BREAKING CHANGE: `connect()` does not return a boolean anymore. It will throw error on connection failure
* BREAKING CHANGE: `pair()` does not return a boolean anymore. It will throw error on connection failure
* BREAKING CHANGE: `onConnectionChange` returns error as well
* BREAKING CHANGE: rename in-app pairing capabilities * BREAKING CHANGE: rename in-app pairing capabilities
* Deprecation: `manufacturerData` is deprecated in BleDevice and will be removed in the future * Deprecation: `manufacturerData` is deprecated in BleDevice and will be removed in the future
* Improve `scanFilter` handling * Improve `scanFilter` handling
@@ -11,6 +14,7 @@
* Auto convert all services passed to `getSystemDevices()` * Auto convert all services passed to `getSystemDevices()`
* Return false for receivesAdvertisements on Linux/Web * Return false for receivesAdvertisements on Linux/Web
* Add 1s delay in discoverServices on Linux * Add 1s delay in discoverServices on Linux
* Add `connectionStream` API to get connection updates as stream
## 0.12.0 ## 0.12.0
* BREAKING CHANGE: `unPair` is now `unpair` * BREAKING CHANGE: `unPair` is now `unpair`
@@ -20,7 +24,6 @@
* Add `PlatformConfig` property in `StartScan` * Add `PlatformConfig` property in `StartScan`
* Add `WebConfig` property in `PlatformConfig` * Add `WebConfig` property in `PlatformConfig`
* Fix notifications for characteristics without cccd on Android * Fix notifications for characteristics without cccd on Android
* Add `connectionStream` API to get connection updates as stream
* Promote Linux to stable * Promote Linux to stable
## 0.11.1 ## 0.11.1
+2 -2
View File
@@ -153,8 +153,8 @@ UniversalBle.connect(deviceId);
UniversalBle.disconnect(deviceId); UniversalBle.disconnect(deviceId);
// Get connection/disconnection updates // Get connection/disconnection updates
UniversalBle.onConnectionChange = (String deviceId, bool isConnected) { UniversalBle.onConnectionChange = (String deviceId, bool isConnected, String? error) {
debugPrint('OnConnectionChange $deviceId, $isConnected'); debugPrint('OnConnectionChange $deviceId, $isConnected Error: $error');
} }
// Get current connection state // Get current connection state
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v21.1.0), do not edit directly. // Autogenerated from Pigeon (v22.4.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -53,19 +53,18 @@ data class UniversalBleScanResult (
val name: String? = null, val name: String? = null,
val isPaired: Boolean? = null, val isPaired: Boolean? = null,
val rssi: Long? = null, val rssi: Long? = null,
val manufacturerDataList: List<UniversalManufacturerData?>? = null, val manufacturerDataList: List<UniversalManufacturerData>? = null,
val services: List<String?>? = null val services: List<String>? = null
)
) { {
companion object { companion object {
@Suppress("LocalVariableName") fun fromList(pigeonVar_list: List<Any?>): UniversalBleScanResult {
fun fromList(__pigeon_list: List<Any?>): UniversalBleScanResult { val deviceId = pigeonVar_list[0] as String
val deviceId = __pigeon_list[0] as String val name = pigeonVar_list[1] as String?
val name = __pigeon_list[1] as String? val isPaired = pigeonVar_list[2] as Boolean?
val isPaired = __pigeon_list[2] as Boolean? val rssi = pigeonVar_list[3] as Long?
val rssi = __pigeon_list[3].let { num -> if (num is Int) num.toLong() else num as Long? } val manufacturerDataList = pigeonVar_list[4] as List<UniversalManufacturerData>?
val manufacturerDataList = __pigeon_list[4] as List<UniversalManufacturerData?>? val services = pigeonVar_list[5] as List<String>?
val services = __pigeon_list[5] as List<String?>?
return UniversalBleScanResult(deviceId, name, isPaired, rssi, manufacturerDataList, services) return UniversalBleScanResult(deviceId, name, isPaired, rssi, manufacturerDataList, services)
} }
} }
@@ -84,14 +83,13 @@ data class UniversalBleScanResult (
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
data class UniversalBleService ( data class UniversalBleService (
val uuid: String, val uuid: String,
val characteristics: List<UniversalBleCharacteristic?>? = null val characteristics: List<UniversalBleCharacteristic>? = null
)
) { {
companion object { companion object {
@Suppress("LocalVariableName") fun fromList(pigeonVar_list: List<Any?>): UniversalBleService {
fun fromList(__pigeon_list: List<Any?>): UniversalBleService { val uuid = pigeonVar_list[0] as String
val uuid = __pigeon_list[0] as String val characteristics = pigeonVar_list[1] as List<UniversalBleCharacteristic>?
val characteristics = __pigeon_list[1] as List<UniversalBleCharacteristic?>?
return UniversalBleService(uuid, characteristics) return UniversalBleService(uuid, characteristics)
} }
} }
@@ -106,14 +104,13 @@ data class UniversalBleService (
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
data class UniversalBleCharacteristic ( data class UniversalBleCharacteristic (
val uuid: String, val uuid: String,
val properties: List<Long?> val properties: List<Long>
)
) { {
companion object { companion object {
@Suppress("LocalVariableName") fun fromList(pigeonVar_list: List<Any?>): UniversalBleCharacteristic {
fun fromList(__pigeon_list: List<Any?>): UniversalBleCharacteristic { val uuid = pigeonVar_list[0] as String
val uuid = __pigeon_list[0] as String val properties = pigeonVar_list[1] as List<Long>
val properties = __pigeon_list[1] as List<Long?>
return UniversalBleCharacteristic(uuid, properties) return UniversalBleCharacteristic(uuid, properties)
} }
} }
@@ -131,17 +128,16 @@ data class UniversalBleCharacteristic (
* Generated class from Pigeon that represents data sent in messages. * Generated class from Pigeon that represents data sent in messages.
*/ */
data class UniversalScanFilter ( data class UniversalScanFilter (
val withServices: List<String?>, val withServices: List<String>,
val withNamePrefix: List<String?>, val withNamePrefix: List<String>,
val withManufacturerData: List<UniversalManufacturerDataFilter?> val withManufacturerData: List<UniversalManufacturerDataFilter>
)
) { {
companion object { companion object {
@Suppress("LocalVariableName") fun fromList(pigeonVar_list: List<Any?>): UniversalScanFilter {
fun fromList(__pigeon_list: List<Any?>): UniversalScanFilter { val withServices = pigeonVar_list[0] as List<String>
val withServices = __pigeon_list[0] as List<String?> val withNamePrefix = pigeonVar_list[1] as List<String>
val withNamePrefix = __pigeon_list[1] as List<String?> val withManufacturerData = pigeonVar_list[2] as List<UniversalManufacturerDataFilter>
val withManufacturerData = __pigeon_list[2] as List<UniversalManufacturerDataFilter?>
return UniversalScanFilter(withServices, withNamePrefix, withManufacturerData) return UniversalScanFilter(withServices, withNamePrefix, withManufacturerData)
} }
} }
@@ -159,14 +155,13 @@ data class UniversalManufacturerDataFilter (
val companyIdentifier: Long, val companyIdentifier: Long,
val data: ByteArray? = null, val data: ByteArray? = null,
val mask: ByteArray? = null val mask: ByteArray? = null
)
) { {
companion object { companion object {
@Suppress("LocalVariableName") fun fromList(pigeonVar_list: List<Any?>): UniversalManufacturerDataFilter {
fun fromList(__pigeon_list: List<Any?>): UniversalManufacturerDataFilter { val companyIdentifier = pigeonVar_list[0] as Long
val companyIdentifier = __pigeon_list[0].let { num -> if (num is Int) num.toLong() else num as Long } val data = pigeonVar_list[1] as ByteArray?
val data = __pigeon_list[1] as ByteArray? val mask = pigeonVar_list[2] as ByteArray?
val mask = __pigeon_list[2] as ByteArray?
return UniversalManufacturerDataFilter(companyIdentifier, data, mask) return UniversalManufacturerDataFilter(companyIdentifier, data, mask)
} }
} }
@@ -183,13 +178,12 @@ data class UniversalManufacturerDataFilter (
data class UniversalManufacturerData ( data class UniversalManufacturerData (
val companyIdentifier: Long, val companyIdentifier: Long,
val data: ByteArray val data: ByteArray
)
) { {
companion object { companion object {
@Suppress("LocalVariableName") fun fromList(pigeonVar_list: List<Any?>): UniversalManufacturerData {
fun fromList(__pigeon_list: List<Any?>): UniversalManufacturerData { val companyIdentifier = pigeonVar_list[0] as Long
val companyIdentifier = __pigeon_list[0].let { num -> if (num is Int) num.toLong() else num as Long } val data = pigeonVar_list[1] as ByteArray
val data = __pigeon_list[1] as ByteArray
return UniversalManufacturerData(companyIdentifier, data) return UniversalManufacturerData(companyIdentifier, data)
} }
} }
@@ -200,7 +194,7 @@ data class UniversalManufacturerData (
) )
} }
} }
private object UniversalBlePigeonCodec : StandardMessageCodec() { private open class UniversalBlePigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) { return when (type) {
129.toByte() -> { 129.toByte() -> {
@@ -294,7 +288,7 @@ interface UniversalBlePlatformChannel {
companion object { companion object {
/** The codec used by UniversalBlePlatformChannel. */ /** The codec used by UniversalBlePlatformChannel. */
val codec: MessageCodec<Any?> by lazy { val codec: MessageCodec<Any?> by lazy {
UniversalBlePigeonCodec UniversalBlePigeonCodec()
} }
/** Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binaryMessenger`. */ /** Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binaryMessenger`. */
@JvmOverloads @JvmOverloads
@@ -414,7 +408,7 @@ interface UniversalBlePlatformChannel {
val deviceIdArg = args[0] as String val deviceIdArg = args[0] as String
val serviceArg = args[1] as String val serviceArg = args[1] as String
val characteristicArg = args[2] as String val characteristicArg = args[2] as String
val bleInputPropertyArg = args[3].let { num -> if (num is Int) num.toLong() else num as Long } val bleInputPropertyArg = args[3] as Long
api.setNotifiable(deviceIdArg, serviceArg, characteristicArg, bleInputPropertyArg) { result: Result<Unit> -> api.setNotifiable(deviceIdArg, serviceArg, characteristicArg, bleInputPropertyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
@@ -476,7 +470,7 @@ interface UniversalBlePlatformChannel {
channel.setMessageHandler { message, reply -> channel.setMessageHandler { message, reply ->
val args = message as List<Any?> val args = message as List<Any?>
val deviceIdArg = args[0] as String val deviceIdArg = args[0] as String
val expectedMtuArg = args[1].let { num -> if (num is Int) num.toLong() else num as Long } val expectedMtuArg = args[1] as Long
api.requestMtu(deviceIdArg, expectedMtuArg) { result: Result<Long> -> api.requestMtu(deviceIdArg, expectedMtuArg) { result: Result<Long> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
@@ -500,7 +494,7 @@ interface UniversalBlePlatformChannel {
val serviceArg = args[1] as String val serviceArg = args[1] as String
val characteristicArg = args[2] as String val characteristicArg = args[2] as String
val valueArg = args[3] as ByteArray val valueArg = args[3] as ByteArray
val bleOutputPropertyArg = args[4].let { num -> if (num is Int) num.toLong() else num as Long } val bleOutputPropertyArg = args[4] as Long
api.writeValue(deviceIdArg, serviceArg, characteristicArg, valueArg, bleOutputPropertyArg) { result: Result<Unit> -> api.writeValue(deviceIdArg, serviceArg, characteristicArg, valueArg, bleOutputPropertyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull() val error = result.exceptionOrNull()
if (error != null) { if (error != null) {
@@ -621,7 +615,7 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
companion object { companion object {
/** The codec used by UniversalBleCallbackChannel. */ /** The codec used by UniversalBleCallbackChannel. */
val codec: MessageCodec<Any?> by lazy { val codec: MessageCodec<Any?> by lazy {
UniversalBlePigeonCodec UniversalBlePigeonCodec()
} }
} }
fun onAvailabilityChanged(stateArg: Long, callback: (Result<Unit>) -> Unit) fun onAvailabilityChanged(stateArg: Long, callback: (Result<Unit>) -> Unit)
@@ -692,12 +686,12 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger,
} }
} }
} }
fun onConnectionChanged(deviceIdArg: String, connectedArg: Boolean, callback: (Result<Unit>) -> Unit) fun onConnectionChanged(deviceIdArg: String, connectedArg: Boolean, errorArg: String?, callback: (Result<Unit>) -> Unit)
{ {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$separatedMessageChannelSuffix" val channelName = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec) val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(deviceIdArg, connectedArg)) { channel.send(listOf(deviceIdArg, connectedArg, errorArg)) {
if (it is List<*>) { if (it is List<*>) {
if (it.size > 1) { if (it.size > 1) {
callback(Result.failure(FlutterError(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?)))
@@ -245,6 +245,82 @@ val DeviceDisconnectedError: FlutterError = FlutterError(
null null
) )
fun Int.parseHciErrorCode(): String? {
return when (this) {
BluetoothGatt.GATT_SUCCESS -> null
0x01 -> "Unknown HCI Command"
0x02 -> "Unknown Connection Identifier"
0x03 -> "Hardware Failure"
0x04 -> "Page Timeout"
0x05 -> "Authentication Failure"
0x06 -> "PIN or Key Missing"
0x07 -> "Memory Capacity Exceeded"
0x08 -> "Connection Timeout"
0x09 -> "Connection Limit Exceeded"
0x0A -> "Synchronous Connection Limit To A Device Exceeded"
0x0B -> "Connection Already Exists"
0x0C -> "Command Disallowed"
0x0D -> "Connection Rejected due to Limited Resources"
0x0E -> "Connection Rejected Due To Security Reasons"
0x0F -> "Connection Rejected due to Unacceptable BD_ADDR"
0x10 -> "Connection Accept Timeout Exceeded"
0x11 -> "Unsupported Feature or Parameter Value"
0x12 -> "Invalid HCI Command Parameters"
0x13 -> "Remote User Terminated Connection"
0x14 -> "Remote Device Terminated Connection due to Low Resources"
0x15 -> "Remote Device Terminated Connection due to Power Off"
0x16 -> "Connection Terminated By Local Host"
0x17 -> "Repeated Attempts"
0x18 -> "Pairing Not Allowed"
0x19 -> "Unknown LMP PDU"
0x1A -> "Unsupported Remote Feature / Unsupported LMP Feature"
0x1B -> "SCO Offset Rejected"
0x1C -> "SCO Interval Rejected"
0x1D -> "SCO Air Mode Rejected"
0x1E -> "Invalid LMP Parameters / Invalid LL Parameters"
0x1F -> "Unspecified Error"
0x20 -> "Unsupported LMP Parameter Value / Unsupported LL Parameter Value"
0x21 -> "Role Change Not Allowed"
0x22 -> "LMP Response Timeout / LL Response Timeout"
0x23 -> "LMP Error Transaction Collision / LL Procedure Collision"
0x24 -> "LMP PDU Not Allowed"
0x25 -> "Encryption Mode Not Acceptable"
0x26 -> "Link Key cannot be Changed"
0x27 -> "Requested QoS Not Supported"
0x28 -> "Instant Passed"
0x29 -> "Pairing With Unit Key Not Supported"
0x2A -> "Different Transaction Collision"
0x2B -> "Reserved for future use"
0x2C -> "QoS Unacceptable Parameter"
0x2D -> "QoS Rejected"
0x2E -> "Channel Classification Not Supported"
0x2F -> "Insufficient Security"
0x30 -> "Parameter Out Of Mandatory Range"
0x31 -> "Reserved for future use"
0x32 -> "Role Switch Pending"
0x33 -> "Reserved for future use"
0x34 -> "Reserved Slot Violation"
0x35 -> "Role Switch Failed"
0x36 -> "Extended Inquiry Response Too Large"
0x37 -> "Secure Simple Pairing Not Supported By Host"
0x38 -> "Host Busy - Pairing"
0x39 -> "Connection Rejected due to No Suitable Channel Found"
0x3A -> "Controller Busy"
0x3B -> "Unacceptable Connection Parameters"
0x3C -> "Advertising Timeout"
0x3D -> "Connection Terminated due to MIC Failure"
0x3E -> "Connection Failed to be Established / Synchronization Timeout"
0x3F -> "MAC Connection Failed"
0x40 -> "Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock Dragging"
0x41 -> "Type0 Submap Not Defined"
0x42 -> "Unknown Advertising Identifier"
0x43 -> "Limit Reached"
0x44 -> "Operation Cancelled by Host"
0x45 -> "Packet Too Long"
else -> "Unknown Error $this"
}
}
// Future result classes // Future result classes
class DiscoverServicesFuture( class DiscoverServicesFuture(
val deviceId: String, val deviceId: String,
@@ -162,7 +162,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
if (currentState == BluetoothGatt.STATE_CONNECTED) { if (currentState == BluetoothGatt.STATE_CONNECTED) {
Log.e(TAG, "$deviceId Already connected") Log.e(TAG, "$deviceId Already connected")
mainThreadHandler?.post { mainThreadHandler?.post {
callbackChannel?.onConnectionChanged(deviceId, true) {} callbackChannel?.onConnectionChanged(deviceId, true, null) {}
} }
return return
} else if (currentState == BluetoothGatt.STATE_CONNECTING) { } else if (currentState == BluetoothGatt.STATE_CONNECTING) {
@@ -864,19 +864,22 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
devicesStateMap[gatt.device.address] = newState devicesStateMap[gatt.device.address] = newState
Log.d(TAG, "onConnectionStateChange-> Status: ${status}, NewState: $newState") Log.d(
TAG,
"onConnectionStateChange-> Status: $status ${status.parseHciErrorCode()}, NewState: $newState"
)
if (newState == BluetoothGatt.STATE_CONNECTED) { if (newState == BluetoothGatt.STATE_CONNECTED) {
mainThreadHandler?.post { mainThreadHandler?.post {
callbackChannel?.onConnectionChanged( callbackChannel?.onConnectionChanged(
gatt.device.address, true gatt.device.address, true, status.parseHciErrorCode()
) {} ) {}
} }
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) { } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
cleanConnection(gatt) cleanConnection(gatt)
mainThreadHandler?.post { mainThreadHandler?.post {
callbackChannel?.onConnectionChanged( callbackChannel?.onConnectionChanged(
gatt.device.address, false gatt.device.address, false, status.parseHciErrorCode()
) {} ) {}
} }
} }
+51 -38
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v21.1.0), do not edit directly. // Autogenerated from Pigeon (v22.4.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
import Foundation import Foundation
@@ -74,17 +74,19 @@ struct UniversalBleScanResult {
var name: String? = nil var name: String? = nil
var isPaired: Bool? = nil var isPaired: Bool? = nil
var rssi: Int64? = nil var rssi: Int64? = nil
var manufacturerDataList: [UniversalManufacturerData?]? = nil var manufacturerDataList: [UniversalManufacturerData]? = nil
var services: [String?]? = nil var services: [String]? = nil
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ __pigeon_list: [Any?]) -> UniversalBleScanResult? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleScanResult? {
let deviceId = __pigeon_list[0] as! String let deviceId = pigeonVar_list[0] as! String
let name: String? = nilOrValue(__pigeon_list[1]) let name: String? = nilOrValue(pigeonVar_list[1])
let isPaired: Bool? = nilOrValue(__pigeon_list[2]) let isPaired: Bool? = nilOrValue(pigeonVar_list[2])
let rssi: Int64? = isNullish(__pigeon_list[3]) ? nil : (__pigeon_list[3] is Int64? ? __pigeon_list[3] as! Int64? : Int64(__pigeon_list[3] as! Int32)) let rssi: Int64? = nilOrValue(pigeonVar_list[3])
let manufacturerDataList: [UniversalManufacturerData?]? = nilOrValue(__pigeon_list[4]) let manufacturerDataList: [UniversalManufacturerData]? = nilOrValue(pigeonVar_list[4])
let services: [String?]? = nilOrValue(__pigeon_list[5]) let services: [String]? = nilOrValue(pigeonVar_list[5])
return UniversalBleScanResult( return UniversalBleScanResult(
deviceId: deviceId, deviceId: deviceId,
@@ -110,12 +112,14 @@ struct UniversalBleScanResult {
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalBleService { struct UniversalBleService {
var uuid: String var uuid: String
var characteristics: [UniversalBleCharacteristic?]? = nil var characteristics: [UniversalBleCharacteristic]? = nil
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ __pigeon_list: [Any?]) -> UniversalBleService? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleService? {
let uuid = __pigeon_list[0] as! String let uuid = pigeonVar_list[0] as! String
let characteristics: [UniversalBleCharacteristic?]? = nilOrValue(__pigeon_list[1]) let characteristics: [UniversalBleCharacteristic]? = nilOrValue(pigeonVar_list[1])
return UniversalBleService( return UniversalBleService(
uuid: uuid, uuid: uuid,
@@ -133,12 +137,14 @@ struct UniversalBleService {
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalBleCharacteristic { struct UniversalBleCharacteristic {
var uuid: String var uuid: String
var properties: [Int64?] var properties: [Int64]
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ __pigeon_list: [Any?]) -> UniversalBleCharacteristic? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalBleCharacteristic? {
let uuid = __pigeon_list[0] as! String let uuid = pigeonVar_list[0] as! String
let properties = __pigeon_list[1] as! [Int64?] let properties = pigeonVar_list[1] as! [Int64]
return UniversalBleCharacteristic( return UniversalBleCharacteristic(
uuid: uuid, uuid: uuid,
@@ -157,15 +163,17 @@ struct UniversalBleCharacteristic {
/// ///
/// Generated class from Pigeon that represents data sent in messages. /// Generated class from Pigeon that represents data sent in messages.
struct UniversalScanFilter { struct UniversalScanFilter {
var withServices: [String?] var withServices: [String]
var withNamePrefix: [String?] var withNamePrefix: [String]
var withManufacturerData: [UniversalManufacturerDataFilter?] var withManufacturerData: [UniversalManufacturerDataFilter]
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ __pigeon_list: [Any?]) -> UniversalScanFilter? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalScanFilter? {
let withServices = __pigeon_list[0] as! [String?] let withServices = pigeonVar_list[0] as! [String]
let withNamePrefix = __pigeon_list[1] as! [String?] let withNamePrefix = pigeonVar_list[1] as! [String]
let withManufacturerData = __pigeon_list[2] as! [UniversalManufacturerDataFilter?] let withManufacturerData = pigeonVar_list[2] as! [UniversalManufacturerDataFilter]
return UniversalScanFilter( return UniversalScanFilter(
withServices: withServices, withServices: withServices,
@@ -188,11 +196,13 @@ struct UniversalManufacturerDataFilter {
var data: FlutterStandardTypedData? = nil var data: FlutterStandardTypedData? = nil
var mask: FlutterStandardTypedData? = nil var mask: FlutterStandardTypedData? = nil
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ __pigeon_list: [Any?]) -> UniversalManufacturerDataFilter? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerDataFilter? {
let companyIdentifier = __pigeon_list[0] is Int64 ? __pigeon_list[0] as! Int64 : Int64(__pigeon_list[0] as! Int32) let companyIdentifier = pigeonVar_list[0] as! Int64
let data: FlutterStandardTypedData? = nilOrValue(__pigeon_list[1]) let data: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[1])
let mask: FlutterStandardTypedData? = nilOrValue(__pigeon_list[2]) let mask: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[2])
return UniversalManufacturerDataFilter( return UniversalManufacturerDataFilter(
companyIdentifier: companyIdentifier, companyIdentifier: companyIdentifier,
@@ -214,10 +224,12 @@ struct UniversalManufacturerData {
var companyIdentifier: Int64 var companyIdentifier: Int64
var data: FlutterStandardTypedData var data: FlutterStandardTypedData
// swift-format-ignore: AlwaysUseLowerCamelCase // swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ __pigeon_list: [Any?]) -> UniversalManufacturerData? { static func fromList(_ pigeonVar_list: [Any?]) -> UniversalManufacturerData? {
let companyIdentifier = __pigeon_list[0] is Int64 ? __pigeon_list[0] as! Int64 : Int64(__pigeon_list[0] as! Int32) let companyIdentifier = pigeonVar_list[0] as! Int64
let data = __pigeon_list[1] as! FlutterStandardTypedData let data = pigeonVar_list[1] as! FlutterStandardTypedData
return UniversalManufacturerData( return UniversalManufacturerData(
companyIdentifier: companyIdentifier, companyIdentifier: companyIdentifier,
@@ -231,6 +243,7 @@ struct UniversalManufacturerData {
] ]
} }
} }
private class UniversalBlePigeonCodecReader: FlutterStandardReader { private class UniversalBlePigeonCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? { override func readValue(ofType type: UInt8) -> Any? {
switch type { switch type {
@@ -416,7 +429,7 @@ class UniversalBlePlatformChannelSetup {
let deviceIdArg = args[0] as! String let deviceIdArg = args[0] as! String
let serviceArg = args[1] as! String let serviceArg = args[1] as! String
let characteristicArg = args[2] as! String let characteristicArg = args[2] as! String
let bleInputPropertyArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) let bleInputPropertyArg = args[3] as! Int64
api.setNotifiable(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg, bleInputProperty: bleInputPropertyArg) { result in api.setNotifiable(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg, bleInputProperty: bleInputPropertyArg) { result in
switch result { switch result {
case .success: case .success:
@@ -470,7 +483,7 @@ class UniversalBlePlatformChannelSetup {
requestMtuChannel.setMessageHandler { message, reply in requestMtuChannel.setMessageHandler { message, reply in
let args = message as! [Any?] let args = message as! [Any?]
let deviceIdArg = args[0] as! String let deviceIdArg = args[0] as! String
let expectedMtuArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) let expectedMtuArg = args[1] as! Int64
api.requestMtu(deviceId: deviceIdArg, expectedMtu: expectedMtuArg) { result in api.requestMtu(deviceId: deviceIdArg, expectedMtu: expectedMtuArg) { result in
switch result { switch result {
case .success(let res): case .success(let res):
@@ -491,7 +504,7 @@ class UniversalBlePlatformChannelSetup {
let serviceArg = args[1] as! String let serviceArg = args[1] as! String
let characteristicArg = args[2] as! String let characteristicArg = args[2] as! String
let valueArg = args[3] as! FlutterStandardTypedData let valueArg = args[3] as! FlutterStandardTypedData
let bleOutputPropertyArg = args[4] is Int64 ? args[4] as! Int64 : Int64(args[4] as! Int32) let bleOutputPropertyArg = args[4] as! Int64
api.writeValue(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg, value: valueArg, bleOutputProperty: bleOutputPropertyArg) { result in api.writeValue(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg, value: valueArg, bleOutputProperty: bleOutputPropertyArg) { result in
switch result { switch result {
case .success: case .success:
@@ -595,7 +608,7 @@ protocol UniversalBleCallbackChannelProtocol {
func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result<Void, PigeonError>) -> Void) func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result<Void, PigeonError>) -> Void)
func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result<Void, PigeonError>) -> Void) func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result<Void, PigeonError>) -> Void)
func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result<Void, PigeonError>) -> Void) func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result<Void, PigeonError>) -> Void)
func onConnectionChanged(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result<Void, PigeonError>) -> Void) func onConnectionChanged(deviceId deviceIdArg: String, connected connectedArg: Bool, error errorArg: String?, completion: @escaping (Result<Void, PigeonError>) -> Void)
} }
class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol { class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
private let binaryMessenger: FlutterBinaryMessenger private let binaryMessenger: FlutterBinaryMessenger
@@ -679,10 +692,10 @@ class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol {
} }
} }
} }
func onConnectionChanged(deviceId deviceIdArg: String, connected connectedArg: Bool, completion: @escaping (Result<Void, PigeonError>) -> Void) { func onConnectionChanged(deviceId deviceIdArg: String, connected connectedArg: Bool, error errorArg: String?, completion: @escaping (Result<Void, PigeonError>) -> Void) {
let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged\(messageChannelSuffix)" let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged\(messageChannelSuffix)"
let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec)
channel.sendMessage([deviceIdArg, connectedArg] as [Any?]) { response in channel.sendMessage([deviceIdArg, connectedArg, errorArg] as [Any?]) { response in
guard let listResponse = response as? [Any?] else { guard let listResponse = response as? [Any?] else {
completion(.failure(createConnectionError(withChannelName: channelName))) completion(.failure(createConnectionError(withChannelName: channelName)))
return return
+2 -2
View File
@@ -104,11 +104,11 @@ extension CBManagerState {
} }
extension Error { extension Error {
func toFlutterError() -> FlutterError { func toPigeonError() -> PigeonError {
let nsError = self as NSError let nsError = self as NSError
let errorCode: String = .init(nsError.code) let errorCode: String = .init(nsError.code)
let errorDescription: String = nsError.localizedDescription let errorDescription: String = nsError.localizedDescription
return FlutterError(code: errorCode, message: errorDescription, details: nil) return PigeonError(code: errorCode, message: errorDescription, details: nil)
} }
} }
+34 -36
View File
@@ -55,7 +55,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
} }
func enableBluetooth(completion: @escaping (Result<Bool, Error>) -> Void) { func enableBluetooth(completion: @escaping (Result<Bool, Error>) -> Void) {
completion(Result.failure(FlutterError(code: "NotSupported", message: nil, details: nil))) completion(Result.failure(PigeonError(code: "NotSupported", message: nil, details: nil)))
} }
func startScan(filter: UniversalScanFilter?) throws { func startScan(filter: UniversalScanFilter?) throws {
@@ -117,7 +117,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
characteristicReadFutures.removeAll { future in characteristicReadFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(FlutterError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
) )
return true return true
} }
@@ -126,7 +126,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
characteristicWriteFutures.removeAll { future in characteristicWriteFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(FlutterError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
) )
return true return true
} }
@@ -135,7 +135,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
characteristicNotifyFutures.removeAll { future in characteristicNotifyFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(FlutterError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
) )
return true return true
} }
@@ -144,7 +144,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
discoverServicesFutures.removeAll { future in discoverServicesFutures.removeAll { future in
if future.deviceId == deviceId { if future.deviceId == deviceId {
future.result( future.result(
Result.failure(FlutterError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil)) Result.failure(PigeonError(code: "DeviceDisconnected", message: "Device Disconnected", details: nil))
) )
return true return true
} }
@@ -156,7 +156,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func discoverServices(deviceId: String, completion: @escaping (Result<[UniversalBleService], Error>) -> Void) { func discoverServices(deviceId: String, completion: @escaping (Result<[UniversalBleService], Error>) -> Void) {
guard let peripheral = discoveredPeripherals[deviceId] else { guard let peripheral = discoveredPeripherals[deviceId] else {
completion( completion(
Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)) Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))
) )
return return
} }
@@ -193,22 +193,22 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func setNotifiable(deviceId: String, service: String, characteristic: String, bleInputProperty: Int64, completion: @escaping (Result<Void, any Error>) -> Void) { func setNotifiable(deviceId: String, service: String, characteristic: String, bleInputProperty: Int64, completion: @escaping (Result<Void, any Error>) -> Void) {
guard let peripheral = discoveredPeripherals[deviceId] else { guard let peripheral = discoveredPeripherals[deviceId] else {
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
return return
} }
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else { guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil))) completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil)))
return return
} }
if bleInputProperty == BleInputProperty.notification.rawValue && !gattCharacteristic.properties.contains(.notify) { if bleInputProperty == BleInputProperty.notification.rawValue && !gattCharacteristic.properties.contains(.notify) {
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support notify", details: nil))) completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support notify", details: nil)))
return return
} }
if bleInputProperty == BleInputProperty.indication.rawValue && !gattCharacteristic.properties.contains(.indicate) { if bleInputProperty == BleInputProperty.indication.rawValue && !gattCharacteristic.properties.contains(.indicate) {
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support indicate", details: nil))) completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support indicate", details: nil)))
return return
} }
@@ -219,15 +219,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func readValue(deviceId: String, service: String, characteristic: String, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) { func readValue(deviceId: String, service: String, characteristic: String, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
guard let peripheral = discoveredPeripherals[deviceId] else { guard let peripheral = discoveredPeripherals[deviceId] else {
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
return return
} }
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else { guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil))) completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil)))
return return
} }
if !gattCharacteristic.properties.contains(.read) { if !gattCharacteristic.properties.contains(.read) {
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support read", details: nil))) completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support read", details: nil)))
return return
} }
peripheral.readValue(for: gattCharacteristic) peripheral.readValue(for: gattCharacteristic)
@@ -236,11 +236,11 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func writeValue(deviceId: String, service: String, characteristic: String, value: FlutterStandardTypedData, bleOutputProperty: Int64, completion: @escaping (Result<Void, Error>) -> Void) { func writeValue(deviceId: String, service: String, characteristic: String, value: FlutterStandardTypedData, bleOutputProperty: Int64, completion: @escaping (Result<Void, Error>) -> Void) {
guard let peripheral = discoveredPeripherals[deviceId] else { guard let peripheral = discoveredPeripherals[deviceId] else {
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
return return
} }
guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else { guard let gattCharacteristic = peripheral.getCharacteristic(characteristic, of: service) else {
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil))) completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown characteristic:\(characteristic)", details: nil)))
return return
} }
@@ -248,12 +248,12 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
if type == CBCharacteristicWriteType.withResponse { if type == CBCharacteristicWriteType.withResponse {
if !gattCharacteristic.properties.contains(.write) { if !gattCharacteristic.properties.contains(.write) {
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support write withResponse", details: nil))) completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support write withResponse", details: nil)))
return return
} }
} else if type == CBCharacteristicWriteType.withoutResponse { } else if type == CBCharacteristicWriteType.withoutResponse {
if !gattCharacteristic.properties.contains(.writeWithoutResponse) { if !gattCharacteristic.properties.contains(.writeWithoutResponse) {
completion(Result.failure(FlutterError(code: "InvalidAction", message: "Characteristic does not support write withoutResponse", details: nil))) completion(Result.failure(PigeonError(code: "InvalidAction", message: "Characteristic does not support write withoutResponse", details: nil)))
return return
} }
} }
@@ -269,7 +269,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
func requestMtu(deviceId: String, expectedMtu _: Int64, completion: @escaping (Result<Int64, Error>) -> Void) { func requestMtu(deviceId: String, expectedMtu _: Int64, completion: @escaping (Result<Int64, Error>) -> Void) {
guard let peripheral = discoveredPeripherals[deviceId] else { guard let peripheral = discoveredPeripherals[deviceId] else {
completion(Result.failure(FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil))) completion(Result.failure(PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)))
return return
} }
let mtu = peripheral.maximumWriteValueLength(for: CBCharacteristicWriteType.withoutResponse) let mtu = peripheral.maximumWriteValueLength(for: CBCharacteristicWriteType.withoutResponse)
@@ -279,15 +279,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
} }
func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) { func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
completion(Result.failure(FlutterError(code: "NotSupported", message: nil, details: nil))) completion(Result.failure(PigeonError(code: "NotSupported", message: nil, details: nil)))
} }
func pair(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) { func pair(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
completion(Result.failure(FlutterError(code: "Implemented in Dart", message: nil, details: nil))) completion(Result.failure(PigeonError(code: "Implemented in Dart", message: nil, details: nil)))
} }
func unPair(deviceId _: String) throws { func unPair(deviceId _: String) throws {
throw FlutterError(code: "NotSupported", message: nil, details: nil) throw PigeonError(code: "NotSupported", message: nil, details: nil)
} }
func getSystemDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void) { func getSystemDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void) {
@@ -345,17 +345,17 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
} }
public func centralManager(_: CBCentralManager, didConnect peripheral: CBPeripheral) { public func centralManager(_: CBCentralManager, didConnect peripheral: CBPeripheral) {
callbackChannel.onConnectionChanged(deviceId: peripheral.uuid.uuidString, connected: true) { _ in } callbackChannel.onConnectionChanged(deviceId: peripheral.uuid.uuidString, connected: true, error: nil) { _ in }
} }
public func centralManager(_: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error _: Error?) { public func centralManager(_: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error _: Error?) {
callbackChannel.onConnectionChanged(deviceId: peripheral.uuid.uuidString, connected: false) { _ in } callbackChannel.onConnectionChanged(deviceId: peripheral.uuid.uuidString, connected: false, error: nil) { _ in }
// Cleanup on disconnect
cleanUpConnection(deviceId: peripheral.uuid.uuidString) cleanUpConnection(deviceId: peripheral.uuid.uuidString)
} }
public func centralManager(_: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { public func centralManager(_: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("Failed to connect: \(peripheral.uuid.uuidString): \(String(describing: error))") callbackChannel.onConnectionChanged(deviceId: peripheral.uuid.uuidString, connected: false, error: error?.localizedDescription) { _ in }
cleanUpConnection(deviceId: peripheral.uuid.uuidString)
} }
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices _: Error?) { public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices _: Error?) {
@@ -397,8 +397,8 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
characteristicWriteFutures.removeAll { future in characteristicWriteFutures.removeAll { future in
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr { if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
if let flutterError = error?.toFlutterError() { if let pigeonError = error?.toPigeonError() {
future.result(Result.failure(flutterError)) future.result(Result.failure(pigeonError))
} else { } else {
future.result(Result.success({}())) future.result(Result.success({}()))
} }
@@ -411,8 +411,8 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
characteristicNotifyFutures.removeAll { future in characteristicNotifyFutures.removeAll { future in
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr { if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
if let flutterError = error?.toFlutterError() { if let pigeonError = error?.toPigeonError() {
future.result(Result.failure(flutterError)) future.result(Result.failure(pigeonError))
} else { } else {
future.result(Result.success({}())) future.result(Result.success({}()))
} }
@@ -437,13 +437,13 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
// Update futures for readValue // Update futures for readValue
characteristicReadFutures.removeAll { future in characteristicReadFutures.removeAll { future in
if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr { if future.deviceId == peripheral.uuid.uuidString && future.characteristicId == characteristic.uuid.uuidStr && future.serviceId == characteristic.service?.uuid.uuidStr {
if let flutterError = error?.toFlutterError() { if let pigeonError = error?.toPigeonError() {
future.result(Result.failure(flutterError)) future.result(Result.failure(pigeonError))
} else { } else {
if let characteristicValue = characteristic.value { if let characteristicValue = characteristic.value {
future.result(Result.success(FlutterStandardTypedData(bytes: characteristicValue))) future.result(Result.success(FlutterStandardTypedData(bytes: characteristicValue)))
} else { } else {
future.result(Result.failure(FlutterError(code: "ReadFailed", message: "No value", details: nil))) future.result(Result.failure(PigeonError(code: "ReadFailed", message: "No value", details: nil)))
} }
} }
return true return true
@@ -456,7 +456,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
extension String { extension String {
func getPeripheral() throws -> CBPeripheral { func getPeripheral() throws -> CBPeripheral {
guard let peripheral = discoveredPeripherals[self] else { guard let peripheral = discoveredPeripherals[self] else {
throw FlutterError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil) throw PigeonError(code: "IllegalArgument", message: "Unknown deviceId:\(self)", details: nil)
} }
return peripheral return peripheral
} }
@@ -466,11 +466,9 @@ extension [String] {
func toCBUUID() throws -> [CBUUID] { func toCBUUID() throws -> [CBUUID] {
return try compactMap { serviceUUID in return try compactMap { serviceUUID in
guard UUID(uuidString: serviceUUID.validFullUUID) != nil else { guard UUID(uuidString: serviceUUID.validFullUUID) != nil else {
throw FlutterError(code: "IllegalArgument", message: "Invalid service UUID:\(serviceUUID)", details: nil) throw PigeonError(code: "IllegalArgument", message: "Invalid service UUID:\(serviceUUID)", details: nil)
} }
return CBUUID(string: serviceUUID) return CBUUID(string: serviceUUID)
} }
} }
} }
extension FlutterError: Error {}
@@ -59,8 +59,14 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
}); });
} }
void _handleConnectionChange(String deviceId, bool isConnected) { void _handleConnectionChange(
print('_handleConnectionChange $deviceId, $isConnected'); String deviceId,
bool isConnected,
String? error,
) {
print(
'_handleConnectionChange $deviceId, $isConnected ${error != null ? 'Error: $error' : ''}',
);
setState(() { setState(() {
if (deviceId == widget.deviceId) { if (deviceId == widget.deviceId) {
this.isConnected = isConnected; this.isConnected = isConnected;
@@ -248,12 +254,12 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
enabled: !isConnected, enabled: !isConnected,
onPressed: () async { onPressed: () async {
try { try {
bool connected = await UniversalBle.connect( await UniversalBle.connect(
widget.deviceId, widget.deviceId,
); );
_addLog("ConnectionResult", connected); _addLog("ConnectionResult", true);
} catch (e) { } catch (e) {
_addLog('ConnectError', e); _addLog('ConnectError (${e.runtimeType})', e);
} }
}, },
), ),
@@ -405,14 +411,18 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
PlatformButton( PlatformButton(
enabled: BleCapabilities.supportsAllPairingKinds, enabled: BleCapabilities.supportsAllPairingKinds,
onPressed: () async { onPressed: () async {
bool? pairingResult = await UniversalBle.pair( try {
widget.deviceId, await UniversalBle.pair(
// pairingCommand: BleCommand( widget.deviceId,
// service: "", // pairingCommand: BleCommand(
// characteristic: "", // service: "",
// ), // characteristic: "",
); // ),
_addLog("Pairing Result", pairingResult); );
_addLog("Pairing Result", true);
} catch (e) {
_addLog('PairError (${e.runtimeType})', e);
}
}, },
text: 'Pair', text: 'Pair',
), ),
@@ -0,0 +1,9 @@
class BleConnectionUpdate {
final bool isConnected;
final String? error;
BleConnectionUpdate({
required this.isConnected,
this.error,
});
}
+13
View File
@@ -7,6 +7,11 @@ class BleService {
BleService(String uuid, this.characteristics) { BleService(String uuid, this.characteristics) {
this.uuid = BleUuidParser.string(uuid); this.uuid = BleUuidParser.string(uuid);
} }
@override
String toString() {
return 'BleService{uuid: $uuid, characteristics: $characteristics}';
}
} }
class BleCharacteristic { class BleCharacteristic {
@@ -16,6 +21,11 @@ class BleCharacteristic {
BleCharacteristic(String uuid, this.properties) { BleCharacteristic(String uuid, this.properties) {
this.uuid = BleUuidParser.string(uuid); this.uuid = BleUuidParser.string(uuid);
} }
@override
String toString() {
return 'BleCharacteristic{uuid: $uuid, properties: $properties}';
}
} }
enum CharacteristicProperty { enum CharacteristicProperty {
@@ -32,4 +42,7 @@ enum CharacteristicProperty {
factory CharacteristicProperty.parse(int index) => factory CharacteristicProperty.parse(int index) =>
CharacteristicProperty.values[index]; CharacteristicProperty.values[index];
@override
String toString() => name;
} }
+1
View File
@@ -1,3 +1,4 @@
export 'package:universal_ble/src/models/ble_connection_update.dart';
export 'package:universal_ble/src/models/manufacturer_data.dart'; export 'package:universal_ble/src/models/manufacturer_data.dart';
export 'package:universal_ble/src/models/platform_config.dart'; export 'package:universal_ble/src/models/platform_config.dart';
export 'package:universal_ble/src/models/queue_type.dart'; export 'package:universal_ble/src/models/queue_type.dart';
+114 -75
View File
@@ -5,6 +5,7 @@ import 'package:universal_ble/src/ble_command_queue.dart';
import 'package:universal_ble/src/universal_ble_linux/universal_ble_linux.dart'; import 'package:universal_ble/src/universal_ble_linux/universal_ble_linux.dart';
import 'package:universal_ble/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart'; import 'package:universal_ble/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart';
import 'package:universal_ble/src/universal_ble_web/universal_ble_web.dart'; import 'package:universal_ble/src/universal_ble_web/universal_ble_web.dart';
import 'package:universal_ble/src/universal_logger.dart';
import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble/universal_ble.dart';
class UniversalBle { class UniversalBle {
@@ -31,7 +32,7 @@ class UniversalBle {
/// [QueueType.none] will execute all commands in parallel. /// [QueueType.none] will execute all commands in parallel.
static set queueType(QueueType queueType) { static set queueType(QueueType queueType) {
_bleCommandQueue.queueType = queueType; _bleCommandQueue.queueType = queueType;
UniversalBlePlatform.logInfo('Queue ${queueType.name}'); UniversalLogger.logInfo('Queue ${queueType.name}');
} }
/// Get Bluetooth availability state. /// Get Bluetooth availability state.
@@ -70,28 +71,37 @@ class UniversalBle {
} }
/// Connection stream of a device /// Connection stream of a device
Stream<bool> connectionStream(String deviceId) => static Stream<BleConnectionUpdate> connectionStream(String deviceId) =>
_platform.connectionStream(deviceId); _platform.connectionStream(deviceId);
/// Connect to a device. /// Connect to a device.
/// It is advised to stop scanning before connecting. /// It is advised to stop scanning before connecting.
/// It might throw errors if device is not connectable. /// It throws error if device connection fails.
/// `connectionTimeout` is supported on Web only. /// Default connection timeout is 60 sec.
static Future<bool> connect( /// Can throw `ConnectionException` or `PlatformException`.
static Future<void> connect(
String deviceId, { String deviceId, {
Duration? connectionTimeout, Duration? connectionTimeout,
}) async { }) async {
connectionTimeout ??= const Duration(seconds: 60);
StreamSubscription? connectionSubscription; StreamSubscription? connectionSubscription;
try { try {
Completer<bool> completer = Completer(); Completer<bool> completer = Completer();
connectionSubscription = connectionSubscription = connectionStream(deviceId).listen(
_platform.connectionStream(deviceId).listen((bool event) { (BleConnectionUpdate event) {
connectionSubscription?.cancel(); connectionSubscription?.cancel();
if (!completer.isCompleted) { if (!completer.isCompleted) {
completer.complete(event); String? error = event.error;
} if (error != null) {
}); completer.completeError(ConnectionException(error));
} else {
completer.complete(event.isConnected);
}
}
},
);
_platform _platform
.connect(deviceId, connectionTimeout: connectionTimeout) .connect(deviceId, connectionTimeout: connectionTimeout)
@@ -99,15 +109,14 @@ class UniversalBle {
(error) { (error) {
if (completer.isCompleted == false) { if (completer.isCompleted == false) {
connectionSubscription?.cancel(); connectionSubscription?.cancel();
completer.completeError(error); completer.completeError(ConnectionException(error));
} }
}, },
); );
if (connectionTimeout != null) { if (!await completer.future.timeout(connectionTimeout)) {
return await completer.future.timeout(connectionTimeout); throw ConnectionException("Failed to connect");
} }
return await completer.future;
} finally { } finally {
connectionSubscription?.cancel(); connectionSubscription?.cancel();
} }
@@ -211,36 +220,65 @@ class UniversalBle {
static Future<bool?> isPaired( static Future<bool?> isPaired(
String deviceId, { String deviceId, {
BleCommand? pairingCommand, BleCommand? pairingCommand,
Duration? connectionTimeout,
}) async { }) async {
if (BleCapabilities.hasSystemPairingApi) { if (BleCapabilities.hasSystemPairingApi) {
return _bleCommandQueue.queueCommand( return _bleCommandQueue.queueCommand(
() => _platform.isPaired(deviceId), () => _platform.isPaired(deviceId),
deviceId: deviceId, deviceId: deviceId,
); );
} else if (pairingCommand != null) {
return _connectAndExecuteBleCommand(deviceId, pairingCommand,
updateCallbackValue: false);
} }
return null;
if (pairingCommand == null) {
UniversalLogger.logWarning("PairingCommand required to get result");
return null;
}
try {
await _connectAndExecuteBleCommand(
deviceId,
pairingCommand,
connectionTimeout: connectionTimeout,
updateCallbackValue: false,
);
// Because pairingCommand will be never null, so we wont get Unknown result here
return true;
} catch (e) {
UniversalLogger.logError("ExecuteBleCommandFailed: $e");
return false;
}
} }
/// Pair a device. /// Pair a device.
/// ///
/// It throws error if pairing fails.
///
/// On `Apple` and `Web`, it only works on devices with encrypted characteristics. /// On `Apple` and `Web`, it only works on devices with encrypted characteristics.
/// It returns null if there is no readable characteristic. /// It is advised to pass a pairingCommand with an encrypted read or write characteristic.
/// When not passing a pairingCommand, you should afterwards use [isPaired] with a pairingCommand
/// to verify the pairing state.
/// ///
/// You can optionally pass a pairingCommand if you know an encrypted read or write characteristic. /// On `Web/Windows` and `Web/Linux`, it does not work for devices that use `ConfirmOnly` pairing.
/// If you do, it returns true if it can successfully execute the command after pairing. /// Can throw `PairingException`, `ConnectionException` or `PlatformException`.
/// static Future<void> pair(
/// On `Web/Windows` and `Web/Linux`, it does not work for devices where `BleCapabilities.triggersConfirmOnlyPairing` is false.
static Future<bool?> pair(
String deviceId, { String deviceId, {
BleCommand? pairingCommand, BleCommand? pairingCommand,
Duration? connectionTimeout,
}) async { }) async {
if (BleCapabilities.hasSystemPairingApi) { if (BleCapabilities.hasSystemPairingApi) {
return _platform.pair(deviceId); bool paired = await _platform.pair(deviceId);
if (!paired) throw PairingException();
} else {
if (pairingCommand == null) {
UniversalLogger.logWarning("PairingCommand required to get result");
}
await _connectAndExecuteBleCommand(
deviceId,
pairingCommand,
connectionTimeout: connectionTimeout,
);
} }
return _connectAndExecuteBleCommand(deviceId, pairingCommand);
} }
/// Unpair a device. /// Unpair a device.
@@ -303,38 +341,32 @@ class UniversalBle {
} }
} }
static Future<bool?> _connectAndExecuteBleCommand( static Future<void> _connectAndExecuteBleCommand(
String deviceId, String deviceId,
BleCommand? bleCommand, { BleCommand? bleCommand, {
Duration? connectionTimeout,
bool updateCallbackValue = false, bool updateCallbackValue = false,
}) async { }) async {
try { // Try to connect first
if (await getConnectionState(deviceId) != BleConnectionState.connected) { if (await getConnectionState(deviceId) != BleConnectionState.connected) {
await connect(deviceId); UniversalLogger.logInfo("Connecting to $deviceId");
} await connect(
deviceId,
List<BleService> services = await discoverServices(deviceId); connectionTimeout: connectionTimeout,
if (bleCommand == null) {
await _attemptPairingReadingAll(deviceId, services);
return null;
} else {
bool commandResult =
await _executeBleCommand(deviceId, services, bleCommand);
if (updateCallbackValue) {
_platform.updatePairingState(deviceId, commandResult);
}
return commandResult;
}
} catch (e) {
UniversalBlePlatform.logInfo(
"FailedToPerform EncryptedCharOperation: $e",
); );
if (updateCallbackValue) {
_platform.updatePairingState(deviceId, false);
}
return false;
} }
List<BleService> services = await discoverServices(deviceId);
UniversalLogger.logInfo("Discovered services: ${services.length}");
if (bleCommand == null) {
// Just attempt pairing
await _attemptPairingReadingAll(deviceId, services);
return;
}
await _executeBleCommand(deviceId, services, bleCommand);
if (updateCallbackValue) _platform.updatePairingState(deviceId, true);
} }
// Fire and forget, and do not rely on result // Fire and forget, and do not rely on result
@@ -359,12 +391,13 @@ class UniversalBle {
} }
} }
} catch (_) {} } catch (_) {}
if (!containsReadCharacteristics) { if (!containsReadCharacteristics) {
throw "No readable characteristic found"; throw PairingException("No readable characteristic found");
} }
} }
static Future<bool> _executeBleCommand( static Future<void> _executeBleCommand(
String deviceId, String deviceId,
List<BleService> services, List<BleService> services,
BleCommand bleCommand, BleCommand bleCommand,
@@ -384,7 +417,7 @@ class UniversalBle {
} }
if (characteristic == null) { if (characteristic == null) {
return false; throw PairingException("BleCommand not found in discovered services");
} }
// Check if BleCommand Supports Read or Write // Check if BleCommand Supports Read or Write
@@ -396,28 +429,34 @@ class UniversalBle {
bleOutputProperty = BleOutputProperty.withoutResponse; bleOutputProperty = BleOutputProperty.withoutResponse;
} else if (!characteristic.properties } else if (!characteristic.properties
.contains(CharacteristicProperty.read)) { .contains(CharacteristicProperty.read)) {
return false; throw PairingException(
"BleCommand does not support read or write operation",
);
} }
Uint8List? value = bleCommand.writeValue; Uint8List? value = bleCommand.writeValue;
if (value != null && bleOutputProperty != null) {
await writeValue( try {
deviceId, if (value != null && bleOutputProperty != null) {
bleCommand.service, await writeValue(
bleCommand.characteristic, deviceId,
value, bleCommand.service,
bleOutputProperty, bleCommand.characteristic,
); value,
} else { bleOutputProperty,
// Fallback to read if supported );
await readValue( } else {
deviceId, // Fallback to read if supported
bleCommand.service, await readValue(
bleCommand.characteristic, deviceId,
timeout: const Duration(seconds: 30), bleCommand.service,
); bleCommand.characteristic,
timeout: const Duration(seconds: 30),
);
}
} catch (e) {
throw PairingException(e.toString());
} }
return true;
} }
/// Get updates of remaining items of a queue. /// Get updates of remaining items of a queue.
+35
View File
@@ -0,0 +1,35 @@
import 'package:flutter/services.dart';
class ConnectionException implements Exception {
late String message;
ConnectionException([dynamic error]) {
message = _errorParser(error);
}
@override
String toString() => message;
}
class PairingException implements Exception {
late String message;
PairingException([dynamic error]) {
message = _errorParser(error);
}
@override
String toString() => message;
}
String _errorParser(dynamic error) {
if (error == null) {
return "Failed";
} else if (error is PlatformException) {
return error.message ?? error.details ?? error.code;
} else if (error is String) {
return error;
} else {
return error.toString();
}
}
@@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:universal_ble/src/models/model_exports.dart'; import 'package:universal_ble/src/models/model_exports.dart';
import 'package:universal_ble/src/universal_ble_filter_util.dart'; import 'package:universal_ble/src/universal_ble_filter_util.dart';
import 'package:universal_ble/src/universal_ble_platform_interface.dart'; import 'package:universal_ble/src/universal_ble_platform_interface.dart';
import 'package:universal_ble/src/universal_logger.dart';
class UniversalBleLinux extends UniversalBlePlatform { class UniversalBleLinux extends UniversalBlePlatform {
UniversalBleLinux._(); UniversalBleLinux._();
@@ -45,10 +46,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
await _activeAdapter?.setPowered(true); await _activeAdapter?.setPowered(true);
return _activeAdapter?.powered ?? false; return _activeAdapter?.powered ?? false;
} catch (e) { } catch (e) {
UniversalBlePlatform.logInfo( UniversalLogger.logError('Error enabling bluetooth: $e');
'Error enabling bluetooth: $e',
isError: true,
);
return false; return false;
} }
} }
@@ -113,10 +111,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
return true; return true;
}); });
} catch (e) { } catch (e) {
UniversalBlePlatform.logInfo( UniversalLogger.logError("stopScan error: $e");
"stopScan error: $e",
isError: true,
);
} }
} }
@@ -159,7 +154,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
await device.propertiesChanged.firstWhere((element) { await device.propertiesChanged.firstWhere((element) {
if (element.contains(BluezProperty.connected)) { if (element.contains(BluezProperty.connected)) {
if (!device.connected) { if (!device.connected) {
UniversalBlePlatform.logInfo( UniversalLogger.logInfo(
"DiscoverServicesFailed: Device disconnected", "DiscoverServicesFailed: Device disconnected",
); );
return true; return true;
@@ -167,7 +162,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
} }
return element.contains(BluezProperty.servicesResolved); return element.contains(BluezProperty.servicesResolved);
}).timeout(const Duration(seconds: 10), onTimeout: () { }).timeout(const Duration(seconds: 10), onTimeout: () {
UniversalBlePlatform.logInfo( UniversalLogger.logInfo(
"DiscoverServicesFailed: Timeout", "DiscoverServicesFailed: Timeout",
); );
return []; return [];
@@ -238,8 +233,9 @@ class UniversalBleLinux extends UniversalBlePlatform {
); );
break; break;
default: default:
UniversalBlePlatform.logInfo( UniversalLogger.logInfo(
"UnhandledCharValuePropertyChange: $property"); "UnhandledCharValuePropertyChange: $property",
);
} }
} }
}); });
@@ -351,8 +347,9 @@ class UniversalBleLinux extends UniversalBlePlatform {
.map((e) => e.uuid.toString()) .map((e) => e.uuid.toString())
.any((service) => withServices.contains(service)); .any((service) => withServices.contains(service));
} else { } else {
UniversalBlePlatform.logInfo( UniversalLogger.logInfo(
'Skipping: ${device.address}: Services not resolved yet.'); 'Skipping: ${device.address}: Services not resolved yet.',
);
return false; return false;
} }
}).toList(); }).toList();
@@ -394,7 +391,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
_activeAdapter ??= _client.adapters.first; _activeAdapter ??= _client.adapters.first;
UniversalBlePlatform.logInfo( UniversalLogger.logInfo(
'BleAdapter: ${_activeAdapter?.name} - ${_activeAdapter?.address}', 'BleAdapter: ${_activeAdapter?.name} - ${_activeAdapter?.address}',
); );
@@ -411,7 +408,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
break; break;
case BluezProperty.propertyClass: case BluezProperty.propertyClass:
default: default:
UniversalBlePlatform.logInfo( UniversalLogger.logInfo(
"UnhandledPropertyChanged: $property", "UnhandledPropertyChanged: $property",
); );
} }
@@ -426,10 +423,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
_initializationCompleter?.complete(); _initializationCompleter?.complete();
_initializationCompleter = null; _initializationCompleter = null;
} catch (e) { } catch (e) {
UniversalBlePlatform.logInfo( UniversalLogger.logError('Error initializing: $e');
'Error initializing: $e',
isError: true,
);
_initializationCompleter?.completeError(e); _initializationCompleter?.completeError(e);
await _client.close(); await _client.close();
rethrow; rethrow;
@@ -501,7 +495,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
case BluezProperty.manufacturerData: case BluezProperty.manufacturerData:
break; break;
default: default:
UniversalBlePlatform.logInfo( UniversalLogger.logInfo(
"UnhandledDevicePropertyChanged ${device.name} ${device.address}: $property", "UnhandledDevicePropertyChanged ${device.name} ${device.address}: $property",
); );
break; break;
File diff suppressed because it is too large Load Diff
@@ -119,10 +119,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
) async { ) async {
var devices = await _channel.getSystemDevices(withServices ?? []); var devices = await _channel.getSystemDevices(withServices ?? []);
return List<BleDevice>.from( return List<BleDevice>.from(
devices devices.map((e) => e.toBleDevice(isSystemDevice: true)).toList(),
.map((e) => e?.toBleDevice(isSystemDevice: true))
.where((e) => e != null)
.toList(),
); );
} }
@@ -175,8 +172,8 @@ class _UniversalBleCallbackHandler extends UniversalBleCallbackChannel {
availabilityChange(AvailabilityState.parse(state)); availabilityChange(AvailabilityState.parse(state));
@override @override
void onConnectionChanged(String deviceId, bool connected) => void onConnectionChanged(String deviceId, bool connected, String? error) =>
connectionChanged(deviceId, connected); connectionChanged(deviceId, connected, error);
@override @override
void onScanResult(UniversalBleScanResult result) => void onScanResult(UniversalBleScanResult result) =>
@@ -200,9 +197,9 @@ extension _UniversalBleScanResultExtension on UniversalBleScanResult {
rssi: rssi, rssi: rssi,
isPaired: isPaired, isPaired: isPaired,
isSystemDevice: isSystemDevice, isSystemDevice: isSystemDevice,
services: services?.nonNulls.map(BleUuidParser.string).toList() ?? [], services: services?.map(BleUuidParser.string).toList() ?? [],
manufacturerDataList: manufacturerDataList?.nonNulls manufacturerDataList: manufacturerDataList
.map((e) => ManufacturerData(e.companyIdentifier, e.data)) ?.map((e) => ManufacturerData(e.companyIdentifier, e.data))
.toList() ?? .toList() ??
[], [],
); );
+18 -16
View File
@@ -1,10 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble/universal_ble.dart';
abstract class UniversalBlePlatform { abstract class UniversalBlePlatform {
StreamController? _connectionStreamController; StreamController<({String deviceId, bool isConnected, String? error})>?
_connectionStreamController;
final Map<String, bool> _pairStateMap = {}; final Map<String, bool> _pairStateMap = {};
Future<AvailabilityState> getBluetoothAvailabilityState(); Future<AvailabilityState> getBluetoothAvailabilityState();
@@ -57,21 +58,27 @@ abstract class UniversalBlePlatform {
bool receivesAdvertisements(String deviceId) => true; bool receivesAdvertisements(String deviceId) => true;
Stream<bool> connectionStream(String deviceId) { Stream<BleConnectionUpdate> connectionStream(String deviceId) {
_setupConnectionStreamIfRequired(); _setupConnectionStreamIfRequired();
return _connectionStreamController!.stream return _connectionStreamController!.stream
.where((event) => event.deviceId == deviceId) .where((event) => event.deviceId == deviceId)
.map((event) => event.isConnected); .map((event) => BleConnectionUpdate(
isConnected: event.isConnected,
error: event.error,
));
} }
void updateScanResult(BleDevice bleDevice) { void updateScanResult(BleDevice bleDevice) {
onScanResult?.call(bleDevice); onScanResult?.call(bleDevice);
} }
void updateConnection(String deviceId, bool isConnected) { void updateConnection(String deviceId, bool isConnected, [String? error]) {
onConnectionChange?.call(deviceId, isConnected); onConnectionChange?.call(deviceId, isConnected, error);
_connectionStreamController _connectionStreamController?.add((
?.add((deviceId: deviceId, isConnected: isConnected)); deviceId: deviceId,
isConnected: isConnected,
error: error,
));
} }
void updateCharacteristicValue( void updateCharacteristicValue(
@@ -97,17 +104,11 @@ abstract class UniversalBlePlatform {
OnAvailabilityChange? onAvailabilityChange; OnAvailabilityChange? onAvailabilityChange;
OnPairingStateChange? onPairingStateChange; OnPairingStateChange? onPairingStateChange;
static void logInfo(String message, {bool isError = false}) {
if (isError) message = '\x1B[31m$message\x1B[31m';
log(message, name: 'UniversalBle');
}
/// Creates an auto disposable streamController /// Creates an auto disposable streamController
void _setupConnectionStreamIfRequired() { void _setupConnectionStreamIfRequired() {
if (_connectionStreamController != null) return; if (_connectionStreamController != null) return;
_connectionStreamController = _connectionStreamController = StreamController.broadcast();
StreamController<({String deviceId, bool isConnected})>.broadcast();
// Auto dispose if no more subscribers // Auto dispose if no more subscribers
_connectionStreamController?.onCancel = () { _connectionStreamController?.onCancel = () {
@@ -119,7 +120,8 @@ abstract class UniversalBlePlatform {
} }
// Callback types // Callback types
typedef OnConnectionChange = void Function(String deviceId, bool isConnected); typedef OnConnectionChange = void Function(
String deviceId, bool isConnected, String? error);
typedef OnValueChange = void Function( typedef OnValueChange = void Function(
String deviceId, String characteristicId, Uint8List value); String deviceId, String characteristicId, Uint8List value);
@@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_web_bluetooth/flutter_web_bluetooth.dart'; import 'package:flutter_web_bluetooth/flutter_web_bluetooth.dart';
import 'package:universal_ble/src/models/model_exports.dart'; import 'package:universal_ble/src/models/model_exports.dart';
import 'package:universal_ble/src/universal_ble_platform_interface.dart'; import 'package:universal_ble/src/universal_ble_platform_interface.dart';
import 'package:universal_ble/src/universal_logger.dart';
class UniversalBleWeb extends UniversalBlePlatform { class UniversalBleWeb extends UniversalBlePlatform {
static UniversalBleWeb? _instance; static UniversalBleWeb? _instance;
@@ -127,10 +128,7 @@ class UniversalBleWeb extends UniversalBlePlatform {
device.advertisementsUseMemory = true; device.advertisementsUseMemory = true;
await device.watchAdvertisements(); await device.watchAdvertisements();
} catch (e) { } catch (e) {
UniversalBlePlatform.logInfo( UniversalLogger.logError("WebWatchAdvertisementError: $e");
"WebWatchAdvertisementError: $e",
isError: true,
);
} }
} }
@@ -395,9 +393,8 @@ class UniversalBleWeb extends UniversalBlePlatform {
} }
if (optionalServices.isEmpty) { if (optionalServices.isEmpty) {
UniversalBlePlatform.logInfo( UniversalLogger.logError(
"OptionalServices list is empty on web, you have to specify services in the ScanFilter in order to be able to access those after connecting", "OptionalServices list is empty on web, you have to specify services in the ScanFilter in order to be able to access those after connecting",
isError: true,
); );
} }
+24
View File
@@ -0,0 +1,24 @@
import 'dart:developer';
class UniversalLogger {
static void logInfo(message) {
log(
message.toString(),
name: 'UniversalBle:INFO',
);
}
static void logError(message) {
log(
'\x1B[31m$message\x1B[31m',
name: 'UniversalBle:ERROR',
);
}
static void logWarning(message) {
log(
'\x1B[33m$message\x1B[33m',
name: 'UniversalBle:WARN',
);
}
}
+1
View File
@@ -1,5 +1,6 @@
library universal_ble; library universal_ble;
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_platform_interface.dart';
export 'package:universal_ble/src/universal_ble.dart'; export 'package:universal_ble/src/universal_ble.dart';
export 'package:universal_ble/src/models/model_exports.dart'; export 'package:universal_ble/src/models/model_exports.dart';
+8 -7
View File
@@ -99,6 +99,7 @@ abstract class UniversalBleCallbackChannel {
void onConnectionChanged( void onConnectionChanged(
String deviceId, String deviceId,
bool connected, bool connected,
String? error,
); );
} }
@@ -107,8 +108,8 @@ class UniversalBleScanResult {
final String? name; final String? name;
final bool? isPaired; final bool? isPaired;
final int? rssi; final int? rssi;
final List<UniversalManufacturerData?>? manufacturerDataList; final List<UniversalManufacturerData>? manufacturerDataList;
final List<String?>? services; final List<String>? services;
UniversalBleScanResult({ UniversalBleScanResult({
required this.name, required this.name,
@@ -122,21 +123,21 @@ class UniversalBleScanResult {
class UniversalBleService { class UniversalBleService {
String uuid; String uuid;
List<UniversalBleCharacteristic?>? characteristics; List<UniversalBleCharacteristic>? characteristics;
UniversalBleService(this.uuid, this.characteristics); UniversalBleService(this.uuid, this.characteristics);
} }
class UniversalBleCharacteristic { class UniversalBleCharacteristic {
String uuid; String uuid;
List<int?> properties; List<int> properties;
UniversalBleCharacteristic(this.uuid, this.properties); UniversalBleCharacteristic(this.uuid, this.properties);
} }
/// Scan Filters /// Scan Filters
class UniversalScanFilter { class UniversalScanFilter {
final List<String?> withServices; final List<String> withServices;
final List<String?> withNamePrefix; final List<String> withNamePrefix;
final List<UniversalManufacturerDataFilter?> withManufacturerData; final List<UniversalManufacturerDataFilter> withManufacturerData;
UniversalScanFilter( UniversalScanFilter(
this.withServices, this.withServices,
+1 -1
View File
@@ -30,7 +30,7 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
pigeon: ^21.1.0 pigeon: ^22.4.0
flutter: flutter:
plugin: plugin:
+33 -25
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v21.1.0), do not edit directly. // Autogenerated from Pigeon (v22.4.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
#undef _HAS_EXCEPTIONS #undef _HAS_EXCEPTIONS
@@ -22,10 +22,10 @@ using flutter::EncodableMap;
using flutter::EncodableValue; using flutter::EncodableValue;
FlutterError CreateConnectionError(const std::string channel_name) { FlutterError CreateConnectionError(const std::string channel_name) {
return FlutterError( return FlutterError(
"channel-error", "channel-error",
"Unable to establish connection on channel: '" + channel_name + "'.", "Unable to establish connection on channel: '" + channel_name + "'.",
EncodableValue("")); EncodableValue(""));
} }
// UniversalBleScanResult // UniversalBleScanResult
@@ -146,7 +146,7 @@ UniversalBleScanResult UniversalBleScanResult::FromEncodableList(const Encodable
} }
auto& encodable_rssi = list[3]; auto& encodable_rssi = list[3];
if (!encodable_rssi.IsNull()) { if (!encodable_rssi.IsNull()) {
decoded.set_rssi(encodable_rssi.LongValue()); decoded.set_rssi(std::get<int64_t>(encodable_rssi));
} }
auto& encodable_manufacturer_data_list = list[4]; auto& encodable_manufacturer_data_list = list[4];
if (!encodable_manufacturer_data_list.IsNull()) { if (!encodable_manufacturer_data_list.IsNull()) {
@@ -364,7 +364,7 @@ EncodableList UniversalManufacturerDataFilter::ToEncodableList() const {
UniversalManufacturerDataFilter UniversalManufacturerDataFilter::FromEncodableList(const EncodableList& list) { UniversalManufacturerDataFilter UniversalManufacturerDataFilter::FromEncodableList(const EncodableList& list) {
UniversalManufacturerDataFilter decoded( UniversalManufacturerDataFilter decoded(
list[0].LongValue()); std::get<int64_t>(list[0]));
auto& encodable_data = list[1]; auto& encodable_data = list[1];
if (!encodable_data.IsNull()) { if (!encodable_data.IsNull()) {
decoded.set_data(std::get<std::vector<uint8_t>>(encodable_data)); decoded.set_data(std::get<std::vector<uint8_t>>(encodable_data));
@@ -412,36 +412,42 @@ EncodableList UniversalManufacturerData::ToEncodableList() const {
UniversalManufacturerData UniversalManufacturerData::FromEncodableList(const EncodableList& list) { UniversalManufacturerData UniversalManufacturerData::FromEncodableList(const EncodableList& list) {
UniversalManufacturerData decoded( UniversalManufacturerData decoded(
list[0].LongValue(), std::get<int64_t>(list[0]),
std::get<std::vector<uint8_t>>(list[1])); std::get<std::vector<uint8_t>>(list[1]));
return decoded; return decoded;
} }
PigeonCodecSerializer::PigeonCodecSerializer() {} PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {}
EncodableValue PigeonCodecSerializer::ReadValueOfType( EncodableValue PigeonInternalCodecSerializer::ReadValueOfType(
uint8_t type, uint8_t type,
flutter::ByteStreamReader* stream) const { flutter::ByteStreamReader* stream) const {
switch (type) { switch (type) {
case 129: case 129: {
return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); return CustomEncodableValue(UniversalBleScanResult::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
case 130: }
return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); case 130: {
case 131: return CustomEncodableValue(UniversalBleService::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); }
case 132: case 131: {
return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); return CustomEncodableValue(UniversalBleCharacteristic::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
case 133: }
return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); case 132: {
case 134: return CustomEncodableValue(UniversalScanFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get<EncodableList>(ReadValue(stream)))); }
case 133: {
return CustomEncodableValue(UniversalManufacturerDataFilter::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
}
case 134: {
return CustomEncodableValue(UniversalManufacturerData::FromEncodableList(std::get<EncodableList>(ReadValue(stream))));
}
default: default:
return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); return flutter::StandardCodecSerializer::ReadValueOfType(type, stream);
} }
} }
void PigeonCodecSerializer::WriteValue( void PigeonInternalCodecSerializer::WriteValue(
const EncodableValue& value, const EncodableValue& value,
flutter::ByteStreamWriter* stream) const { flutter::ByteStreamWriter* stream) const {
if (const CustomEncodableValue* custom_value = std::get_if<CustomEncodableValue>(&value)) { if (const CustomEncodableValue* custom_value = std::get_if<CustomEncodableValue>(&value)) {
@@ -481,7 +487,7 @@ void PigeonCodecSerializer::WriteValue(
/// The codec used by UniversalBlePlatformChannel. /// The codec used by UniversalBlePlatformChannel.
const flutter::StandardMessageCodec& UniversalBlePlatformChannel::GetCodec() { const flutter::StandardMessageCodec& UniversalBlePlatformChannel::GetCodec() {
return flutter::StandardMessageCodec::GetInstance(&PigeonCodecSerializer::GetInstance()); return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance());
} }
// Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binary_messenger`. // Sets up an instance of `UniversalBlePlatformChannel` to handle messages through the `binary_messenger`.
@@ -1019,7 +1025,7 @@ UniversalBleCallbackChannel::UniversalBleCallbackChannel(
message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {}
const flutter::StandardMessageCodec& UniversalBleCallbackChannel::GetCodec() { const flutter::StandardMessageCodec& UniversalBleCallbackChannel::GetCodec() {
return flutter::StandardMessageCodec::GetInstance(&PigeonCodecSerializer::GetInstance()); return flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance());
} }
void UniversalBleCallbackChannel::OnAvailabilityChanged( void UniversalBleCallbackChannel::OnAvailabilityChanged(
@@ -1133,6 +1139,7 @@ void UniversalBleCallbackChannel::OnValueChanged(
void UniversalBleCallbackChannel::OnConnectionChanged( void UniversalBleCallbackChannel::OnConnectionChanged(
const std::string& device_id_arg, const std::string& device_id_arg,
bool connected_arg, bool connected_arg,
const std::string* error_arg,
std::function<void(void)>&& on_success, std::function<void(void)>&& on_success,
std::function<void(const FlutterError&)>&& on_error) { std::function<void(const FlutterError&)>&& on_error) {
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.UniversalBleCallbackChannel.onConnectionChanged" + message_channel_suffix_;
@@ -1140,6 +1147,7 @@ void UniversalBleCallbackChannel::OnConnectionChanged(
EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ EncodableValue encoded_api_arguments = EncodableValue(EncodableList{
EncodableValue(device_id_arg), EncodableValue(device_id_arg),
EncodableValue(connected_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) { 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<EncodableValue> response = GetCodec().DecodeMessage(reply, reply_size); std::unique_ptr<EncodableValue> response = GetCodec().DecodeMessage(reply, reply_size);
+14 -11
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v21.1.0), do not edit directly. // Autogenerated from Pigeon (v22.4.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
#ifndef PIGEON_UNIVERSAL_BLE_G_H_ #ifndef PIGEON_UNIVERSAL_BLE_G_H_
@@ -57,6 +57,7 @@ template<class T> class ErrorOr {
}; };
// Generated class from Pigeon that represents data sent in messages. // Generated class from Pigeon that represents data sent in messages.
class UniversalBleScanResult { class UniversalBleScanResult {
public: public:
@@ -101,7 +102,7 @@ class UniversalBleScanResult {
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
friend class UniversalBlePlatformChannel; friend class UniversalBlePlatformChannel;
friend class UniversalBleCallbackChannel; friend class UniversalBleCallbackChannel;
friend class PigeonCodecSerializer; friend class PigeonInternalCodecSerializer;
std::string device_id_; std::string device_id_;
std::optional<std::string> name_; std::optional<std::string> name_;
std::optional<bool> is_paired_; std::optional<bool> is_paired_;
@@ -136,7 +137,7 @@ class UniversalBleService {
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
friend class UniversalBlePlatformChannel; friend class UniversalBlePlatformChannel;
friend class UniversalBleCallbackChannel; friend class UniversalBleCallbackChannel;
friend class PigeonCodecSerializer; friend class PigeonInternalCodecSerializer;
std::string uuid_; std::string uuid_;
std::optional<flutter::EncodableList> characteristics_; std::optional<flutter::EncodableList> characteristics_;
@@ -163,7 +164,7 @@ class UniversalBleCharacteristic {
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
friend class UniversalBlePlatformChannel; friend class UniversalBlePlatformChannel;
friend class UniversalBleCallbackChannel; friend class UniversalBleCallbackChannel;
friend class PigeonCodecSerializer; friend class PigeonInternalCodecSerializer;
std::string uuid_; std::string uuid_;
flutter::EncodableList properties_; flutter::EncodableList properties_;
@@ -196,7 +197,7 @@ class UniversalScanFilter {
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
friend class UniversalBlePlatformChannel; friend class UniversalBlePlatformChannel;
friend class UniversalBleCallbackChannel; friend class UniversalBleCallbackChannel;
friend class PigeonCodecSerializer; friend class PigeonInternalCodecSerializer;
flutter::EncodableList with_services_; flutter::EncodableList with_services_;
flutter::EncodableList with_name_prefix_; flutter::EncodableList with_name_prefix_;
flutter::EncodableList with_manufacturer_data_; flutter::EncodableList with_manufacturer_data_;
@@ -233,7 +234,7 @@ class UniversalManufacturerDataFilter {
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
friend class UniversalBlePlatformChannel; friend class UniversalBlePlatformChannel;
friend class UniversalBleCallbackChannel; friend class UniversalBleCallbackChannel;
friend class PigeonCodecSerializer; friend class PigeonInternalCodecSerializer;
int64_t company_identifier_; int64_t company_identifier_;
std::optional<std::vector<uint8_t>> data_; std::optional<std::vector<uint8_t>> data_;
std::optional<std::vector<uint8_t>> mask_; std::optional<std::vector<uint8_t>> mask_;
@@ -261,17 +262,18 @@ class UniversalManufacturerData {
flutter::EncodableList ToEncodableList() const; flutter::EncodableList ToEncodableList() const;
friend class UniversalBlePlatformChannel; friend class UniversalBlePlatformChannel;
friend class UniversalBleCallbackChannel; friend class UniversalBleCallbackChannel;
friend class PigeonCodecSerializer; friend class PigeonInternalCodecSerializer;
int64_t company_identifier_; int64_t company_identifier_;
std::vector<uint8_t> data_; std::vector<uint8_t> data_;
}; };
class PigeonCodecSerializer : public flutter::StandardCodecSerializer {
class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer {
public: public:
PigeonCodecSerializer(); PigeonInternalCodecSerializer();
inline static PigeonCodecSerializer& GetInstance() { inline static PigeonInternalCodecSerializer& GetInstance() {
static PigeonCodecSerializer sInstance; static PigeonInternalCodecSerializer sInstance;
return sInstance; return sInstance;
} }
@@ -387,6 +389,7 @@ class UniversalBleCallbackChannel {
void OnConnectionChanged( void OnConnectionChanged(
const std::string& device_id, const std::string& device_id,
bool connected, bool connected,
const std::string* error,
std::function<void(void)>&& on_success, std::function<void(void)>&& on_success,
std::function<void(const FlutterError&)>&& on_error); std::function<void(const FlutterError&)>&& on_error);
+8 -7
View File
@@ -190,7 +190,7 @@ namespace universal_ble
CleanConnection(deviceAddress); CleanConnection(deviceAddress);
// TODO: send disconnect event only after disconnect is complete // TODO: send disconnect event only after disconnect is complete
uiThreadHandler_.Post([deviceAddress] uiThreadHandler_.Post([deviceAddress]
{ callbackChannel->OnConnectionChanged(_mac_address_to_str(deviceAddress), false, SuccessCallback, ErrorCallback); }); { callbackChannel->OnConnectionChanged(_mac_address_to_str(deviceAddress), false, nullptr, SuccessCallback, ErrorCallback); });
return std::nullopt; return std::nullopt;
}; };
@@ -925,7 +925,7 @@ namespace universal_ble
{ {
std::cout << "ConnectionLog: ConnectionFailed: Failed to get device" << std::endl; std::cout << "ConnectionLog: ConnectionFailed: Failed to get device" << std::endl;
uiThreadHandler_.Post([bluetoothAddress] uiThreadHandler_.Post([bluetoothAddress]
{ callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), false, SuccessCallback, ErrorCallback); }); { callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), false, new std::string("Failed to get device"), SuccessCallback, ErrorCallback); });
co_return; co_return;
} }
@@ -933,9 +933,10 @@ namespace universal_ble
auto status = servicesResult.Status(); auto status = servicesResult.Status();
if (status != GattCommunicationStatus::Success) if (status != GattCommunicationStatus::Success)
{ {
std::cout << "ConnectionFailed: Failed to get services: " << GattCommunicationStatusToString(status) << std::endl; std::string error = GattCommunicationStatusToString(status);
uiThreadHandler_.Post([bluetoothAddress] std::cout << "ConnectionFailed: Failed to get services: " << error << std::endl;
{ callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), false, SuccessCallback, ErrorCallback); }); uiThreadHandler_.Post([bluetoothAddress, error]
{ callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), false, &error, SuccessCallback, ErrorCallback); });
co_return; co_return;
} }
@@ -972,7 +973,7 @@ namespace universal_ble
connectedDevices.insert(std::move(pair)); connectedDevices.insert(std::move(pair));
std::cout << "ConnectionLog: Connected" << std::endl; std::cout << "ConnectionLog: Connected" << std::endl;
uiThreadHandler_.Post([bluetoothAddress] uiThreadHandler_.Post([bluetoothAddress]
{ callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), true, SuccessCallback, ErrorCallback); }); { callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), true, nullptr, SuccessCallback, ErrorCallback); });
} }
void UniversalBlePlugin::BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, IInspectable args) void UniversalBlePlugin::BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, IInspectable args)
@@ -982,7 +983,7 @@ namespace universal_ble
CleanConnection(sender.BluetoothAddress()); CleanConnection(sender.BluetoothAddress());
auto bluetoothAddress = sender.BluetoothAddress(); auto bluetoothAddress = sender.BluetoothAddress();
uiThreadHandler_.Post([bluetoothAddress] uiThreadHandler_.Post([bluetoothAddress]
{ callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), false, SuccessCallback, ErrorCallback); }); { callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), false, nullptr, SuccessCallback, ErrorCallback); });
} }
} }