Implement ScanFilter (#17)

* Implement ScanFilter

* Add windows implementation

* Fix Linux and cleanups

* Update Readme, Changelog and Version

* Minor fixes from AI comments

* Fix windows crash and update pigeon

* Fix UUID parsing

* Apply suggestions from code review

Co-authored-by: Foti Dim <foti@navideck.com>

---------

Co-authored-by: Foti Dim <foti@navideck.com>
This commit is contained in:
Rohit Sangwan
2024-03-05 22:37:14 +05:30
committed by GitHub
parent 7e47be374b
commit 1f7ba287ef
28 changed files with 546 additions and 118 deletions
+34 -5
View File
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v16.0.5), do not edit directly.
// Autogenerated from Pigeon (v17.1.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@@ -51,6 +51,7 @@ struct UniversalBleScanResult {
var rssi: Int64? = nil
var manufacturerData: FlutterStandardTypedData? = nil
var manufacturerDataHead: FlutterStandardTypedData? = nil
var services: [String?]? = nil
static func fromList(_ list: [Any?]) -> UniversalBleScanResult? {
let deviceId = list[0] as! String
@@ -59,6 +60,7 @@ struct UniversalBleScanResult {
let rssi: Int64? = isNullish(list[3]) ? nil : (list[3] is Int64? ? list[3] as! Int64? : Int64(list[3] as! Int32))
let manufacturerData: FlutterStandardTypedData? = nilOrValue(list[4])
let manufacturerDataHead: FlutterStandardTypedData? = nilOrValue(list[5])
let services: [String?]? = nilOrValue(list[6])
return UniversalBleScanResult(
deviceId: deviceId,
@@ -66,7 +68,8 @@ struct UniversalBleScanResult {
isPaired: isPaired,
rssi: rssi,
manufacturerData: manufacturerData,
manufacturerDataHead: manufacturerDataHead
manufacturerDataHead: manufacturerDataHead,
services: services
)
}
func toList() -> [Any?] {
@@ -77,6 +80,7 @@ struct UniversalBleScanResult {
rssi,
manufacturerData,
manufacturerDataHead,
services,
]
}
}
@@ -125,6 +129,24 @@ struct UniversalBleCharacteristic {
}
}
/// Generated class from Pigeon that represents data sent in messages.
struct UniversalScanFilter {
var withServices: [String?]
static func fromList(_ list: [Any?]) -> UniversalScanFilter? {
let withServices = list[0] as! [String?]
return UniversalScanFilter(
withServices: withServices
)
}
func toList() -> [Any?] {
return [
withServices
]
}
}
private class UniversalBlePlatformChannelCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? {
switch type {
@@ -134,6 +156,8 @@ private class UniversalBlePlatformChannelCodecReader: FlutterStandardReader {
return UniversalBleScanResult.fromList(self.readValue() as! [Any?])
case 130:
return UniversalBleService.fromList(self.readValue() as! [Any?])
case 131:
return UniversalScanFilter.fromList(self.readValue() as! [Any?])
default:
return super.readValue(ofType: type)
}
@@ -151,6 +175,9 @@ private class UniversalBlePlatformChannelCodecWriter: FlutterStandardWriter {
} else if let value = value as? UniversalBleService {
super.writeByte(130)
super.writeValue(value.toList())
} else if let value = value as? UniversalScanFilter {
super.writeByte(131)
super.writeValue(value.toList())
} else {
super.writeValue(value)
}
@@ -177,7 +204,7 @@ class UniversalBlePlatformChannelCodec: FlutterStandardMessageCodec {
protocol UniversalBlePlatformChannel {
func getBluetoothAvailabilityState(completion: @escaping (Result<Int64, Error>) -> Void)
func enableBluetooth(completion: @escaping (Result<Bool, Error>) -> Void)
func startScan() throws
func startScan(filter: UniversalScanFilter?) throws
func stopScan() throws
func connect(deviceId: String) throws
func disconnect(deviceId: String) throws
@@ -230,9 +257,11 @@ class UniversalBlePlatformChannelSetup {
}
let startScanChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan", binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
startScanChannel.setMessageHandler { _, reply in
startScanChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let filterArg: UniversalScanFilter? = nilOrValue(args[0])
do {
try api.startScan()
try api.startScan(filter: filterArg)
reply(wrapResult(nil))
} catch {
reply(wrapError(error))
+14
View File
@@ -141,6 +141,20 @@ public extension CBPeripheral {
}
}
extension String {
var validFullUUID: String {
let uuidLength = self.count
if uuidLength == 4 || uuidLength == 8 {
let baseUuid = "00000000-0000-1000-8000-00805F9B34FB"
let start = baseUuid.startIndex
let range = baseUuid.index(start, offsetBy: 4-uuidLength)..<baseUuid.index(start, offsetBy: 4)
return baseUuid.replacingCharacters(in: range, with: self)
} else {
return self
}
}
}
// Future classes
class CharacteristicReadFuture {
let deviceId: String
+17 -3
View File
@@ -56,8 +56,20 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
completion(Result.failure(FlutterError(code: "NotSupported", message: nil, details: nil)))
}
func startScan() throws {
manager.scanForPeripherals(withServices: nil)
func startScan(filter: UniversalScanFilter?) throws {
// Apply services filter
var withServices: [CBUUID] = []
for service in filter?.withServices ?? [] {
if let service = service {
if UUID(uuidString: service.validFullUUID) == nil {
throw FlutterError(code: "IllegalArgument", message: "Invalid service UUID:\(service)", details: nil)
}
withServices.append(CBUUID(string: service))
}
}
manager.scanForPeripherals(withServices: withServices)
}
func stopScan() throws {
@@ -228,12 +240,14 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
public func centralManager(_: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
discoveredPeripherals[peripheral.uuid.uuidString] = peripheral
let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data
let services = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID]
callbackChannel.onScanResult(result: UniversalBleScanResult(
deviceId: peripheral.uuid.uuidString,
name: peripheral.name,
isPaired: nil,
rssi: RSSI as? Int64,
manufacturerData: FlutterStandardTypedData(bytes: manufacturerData ?? Data())
manufacturerData: FlutterStandardTypedData(bytes: manufacturerData ?? Data()),
services: services?.map { $0.uuidStr }
)) { _ in }
}