From 5847bbffc5b4e9f140ed1a3845d34140e971b2dc Mon Sep 17 00:00:00 2001 From: Rohit Sangwan Date: Fri, 17 May 2024 19:19:30 +0530 Subject: [PATCH] Add name prefix filtering (#45) * Add name filter * Change name filter to "prefix" * Implement namePrefix filtering * Update lib/src/universal_ble_platform_interface.dart * Update lib/src/universal_ble_platform_interface.dart --------- Co-authored-by: fotidim --- CHANGELOG.md | 4 ++++ README.md | 7 +++++++ .../lib/home/widgets/scanned_item_widget.dart | 13 +++++++++---- lib/src/models/scan_filter.dart | 2 ++ .../universal_ble_linux.dart | 7 ++++--- .../universal_ble_pigeon_channel.dart | 3 ++- lib/src/universal_ble_platform_interface.dart | 17 ++++++++++++++++- .../universal_ble_web/universal_ble_web.dart | 11 +++++++++-- pubspec.yaml | 2 +- 9 files changed, 54 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc55220..0c90a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ +## 0.9.11 +* Add device name prefix filtering + ## 0.9.10 * Fix Windows scan filter +* Remove scan result caching on Windows * Improve service discovery on Linux * Use asynchronous callbacks for SetNotifiable * Remove dependency on `convert` diff --git a/README.md b/README.md index 41754fb..6a25c35 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,13 @@ Use the `withManufacturerData` parameter to filter devices by manufacturer data. ```dart List withManufacturerData; ``` +##### With namePrefix + +Use the `withNamePrefix` parameter to filter devices by names (case sensitive). When you pass a list of names, the scan results will only include devices that have this name or start with the provided parameter. + +```dart +List withNamePrefix; +``` ### Connecting diff --git a/example/lib/home/widgets/scanned_item_widget.dart b/example/lib/home/widgets/scanned_item_widget.dart index 54589d8..0a3a319 100644 --- a/example/lib/home/widgets/scanned_item_widget.dart +++ b/example/lib/home/widgets/scanned_item_widget.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble_example/data/capabilities.dart'; @@ -10,6 +11,11 @@ class ScannedItemWidget extends StatelessWidget { @override Widget build(BuildContext context) { String? name = scanResult.name; + Uint8List? rawManufacturerData = scanResult.manufacturerData; + ManufacturerData? manufacturerData; + if (rawManufacturerData != null && rawManufacturerData.isNotEmpty) { + manufacturerData = ManufacturerData.fromData(rawManufacturerData); + } if (name == null || name.isEmpty) name = 'NA'; return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), @@ -23,12 +29,11 @@ class ScannedItemWidget extends StatelessWidget { children: [ Text(scanResult.deviceId), Visibility( - visible: scanResult.manufacturerData?.isNotEmpty == true, + visible: manufacturerData != null, child: Text( Platform.isWeb || Platform.isDesktop - ? ManufacturerData.fromData(scanResult.manufacturerData!) - .toString() - : 'ManufacturerCompanyId: ${ManufacturerData.fromData(scanResult.manufacturerData!).companyIdRadix16}', + ? manufacturerData.toString() + : 'ManufacturerCompanyId: ${manufacturerData?.companyIdRadix16}', ), ), Visibility( diff --git a/lib/src/models/scan_filter.dart b/lib/src/models/scan_filter.dart index 1c68069..177687b 100644 --- a/lib/src/models/scan_filter.dart +++ b/lib/src/models/scan_filter.dart @@ -3,10 +3,12 @@ import 'dart:typed_data'; class ScanFilter { final List withServices; final List withManufacturerData; + final List withNamePrefix; ScanFilter({ this.withServices = const [], this.withManufacturerData = const [], + this.withNamePrefix = const [], }); } diff --git a/lib/src/universal_ble_linux/universal_ble_linux.dart b/lib/src/universal_ble_linux/universal_ble_linux.dart index 6ef3af8..911c0fc 100644 --- a/lib/src/universal_ble_linux/universal_ble_linux.dart +++ b/lib/src/universal_ble_linux/universal_ble_linux.dart @@ -57,6 +57,7 @@ class UniversalBleLinux extends UniversalBlePlatform { ScanFilter? scanFilter, }) async { await _ensureInitialized(); + await super.startScan(scanFilter: scanFilter); if (_activeAdapter?.discovering != true) { // Add services filter _activeAdapter?.setDiscoveryFilter( @@ -399,7 +400,7 @@ class UniversalBleLinux extends UniversalBlePlatform { } // Update scan results only if rssi is available - if (device.rssi != 0) onScanResult?.call(device.toBleScanResult()); + if (device.rssi != 0) updateScanResult(device.toBleScanResult()); // Setup Cache _devices[device.address] = device; @@ -414,7 +415,7 @@ class UniversalBleLinux extends UniversalBlePlatform { for (final property in properties) { switch (property) { case BluezProperty.rssi: - onScanResult?.call(device.toBleScanResult()); + updateScanResult(device.toBleScanResult()); break; case BluezProperty.connected: onConnectionChanged?.call( @@ -425,7 +426,7 @@ class UniversalBleLinux extends UniversalBlePlatform { ); break; case BluezProperty.manufacturerData: - onScanResult?.call(device.toBleScanResult()); + updateScanResult(device.toBleScanResult()); break; case BluezProperty.paired: onPairingStateChange?.call(device.address, device.paired, null); diff --git a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart index d843fe3..e6fb3f8 100644 --- a/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart +++ b/lib/src/universal_ble_pigeon/universal_ble_pigeon_channel.dart @@ -31,6 +31,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { Future startScan({ ScanFilter? scanFilter, }) async { + await super.startScan(scanFilter: scanFilter); await _channel.startScan( scanFilter.toUniversalScanFilter(), ); @@ -116,7 +117,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform { /// To set listeners void _setupListeners() { UniversalBleCallbackChannel.setUp(_UniversalBleCallbackHandler( - scanResult: (BleScanResult scanResult) => onScanResult?.call(scanResult), + scanResult: (BleScanResult scanResult) => updateScanResult(scanResult), availabilityChange: (AvailabilityState state) => onAvailabilityChange?.call(state), connectionChanged: (String deviceId, BleConnectionState state) => diff --git a/lib/src/universal_ble_platform_interface.dart b/lib/src/universal_ble_platform_interface.dart index 0865d49..0372b29 100644 --- a/lib/src/universal_ble_platform_interface.dart +++ b/lib/src/universal_ble_platform_interface.dart @@ -3,13 +3,17 @@ import 'dart:typed_data'; import 'package:universal_ble/universal_ble.dart'; abstract class UniversalBlePlatform { + ScanFilter? _scanFilter; + Future getBluetoothAvailabilityState(); Future enableBluetooth(); Future startScan({ ScanFilter? scanFilter, - }); + }) async { + _scanFilter = scanFilter; + } Future stopScan(); @@ -44,6 +48,17 @@ abstract class UniversalBlePlatform { List? withServices, ); + void updateScanResult(BleScanResult scanResult) { + // Filter by name + ScanFilter? scanFilter = _scanFilter; + if (scanFilter != null && scanFilter.withNamePrefix.isNotEmpty) { + if (scanResult.name == null || + !scanFilter.withNamePrefix + .any((e) => scanResult.name?.startsWith(e) == true)) return; + } + onScanResult?.call(scanResult); + } + OnAvailabilityChange? onAvailabilityChange; OnScanResult? onScanResult; OnConnectionChanged? onConnectionChanged; diff --git a/lib/src/universal_ble_web/universal_ble_web.dart b/lib/src/universal_ble_web/universal_ble_web.dart index d940911..4109ac8 100644 --- a/lib/src/universal_ble_web/universal_ble_web.dart +++ b/lib/src/universal_ble_web/universal_ble_web.dart @@ -127,7 +127,7 @@ class UniversalBleWeb extends UniversalBlePlatform { _bluetoothDeviceList[device.id] = device; // Update Scan Result - onScanResult?.call(device.toBleScanResult()); + updateScanResult(device.toBleScanResult()); /// This will work only if `chrome://flags/#enable-experimental-web-platform-features` is enabled if (FlutterWebBluetooth.instance.hasRequestLEScan) { @@ -140,7 +140,7 @@ class UniversalBleWeb extends UniversalBlePlatform { _deviceAdvertisementStreamList[device.id] = device.advertisements.listen((event) { - onScanResult?.call( + updateScanResult( device.toBleScanResult( rssi: event.rssi, manufacturerDataMap: event.manufacturerData, @@ -410,6 +410,13 @@ extension ScanFilterExtension on ScanFilter { ); } + // Add name filter + for (var name in withNamePrefix) { + filters.add( + RequestFilterBuilder(namePrefix: name), + ); + } + if (filters.isEmpty) { return RequestOptionsBuilder.acceptAllDevices(); } diff --git a/pubspec.yaml b/pubspec.yaml index b3f6aec..7e85bd1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: universal_ble description: A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE) plugin for Flutter -version: 0.9.10 +version: 0.9.11 homepage: https://navideck.com repository: https://github.com/Navideck/universal_ble issue_tracker: https://github.com/Navideck/universal_ble/issues