Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## 3.1.1
* Apple, Linux: `discoverServices` honours its `timeout`. Both gave up after a fixed 10 seconds, so a longer `timeout` could not help a peripheral that is slow to answer. On Apple, `timeout` (or, without one, the global `UniversalBle.timeout`) is now passed on as the native limit, which `AppleDiscoverServicesOptions(timeoutMillis:)` in `DiscoverServicesPlatformConfig.apple` also sets directly, and then bounds the whole call when no `timeout` is given; without either, it stays 10 seconds. On Linux the discovery no longer has a limit of its own and is bounded by `timeout` alone, as on Android, Windows and Web, so one that runs out of time now fails with a `TimeoutException` rather than `Failed to resolve services` (#349).
* Apple: a read, write or subscription the peripheral refuses now reports its ATT error as the matching `UniversalBleErrorCode` (`insufficientEncryption`, `insufficientAuthentication`, `readNotPermitted`, ...), as Android does, instead of `unknownError`. The error code is still in `details`. Codes in `CBErrorDomain` are unchanged: its numbers overlap ATT's with other meanings (#348).
* Bump `bluez` to `^0.9.0`.
* Bump the `pigeon` dev dependency to `^29.0.0`.
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,14 @@ List<BleService> services = await bleDevice.discoverServices(
);
```

On iOS and macOS a discovery that has not completed after 10 seconds fails, so that it cannot hold back later calls for the same device. A `timeout` passed to `discoverServices`, or a global `UniversalBle.timeout` above 10 seconds, extends that, for a peripheral that is slow to answer; on the other platforms it is the only limit. `AppleDiscoverServicesOptions(timeoutMillis: ...)` sets the iOS and macOS limit directly, and without a `timeout` it bounds the whole call too.

```dart
List<BleService> services = await bleDevice.discoverServices(
timeout: const Duration(seconds: 30),
);
```

#### GetService

Retrieves a specific service. Returns a `Future<BleService>`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1388,25 +1388,75 @@ data class AndroidDiscoverServicesOptions (
}
}

/** Generated class from Pigeon that represents data sent in messages. */
data class AppleDiscoverServicesOptions (
/**
* How long, in milliseconds, the native discovery may take before it fails.
* iOS and macOS bound discovery themselves, so that a discovery that never
* completes cannot hold back later calls; 10 seconds when not set. Other
* platforms are bounded by the `timeout` of `discoverServices` alone.
*
* `discoverServices` fills this in from its `timeout` (by default the global
* `UniversalBle.timeout`) when only that is given, and takes this as its
* `timeout` when only this is. A value that is not positive counts as unset.
*/
val timeoutMillis: Long? = null
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): AppleDiscoverServicesOptions {
val timeoutMillis = pigeonVar_list[0] as Long?
return AppleDiscoverServicesOptions(timeoutMillis)
}
}
fun toList(): List<Any?> {
return listOf(
timeoutMillis,
)
}
override fun equals(other: Any?): Boolean {
if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
val other = other as AppleDiscoverServicesOptions
return UniversalBlePigeonUtils.deepEquals(this.timeoutMillis, other.timeoutMillis)
}

override fun hashCode(): Int {
var result = javaClass.hashCode()
result = 31 * result + UniversalBlePigeonUtils.deepHash(this.timeoutMillis)
return result
}
override fun toString(): String {
return "AppleDiscoverServicesOptions(timeoutMillis=$timeoutMillis)"
}
}

/**
* Platform-specific options for `discoverServices`. Ignored on platforms
* that have no equivalent.
*
* Generated class from Pigeon that represents data sent in messages.
*/
data class DiscoverServicesPlatformConfig (
val android: AndroidDiscoverServicesOptions? = null
val android: AndroidDiscoverServicesOptions? = null,
val apple: AppleDiscoverServicesOptions? = null
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): DiscoverServicesPlatformConfig {
val android = pigeonVar_list[0] as AndroidDiscoverServicesOptions?
return DiscoverServicesPlatformConfig(android)
val apple = pigeonVar_list[1] as AppleDiscoverServicesOptions?
return DiscoverServicesPlatformConfig(android, apple)
}
}
fun toList(): List<Any?> {
return listOf(
android,
apple,
)
}
override fun equals(other: Any?): Boolean {
Expand All @@ -1417,16 +1467,17 @@ data class DiscoverServicesPlatformConfig (
return true
}
val other = other as DiscoverServicesPlatformConfig
return UniversalBlePigeonUtils.deepEquals(this.android, other.android)
return UniversalBlePigeonUtils.deepEquals(this.android, other.android) && UniversalBlePigeonUtils.deepEquals(this.apple, other.apple)
}

override fun hashCode(): Int {
var result = javaClass.hashCode()
result = 31 * result + UniversalBlePigeonUtils.deepHash(this.android)
result = 31 * result + UniversalBlePigeonUtils.deepHash(this.apple)
return result
}
override fun toString(): String {
return "DiscoverServicesPlatformConfig(android=$android)"
return "DiscoverServicesPlatformConfig(android=$android, apple=$apple)"
}
}

Expand Down Expand Up @@ -1917,40 +1968,45 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() {
}
161.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
DiscoverServicesPlatformConfig.fromList(it)
AppleDiscoverServicesOptions.fromList(it)
}
}
162.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralAndroidOptions.fromList(it)
DiscoverServicesPlatformConfig.fromList(it)
}
}
163.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralPlatformConfig.fromList(it)
PeripheralAndroidOptions.fromList(it)
}
}
164.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralService.fromList(it)
PeripheralPlatformConfig.fromList(it)
}
}
165.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralCharacteristic.fromList(it)
PeripheralService.fromList(it)
}
}
166.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralDescriptor.fromList(it)
PeripheralCharacteristic.fromList(it)
}
}
167.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralReadRequestResult.fromList(it)
PeripheralDescriptor.fromList(it)
}
}
168.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralReadRequestResult.fromList(it)
}
}
169.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PeripheralWriteRequestResult.fromList(it)
}
Expand Down Expand Up @@ -2088,38 +2144,42 @@ private open class UniversalBlePigeonCodec : StandardMessageCodec() {
stream.write(160)
writeValue(stream, value.toList())
}
is DiscoverServicesPlatformConfig -> {
is AppleDiscoverServicesOptions -> {
stream.write(161)
writeValue(stream, value.toList())
}
is PeripheralAndroidOptions -> {
is DiscoverServicesPlatformConfig -> {
stream.write(162)
writeValue(stream, value.toList())
}
is PeripheralPlatformConfig -> {
is PeripheralAndroidOptions -> {
stream.write(163)
writeValue(stream, value.toList())
}
is PeripheralService -> {
is PeripheralPlatformConfig -> {
stream.write(164)
writeValue(stream, value.toList())
}
is PeripheralCharacteristic -> {
is PeripheralService -> {
stream.write(165)
writeValue(stream, value.toList())
}
is PeripheralDescriptor -> {
is PeripheralCharacteristic -> {
stream.write(166)
writeValue(stream, value.toList())
}
is PeripheralReadRequestResult -> {
is PeripheralDescriptor -> {
stream.write(167)
writeValue(stream, value.toList())
}
is PeripheralWriteRequestResult -> {
is PeripheralReadRequestResult -> {
stream.write(168)
writeValue(stream, value.toList())
}
is PeripheralWriteRequestResult -> {
stream.write(169)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
Expand Down
91 changes: 72 additions & 19 deletions darwin/universal_ble/Sources/universal_ble/UniversalBle.g.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1259,41 +1259,89 @@ struct AndroidDiscoverServicesOptions: Hashable, CustomStringConvertible {
}
}

/// Generated class from Pigeon that represents data sent in messages.
struct AppleDiscoverServicesOptions: Hashable, CustomStringConvertible {
/// How long, in milliseconds, the native discovery may take before it fails.
/// iOS and macOS bound discovery themselves, so that a discovery that never
/// completes cannot hold back later calls; 10 seconds when not set. Other
/// platforms are bounded by the `timeout` of `discoverServices` alone.
///
/// `discoverServices` fills this in from its `timeout` (by default the global
/// `UniversalBle.timeout`) when only that is given, and takes this as its
/// `timeout` when only this is. A value that is not positive counts as unset.
var timeoutMillis: Int64? = nil


// swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> AppleDiscoverServicesOptions? {
let timeoutMillis: Int64? = nilOrValue(pigeonVar_list[0])

return AppleDiscoverServicesOptions(
timeoutMillis: timeoutMillis
)
}
func toList() -> [Any?] {
return [
timeoutMillis
]
}
static func == (lhs: AppleDiscoverServicesOptions, rhs: AppleDiscoverServicesOptions) -> Bool {
if Swift.type(of: lhs) != Swift.type(of: rhs) {
return false
}
return UniversalBlePigeonInternal.deepEquals(lhs.timeoutMillis, rhs.timeoutMillis)
}

func hash(into hasher: inout Hasher) {
hasher.combine("AppleDiscoverServicesOptions")
UniversalBlePigeonInternal.deepHash(value: timeoutMillis, hasher: &hasher)
}

public var description: String {
return "AppleDiscoverServicesOptions(timeoutMillis: \(String(describing: timeoutMillis)))"
}
}

/// Platform-specific options for `discoverServices`. Ignored on platforms
/// that have no equivalent.
///
/// Generated class from Pigeon that represents data sent in messages.
struct DiscoverServicesPlatformConfig: Hashable, CustomStringConvertible {
var android: AndroidDiscoverServicesOptions? = nil
var apple: AppleDiscoverServicesOptions? = nil


// swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> DiscoverServicesPlatformConfig? {
let android: AndroidDiscoverServicesOptions? = nilOrValue(pigeonVar_list[0])
let apple: AppleDiscoverServicesOptions? = nilOrValue(pigeonVar_list[1])

return DiscoverServicesPlatformConfig(
android: android
android: android,
apple: apple
)
}
func toList() -> [Any?] {
return [
android
android,
apple,
]
}
static func == (lhs: DiscoverServicesPlatformConfig, rhs: DiscoverServicesPlatformConfig) -> Bool {
if Swift.type(of: lhs) != Swift.type(of: rhs) {
return false
}
return UniversalBlePigeonInternal.deepEquals(lhs.android, rhs.android)
return UniversalBlePigeonInternal.deepEquals(lhs.android, rhs.android) && UniversalBlePigeonInternal.deepEquals(lhs.apple, rhs.apple)
}

func hash(into hasher: inout Hasher) {
hasher.combine("DiscoverServicesPlatformConfig")
UniversalBlePigeonInternal.deepHash(value: android, hasher: &hasher)
UniversalBlePigeonInternal.deepHash(value: apple, hasher: &hasher)
}

public var description: String {
return "DiscoverServicesPlatformConfig(android: \(String(describing: android)))"
return "DiscoverServicesPlatformConfig(android: \(String(describing: android)), apple: \(String(describing: apple)))"
}
}

Expand Down Expand Up @@ -1743,20 +1791,22 @@ private class UniversalBlePigeonCodecReader: FlutterStandardReader {
case 160:
return AndroidDiscoverServicesOptions.fromList(self.readValue() as! [Any?])
case 161:
return DiscoverServicesPlatformConfig.fromList(self.readValue() as! [Any?])
return AppleDiscoverServicesOptions.fromList(self.readValue() as! [Any?])
case 162:
return PeripheralAndroidOptions.fromList(self.readValue() as! [Any?])
return DiscoverServicesPlatformConfig.fromList(self.readValue() as! [Any?])
case 163:
return PeripheralPlatformConfig.fromList(self.readValue() as! [Any?])
return PeripheralAndroidOptions.fromList(self.readValue() as! [Any?])
case 164:
return PeripheralService.fromList(self.readValue() as! [Any?])
return PeripheralPlatformConfig.fromList(self.readValue() as! [Any?])
case 165:
return PeripheralCharacteristic.fromList(self.readValue() as! [Any?])
return PeripheralService.fromList(self.readValue() as! [Any?])
case 166:
return PeripheralDescriptor.fromList(self.readValue() as! [Any?])
return PeripheralCharacteristic.fromList(self.readValue() as! [Any?])
case 167:
return PeripheralReadRequestResult.fromList(self.readValue() as! [Any?])
return PeripheralDescriptor.fromList(self.readValue() as! [Any?])
case 168:
return PeripheralReadRequestResult.fromList(self.readValue() as! [Any?])
case 169:
return PeripheralWriteRequestResult.fromList(self.readValue() as! [Any?])
default:
return super.readValue(ofType: type)
Expand Down Expand Up @@ -1862,30 +1912,33 @@ private class UniversalBlePigeonCodecWriter: FlutterStandardWriter {
} else if let value = value as? AndroidDiscoverServicesOptions {
super.writeByte(160)
super.writeValue(value.toList())
} else if let value = value as? DiscoverServicesPlatformConfig {
} else if let value = value as? AppleDiscoverServicesOptions {
super.writeByte(161)
super.writeValue(value.toList())
} else if let value = value as? PeripheralAndroidOptions {
} else if let value = value as? DiscoverServicesPlatformConfig {
super.writeByte(162)
super.writeValue(value.toList())
} else if let value = value as? PeripheralPlatformConfig {
} else if let value = value as? PeripheralAndroidOptions {
super.writeByte(163)
super.writeValue(value.toList())
} else if let value = value as? PeripheralService {
} else if let value = value as? PeripheralPlatformConfig {
super.writeByte(164)
super.writeValue(value.toList())
} else if let value = value as? PeripheralCharacteristic {
} else if let value = value as? PeripheralService {
super.writeByte(165)
super.writeValue(value.toList())
} else if let value = value as? PeripheralDescriptor {
} else if let value = value as? PeripheralCharacteristic {
super.writeByte(166)
super.writeValue(value.toList())
} else if let value = value as? PeripheralReadRequestResult {
} else if let value = value as? PeripheralDescriptor {
super.writeByte(167)
super.writeValue(value.toList())
} else if let value = value as? PeripheralWriteRequestResult {
} else if let value = value as? PeripheralReadRequestResult {
super.writeByte(168)
super.writeValue(value.toList())
} else if let value = value as? PeripheralWriteRequestResult {
super.writeByte(169)
super.writeValue(value.toList())
} else {
super.writeValue(value)
}
Expand Down
Loading
Loading