Add platform specific options in start scan (#65)

* Add platform specific options in start scan

* Add code level doc and ChangeLog

* Minor improvements
This commit is contained in:
Rohit Sangwan
2024-07-21 20:35:29 +05:30
committed by GitHub
parent 0d6b612497
commit 28b0bc6b7c
11 changed files with 123 additions and 83 deletions
+1
View File
@@ -1,3 +1,4 @@
export 'package:universal_ble/src/models/platform_config.dart';
export 'package:universal_ble/src/models/queue_type.dart';
export 'package:universal_ble/src/models/ble_uuid_parser.dart';
export 'package:universal_ble/src/models/scan_filter.dart';
+23
View File
@@ -0,0 +1,23 @@
/// Platform specific config to scan devices
class PlatformConfig {
WebConfig? web;
PlatformConfig({this.web});
}
/// Web config to scan devices
/// [optionalServices] is a list of service uuid's to ensure that you can access the specified services after connecting to the device,
/// by default services from scanFilter will be used
/// [optionalManufacturerData] is list of `CompanyIdentifier's` and used to add `ManufacturerData` in advertisement results of selected device from web dialog,
/// by default manufacturerData from scanFilter will be used
/// Checkout more details on [web](https://developer.mozilla.org/en-US/docs/Web/API/Bluetooth/requestDevice)
/// Note: you will only get advertisements if Experimental Flag is enabled in the browser
class WebConfig {
List<String> optionalServices;
List<int> optionalManufacturerData;
WebConfig({
this.optionalServices = const [],
this.optionalManufacturerData = const [],
});
}
+5 -1
View File
@@ -49,9 +49,13 @@ class UniversalBle {
/// `webRequestOptions` is supported on Web only
static Future<void> startScan({
ScanFilter? scanFilter,
PlatformConfig? platformConfig,
}) async {
return await _bleCommandQueue.queueCommand(
() => _platform.startScan(scanFilter: scanFilter),
() => _platform.startScan(
scanFilter: scanFilter,
platformConfig: platformConfig,
),
withTimeout: false,
);
}
@@ -55,6 +55,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
@override
Future<void> startScan({
ScanFilter? scanFilter,
PlatformConfig? platformConfig,
}) async {
await _ensureInitialized();
await super.startScan(scanFilter: scanFilter);
@@ -30,6 +30,7 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
@override
Future<void> startScan({
ScanFilter? scanFilter,
PlatformConfig? platformConfig,
}) async {
await super.startScan(scanFilter: scanFilter);
await _channel.startScan(
@@ -11,6 +11,7 @@ abstract class UniversalBlePlatform {
Future<void> startScan({
ScanFilter? scanFilter,
PlatformConfig? platformConfig,
}) async {
_scanFilter = scanFilter;
}
@@ -116,17 +116,10 @@ class UniversalBleWeb extends UniversalBlePlatform {
@override
Future<void> startScan({
ScanFilter? scanFilter,
PlatformConfig? platformConfig,
}) async {
if (scanFilter == null || scanFilter.withServices.isEmpty) {
UniversalBlePlatform.logInfo(
"Service list empty: on web you have to specify services in the ScanFilter in order to be able to access those after connecting",
isError: true,
);
}
BluetoothDevice device = await FlutterWebBluetooth.instance.requestDevice(
scanFilter?.toRequestOptionsBuilder() ??
RequestOptionsBuilder.acceptAllDevices(),
_getRequestOptionBuilder(scanFilter, platformConfig?.web),
);
// Update local device list
@@ -158,7 +151,7 @@ class UniversalBleWeb extends UniversalBlePlatform {
device.toBleScanResult(
rssi: event.rssi,
manufacturerDataMap: event.manufacturerData,
services: event.uuids,
services: event.uuids.toSet().toList(),
),
);
});
@@ -366,6 +359,78 @@ class UniversalBleWeb extends UniversalBlePlatform {
Future<bool> enableBluetooth() {
throw UnimplementedError();
}
RequestOptionsBuilder _getRequestOptionBuilder(
ScanFilter? scanFilter,
WebConfig? webConfig,
) {
List<RequestFilterBuilder> filters = [];
List<int> optionalManufacturerData = [];
List<String> optionalServices = [];
if (webConfig != null) {
optionalServices.addAll(webConfig.optionalServices.toValidUUIDList());
optionalManufacturerData.addAll(webConfig.optionalManufacturerData);
}
if (scanFilter != null) {
// Add services filter
for (var service in scanFilter.withServices.toValidUUIDList()) {
filters.add(RequestFilterBuilder(services: [service]));
if (webConfig == null || webConfig.optionalServices.isEmpty) {
optionalServices.add(service);
}
}
// Add manufacturer data filter
for (var manufacturerData in scanFilter.withManufacturerData) {
filters.add(
RequestFilterBuilder(
manufacturerData: [
ManufacturerDataFilterBuilder(
companyIdentifier: manufacturerData.companyIdentifier,
dataPrefix: manufacturerData.data,
mask: manufacturerData.mask,
),
],
),
);
// Add optionalManufacturerData from scanFilter if webConfig is not provided
if (webConfig == null || webConfig.optionalManufacturerData.isEmpty) {
int? companyId = manufacturerData.companyIdentifier;
if (companyId != null) {
optionalManufacturerData.add(companyId);
}
}
}
// Add name filter
for (var name in scanFilter.withNamePrefix) {
filters.add(RequestFilterBuilder(namePrefix: name));
}
}
if (optionalServices.isEmpty) {
UniversalBlePlatform.logInfo(
"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,
);
}
if (filters.isEmpty) {
return RequestOptionsBuilder.acceptAllDevices(
optionalServices: optionalServices,
optionalManufacturerData: optionalManufacturerData,
);
} else {
return RequestOptionsBuilder(
filters,
optionalServices: optionalServices,
optionalManufacturerData: optionalManufacturerData,
);
}
}
}
extension _BluetoothDeviceExtension on BluetoothDevice {
@@ -398,55 +463,3 @@ extension _UnmodifiableMapViewExtension on UnmodifiableMapView<int, ByteData> {
return Uint8List.fromList(bytes + manufacturerDataValue);
}
}
extension ScanFilterExtension on ScanFilter {
RequestOptionsBuilder toRequestOptionsBuilder() {
List<RequestFilterBuilder> filters = [];
List<int> manufacturerCompanyIdentifiers = [];
// Add services filter
for (var service in withServices.toValidUUIDList()) {
filters.add(
RequestFilterBuilder(
services: [service],
),
);
}
// Add manufacturer data filter
for (var manufacturerData in withManufacturerData) {
filters.add(
RequestFilterBuilder(
manufacturerData: [
ManufacturerDataFilterBuilder(
companyIdentifier: manufacturerData.companyIdentifier,
dataPrefix: manufacturerData.data,
mask: manufacturerData.mask,
),
],
),
);
int? companyId = manufacturerData.companyIdentifier;
if (companyId != null) {
manufacturerCompanyIdentifiers.add(companyId);
}
}
// Add name filter
for (var name in withNamePrefix) {
filters.add(
RequestFilterBuilder(namePrefix: name),
);
}
if (filters.isEmpty) {
return RequestOptionsBuilder.acceptAllDevices();
}
return RequestOptionsBuilder(
filters,
optionalServices: withServices.toValidUUIDList(),
optionalManufacturerData: manufacturerCompanyIdentifiers,
);
}
}