Improve web support (#66)
* Improve web support * Rename to _hasSelectedCharacteristicProperty * Update comment * Make _bleService private --------- Co-authored-by: Foti Dim <fdimanidis@gmail.com>
This commit is contained in:
@@ -152,7 +152,10 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
selectedCharacteristic!.service.uuid,
|
||||
selectedCharacteristic!.characteristic.uuid,
|
||||
value,
|
||||
BleOutputProperty.withResponse,
|
||||
_hasSelectedCharacteristicProperty(
|
||||
[CharacteristicProperty.writeWithoutResponse])
|
||||
? BleOutputProperty.withoutResponse
|
||||
: BleOutputProperty.withResponse,
|
||||
);
|
||||
_addLog('Write', value);
|
||||
} catch (e) {
|
||||
@@ -187,17 +190,6 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
}
|
||||
}
|
||||
|
||||
bool isValidProperty(List<CharacteristicProperty> properties) {
|
||||
for (CharacteristicProperty property in properties) {
|
||||
if (selectedCharacteristic?.characteristic.properties
|
||||
.contains(property) ??
|
||||
false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -307,7 +299,7 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
),
|
||||
),
|
||||
|
||||
if (isValidProperty([
|
||||
if (_hasSelectedCharacteristicProperty([
|
||||
CharacteristicProperty.write,
|
||||
CharacteristicProperty.writeWithoutResponse
|
||||
]))
|
||||
@@ -375,7 +367,7 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
PlatformButton(
|
||||
enabled: isConnected &&
|
||||
discoveredServices.isNotEmpty &&
|
||||
isValidProperty([
|
||||
_hasSelectedCharacteristicProperty([
|
||||
CharacteristicProperty.read,
|
||||
]),
|
||||
onPressed: _readValue,
|
||||
@@ -384,7 +376,7 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
PlatformButton(
|
||||
enabled: isConnected &&
|
||||
discoveredServices.isNotEmpty &&
|
||||
isValidProperty([
|
||||
_hasSelectedCharacteristicProperty([
|
||||
CharacteristicProperty.write,
|
||||
CharacteristicProperty.writeWithoutResponse
|
||||
]),
|
||||
@@ -394,7 +386,7 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
PlatformButton(
|
||||
enabled: isConnected &&
|
||||
discoveredServices.isNotEmpty &&
|
||||
isValidProperty([
|
||||
_hasSelectedCharacteristicProperty([
|
||||
CharacteristicProperty.notify,
|
||||
CharacteristicProperty.indicate
|
||||
]),
|
||||
@@ -405,7 +397,7 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
PlatformButton(
|
||||
enabled: isConnected &&
|
||||
discoveredServices.isNotEmpty &&
|
||||
isValidProperty([
|
||||
_hasSelectedCharacteristicProperty([
|
||||
CharacteristicProperty.notify,
|
||||
CharacteristicProperty.indicate
|
||||
]),
|
||||
@@ -476,4 +468,11 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
bool _hasSelectedCharacteristicProperty(
|
||||
List<CharacteristicProperty> properties) =>
|
||||
properties.any((property) =>
|
||||
selectedCharacteristic?.characteristic.properties
|
||||
.contains(property) ??
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
final Map<String, StreamSubscription> _deviceAdvertisementStreamList = {};
|
||||
final Map<String, StreamSubscription> _connectedDeviceStreamList = {};
|
||||
final Map<String, StreamSubscription> _characteristicStreamList = {};
|
||||
final Map<String, List<_UniversalWebBluetoothService>> _serviceCache = {};
|
||||
|
||||
@override
|
||||
Future<BleConnectionState> getConnectionState(String deviceId) async {
|
||||
@@ -56,47 +57,8 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<BleService>> discoverServices(String deviceId) async {
|
||||
final device = _getDeviceById(deviceId);
|
||||
final services = await device?.discoverServices();
|
||||
if (services == null) return [];
|
||||
var discoveredServices = <BleService>[];
|
||||
for (var service in services) {
|
||||
final characteristics = await service.getCharacteristics();
|
||||
List<BleCharacteristic> bleCharacteristics = [];
|
||||
for (BluetoothCharacteristic characteristic in characteristics) {
|
||||
List<CharacteristicProperty> properties = [];
|
||||
if (characteristic.properties.broadcast) {
|
||||
properties.add(CharacteristicProperty.broadcast);
|
||||
}
|
||||
if (characteristic.properties.read) {
|
||||
properties.add(CharacteristicProperty.read);
|
||||
}
|
||||
if (characteristic.properties.writeWithoutResponse) {
|
||||
properties.add(CharacteristicProperty.writeWithoutResponse);
|
||||
}
|
||||
if (characteristic.properties.write) {
|
||||
properties.add(CharacteristicProperty.write);
|
||||
}
|
||||
if (characteristic.properties.notify) {
|
||||
properties.add(CharacteristicProperty.notify);
|
||||
}
|
||||
if (characteristic.properties.indicate) {
|
||||
properties.add(CharacteristicProperty.indicate);
|
||||
}
|
||||
if (characteristic.properties.authenticatedSignedWrites) {
|
||||
properties.add(CharacteristicProperty.authenticatedSignedWrites);
|
||||
}
|
||||
bleCharacteristics.add(
|
||||
BleCharacteristic(characteristic.uuid.toString(), properties),
|
||||
);
|
||||
}
|
||||
discoveredServices.add(
|
||||
BleService(service.uuid.toString(), bleCharacteristics),
|
||||
);
|
||||
}
|
||||
return discoveredServices;
|
||||
}
|
||||
Future<List<BleService>> discoverServices(String deviceId) async =>
|
||||
(await _getServices(deviceId)).map((e) => e._bleService).toList();
|
||||
|
||||
@override
|
||||
Future<AvailabilityState> getBluetoothAvailabilityState() async {
|
||||
@@ -118,6 +80,7 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
ScanFilter? scanFilter,
|
||||
PlatformConfig? platformConfig,
|
||||
}) async {
|
||||
FlutterWebBluetooth.instance.isAvailable;
|
||||
BluetoothDevice device = await FlutterWebBluetooth.instance.requestDevice(
|
||||
_getRequestOptionBuilder(scanFilter, platformConfig?.web),
|
||||
);
|
||||
@@ -322,6 +285,7 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
return key.contains(deviceId);
|
||||
});
|
||||
_disposeAdvertisementWatcher(deviceId);
|
||||
_serviceCache.remove(deviceId);
|
||||
// _bluetoothDeviceList.removeWhere((element) => element.id == deviceId);
|
||||
}
|
||||
|
||||
@@ -330,20 +294,33 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
required String serviceId,
|
||||
required String characteristicId,
|
||||
}) async {
|
||||
final device = _getDeviceById(deviceId);
|
||||
List<BluetoothService> services = await device?.discoverServices() ?? [];
|
||||
BluetoothService? service;
|
||||
for (BluetoothService bleService in services) {
|
||||
if (bleService.uuid.toString() == serviceId.toString()) {
|
||||
service = bleService;
|
||||
break;
|
||||
for (var service in await _getServices(deviceId)) {
|
||||
if (BleUuidParser.compareStrings(service.uuid, serviceId)) {
|
||||
return service.getCharacteristic(characteristicId);
|
||||
}
|
||||
}
|
||||
return await service?.getCharacteristic(characteristicId.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
BluetoothDevice? _getDeviceById(String id) => _bluetoothDeviceList[id];
|
||||
|
||||
/// Get services and their characteristics.
|
||||
/// Services and characteristics are cached.
|
||||
/// Clears cache on disconnection.
|
||||
Future<List<_UniversalWebBluetoothService>> _getServices(
|
||||
String deviceId,
|
||||
) async {
|
||||
BluetoothDevice? device = _getDeviceById(deviceId);
|
||||
if (device == null) return [];
|
||||
var services = _serviceCache[deviceId] ?? [];
|
||||
if (services.isNotEmpty) return services;
|
||||
for (var service in await device.discoverServices()) {
|
||||
services.add(await _UniversalWebBluetoothService.fromService(service));
|
||||
}
|
||||
_serviceCache[deviceId] = services;
|
||||
return services;
|
||||
}
|
||||
|
||||
void _disposeAdvertisementWatcher([String? deviceId]) {
|
||||
_deviceAdvertisementStreamList.removeWhere((key, value) {
|
||||
if (deviceId != null && key != deviceId) return false;
|
||||
@@ -463,3 +440,51 @@ extension _UnmodifiableMapViewExtension on UnmodifiableMapView<int, ByteData> {
|
||||
return Uint8List.fromList(bytes + manufacturerDataValue);
|
||||
}
|
||||
}
|
||||
|
||||
class _UniversalWebBluetoothService {
|
||||
late String uuid;
|
||||
BluetoothService service;
|
||||
List<BluetoothCharacteristic> characteristics;
|
||||
|
||||
_UniversalWebBluetoothService({
|
||||
required this.service,
|
||||
required this.characteristics,
|
||||
}) {
|
||||
uuid = service.uuid;
|
||||
}
|
||||
|
||||
static Future<_UniversalWebBluetoothService> fromService(
|
||||
BluetoothService service,
|
||||
) async {
|
||||
return _UniversalWebBluetoothService(
|
||||
service: service,
|
||||
characteristics: await service.getCharacteristics(),
|
||||
);
|
||||
}
|
||||
|
||||
BluetoothCharacteristic? getCharacteristic(String characteristicId) {
|
||||
for (var characteristic in characteristics) {
|
||||
if (BleUuidParser.compareStrings(characteristic.uuid, characteristicId)) {
|
||||
return characteristic;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
BleService get _bleService => BleService(
|
||||
service.uuid,
|
||||
characteristics.map((e) {
|
||||
return BleCharacteristic(e.uuid, [
|
||||
if (e.properties.broadcast) CharacteristicProperty.broadcast,
|
||||
if (e.properties.read) CharacteristicProperty.read,
|
||||
if (e.properties.write) CharacteristicProperty.write,
|
||||
if (e.properties.writeWithoutResponse)
|
||||
CharacteristicProperty.writeWithoutResponse,
|
||||
if (e.properties.notify) CharacteristicProperty.notify,
|
||||
if (e.properties.indicate) CharacteristicProperty.indicate,
|
||||
if (e.properties.authenticatedSignedWrites)
|
||||
CharacteristicProperty.authenticatedSignedWrites,
|
||||
]);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user