feat: 支持外围设备接口,优化中心设备接口 (#18)
* 临时提交 * 临时提交 * 临时提交 * fix: 调整接口 * fix: 修复问题 * fix: 调整 iOS 实现 * fix: 添加注释 * fix: 修改预览版本号 * fix: 修复已知问题 * fix: 优化接口 * fix: 解决 32 位 UUID 报错问题 * fix: 修复问题 * fix: 修复依赖项 * fix: 移除多余代码 * fix: 修复已知问题 * fix: 修复问题 * fix: 修改版本号 * fix: 修复问题 * fix: 发布正式版本
This commit is contained in:
@ -1,3 +1,37 @@
|
||||
## 3.0.0
|
||||
|
||||
* Add `PeripheralManager` api.
|
||||
* Add `CentralManager#readRSSI` method.
|
||||
* Add `CentralManager.instance` api.
|
||||
* Add `PeripheralManager.instance` api.
|
||||
* Move `CentralController` to `CentralManager`.
|
||||
* Move `CentralState` to `BluetoothLowEnergyState`.
|
||||
* Move `CentralDiscoveredEventArgs` to `DiscoveredEventArgs`.
|
||||
* Move `Advertisement` class to `AdvertiseData` class.
|
||||
* Move `setUp` method from `BluetoothLowEnergy` class to `BluetoothLowEnergyManger` class.
|
||||
* Change the type of `manufacturerSpecificData` from `Map<int, Uint8List>` to `ManufacturerSpecificData`.
|
||||
* [Fix the issue that `UUID.fromString()` throw FormatException with 32 bits UUID string.](https://github.com/yanshouwang/bluetooth_low_energy/issues/13)
|
||||
* Fix known issues.
|
||||
|
||||
## 3.0.0-dev.4
|
||||
|
||||
* Move `Advertisement` class to `AdvertiseData` class.
|
||||
|
||||
## 3.0.0-dev.3
|
||||
|
||||
* [Fix the issue that `UUID.fromString()` throw FormatException with 32 bits UUID string.](https://github.com/yanshouwang/bluetooth_low_energy/issues/13)
|
||||
* Change the type of `manufacturerSpecificData` from `Map<int, Uint8List>` to `ManufacturerSpecificData`.
|
||||
|
||||
## 3.0.0-dev.2
|
||||
|
||||
* Move `setUp` method from `BluetoothLowEnergy` class to `BluetoothLowEnergyManger` class.
|
||||
* Add `CentralManager.instance` api.
|
||||
* Add `PeripheralManager.instance` api.
|
||||
|
||||
## 3.0.0-dev.1
|
||||
|
||||
* Implement new central manager api.
|
||||
|
||||
## 2.2.0
|
||||
|
||||
* Add `CentralController#getMaximumWriteLength` method.
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
|
||||
import 'src/my_central_controller.dart';
|
||||
import 'src/my_bluetooth_low_energy.dart';
|
||||
|
||||
abstract class BluetoothLowEnergyLinux {
|
||||
static void registerWith() {
|
||||
CentralController.instance = MyCentralController();
|
||||
BluetoothLowEnergy.instance = MyBluetoothLowEnergy();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
|
||||
import 'my_central_manager.dart';
|
||||
|
||||
class MyBluetoothLowEnergy extends BluetoothLowEnergy {
|
||||
@override
|
||||
final MyCentralManager centralManager;
|
||||
@override
|
||||
PeripheralManager get peripheralManager => throw UnimplementedError();
|
||||
|
||||
MyBluetoothLowEnergy() : centralManager = MyCentralManager();
|
||||
}
|
@ -3,54 +3,87 @@ import 'dart:typed_data';
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
extension MyBlueZAdapter on BlueZAdapter {
|
||||
CentralState get state {
|
||||
return powered ? CentralState.poweredOn : CentralState.poweredOff;
|
||||
import 'my_gatt_characteristic2.dart';
|
||||
import 'my_gatt_descriptor2.dart';
|
||||
import 'my_gatt_service2.dart';
|
||||
|
||||
extension BlueZAdapterX on BlueZAdapter {
|
||||
BluetoothLowEnergyState get myState {
|
||||
return powered
|
||||
? BluetoothLowEnergyState.poweredOn
|
||||
: BluetoothLowEnergyState.poweredOff;
|
||||
}
|
||||
}
|
||||
|
||||
extension MyBlueZDevice on BlueZDevice {
|
||||
extension BlueZDeviceX on BlueZDevice {
|
||||
BlueZUUID get uuid {
|
||||
final node = address.replaceAll(':', '');
|
||||
// We don't know the timestamp of the bluetooth device, use nil UUID as prefix.
|
||||
return BlueZUUID.fromString("00000000-0000-0000-0000-$node");
|
||||
}
|
||||
|
||||
Advertisement get advertisement {
|
||||
final name = this.name.isNotEmpty ? this.name : null;
|
||||
final manufacturerSpecificData = manufacturerData.map((key, value) {
|
||||
final id = key.id;
|
||||
final data = Uint8List.fromList(value);
|
||||
return MapEntry(id, data);
|
||||
UUID get myUUID => uuid.toMyUUID();
|
||||
|
||||
List<MyGattService2> get myServices =>
|
||||
gattServices.map((service) => MyGattService2(service)).toList();
|
||||
|
||||
AdvertiseData get myAdvertiseData {
|
||||
final myName = name.isNotEmpty ? name : null;
|
||||
final myServiceUUIDs = uuids.map((uuid) => uuid.toMyUUID()).toList();
|
||||
final myServiceData = serviceData.map((uuid, data) {
|
||||
final myUUID = uuid.toMyUUID();
|
||||
final myData = Uint8List.fromList(data);
|
||||
return MapEntry(myUUID, myData);
|
||||
});
|
||||
final serviceUUIDs = uuids.map((uuid) => uuid.toUUID()).toList();
|
||||
final serviceData = this.serviceData.map((uuid, data) {
|
||||
final key = uuid.toUUID();
|
||||
final value = Uint8List.fromList(data);
|
||||
return MapEntry(key, value);
|
||||
});
|
||||
return Advertisement(
|
||||
name: name,
|
||||
manufacturerSpecificData: manufacturerSpecificData,
|
||||
serviceUUIDs: serviceUUIDs,
|
||||
serviceData: serviceData,
|
||||
return AdvertiseData(
|
||||
name: myName,
|
||||
serviceUUIDs: myServiceUUIDs,
|
||||
serviceData: myServiceData,
|
||||
manufacturerSpecificData: myManufacturerSpecificData,
|
||||
);
|
||||
}
|
||||
|
||||
ManufacturerSpecificData get myManufacturerSpecificData {
|
||||
final entry = manufacturerData.entries.last;
|
||||
final myId = entry.key.id;
|
||||
final myData = Uint8List.fromList(entry.value);
|
||||
return ManufacturerSpecificData(
|
||||
id: myId,
|
||||
data: myData,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyBlueZUUID on BlueZUUID {
|
||||
UUID toUUID() => UUID(value);
|
||||
}
|
||||
extension BlueZGattServiceX on BlueZGattService {
|
||||
UUID get myUUID => uuid.toMyUUID();
|
||||
|
||||
extension MyBlueZGattCharacteristic on BlueZGattCharacteristic {
|
||||
List<GattCharacteristicProperty> get properties => flags
|
||||
.map((e) => e.toProperty())
|
||||
.whereType<GattCharacteristicProperty>()
|
||||
List<MyGattCharacteristic2> get myCharacteristics => characteristics
|
||||
.map((characteristic) => MyGattCharacteristic2(characteristic))
|
||||
.toList();
|
||||
}
|
||||
|
||||
extension MyBlueZGattCharacteristicFlag on BlueZGattCharacteristicFlag {
|
||||
GattCharacteristicProperty? toProperty() {
|
||||
extension MyBlueZGattCharacteristic on BlueZGattCharacteristic {
|
||||
UUID get myUUID => uuid.toMyUUID();
|
||||
|
||||
List<GattCharacteristicProperty> get myProperties => flags
|
||||
.map((e) => e.toMyProperty())
|
||||
.whereType<GattCharacteristicProperty>()
|
||||
.toList();
|
||||
|
||||
List<MyGattDescriptor2> get myDescriptors =>
|
||||
descriptors.map((descriptor) => MyGattDescriptor2(descriptor)).toList();
|
||||
}
|
||||
|
||||
extension BlueZGattDescriptorX on BlueZGattDescriptor {
|
||||
UUID get myUUID => uuid.toMyUUID();
|
||||
}
|
||||
|
||||
extension BlueZUUIDX on BlueZUUID {
|
||||
UUID toMyUUID() => UUID(value);
|
||||
}
|
||||
|
||||
extension BlueZGattCharacteristicFlagX on BlueZGattCharacteristicFlag {
|
||||
GattCharacteristicProperty? toMyProperty() {
|
||||
switch (this) {
|
||||
case BlueZGattCharacteristicFlag.read:
|
||||
return GattCharacteristicProperty.read;
|
||||
@ -68,8 +101,8 @@ extension MyBlueZGattCharacteristicFlag on BlueZGattCharacteristicFlag {
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattCharacteristicWriteType on GattCharacteristicWriteType {
|
||||
BlueZGattCharacteristicWriteType toBlueZ() {
|
||||
extension GattCharacteristicWriteTypeX on GattCharacteristicWriteType {
|
||||
BlueZGattCharacteristicWriteType toBlueZWriteType() {
|
||||
switch (this) {
|
||||
case GattCharacteristicWriteType.withResponse:
|
||||
return BlueZGattCharacteristicWriteType.request;
|
||||
|
@ -1,443 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bluetooth_low_energy_linux/src/my_event_args.dart';
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
import 'my_gatt_characteristic.dart';
|
||||
import 'my_gatt_descriptor.dart';
|
||||
import 'my_gatt_service.dart';
|
||||
import 'my_peripheral.dart';
|
||||
|
||||
class MyCentralController extends CentralController {
|
||||
MyCentralController()
|
||||
: _client = BlueZClient(),
|
||||
_stateChangedController = StreamController.broadcast(),
|
||||
_discoveredController = StreamController.broadcast(),
|
||||
_peripheralStateChangedController = StreamController.broadcast(),
|
||||
_characteristicValueChangedController = StreamController.broadcast(),
|
||||
_myPeripheralDiscoveredController = StreamController.broadcast(),
|
||||
_devicePropertiesChangedSubscriptions = {},
|
||||
_characteristicPropertiesChangedSubscriptions = {},
|
||||
_myPeripherals = {},
|
||||
_myServices = {},
|
||||
_myCharacteristics = {},
|
||||
_myDescriptors = {},
|
||||
_state = CentralState.unknown;
|
||||
|
||||
final BlueZClient _client;
|
||||
final StreamController<CentralStateChangedEventArgs> _stateChangedController;
|
||||
final StreamController<CentralDiscoveredEventArgs> _discoveredController;
|
||||
final StreamController<PeripheralStateChangedEventArgs>
|
||||
_peripheralStateChangedController;
|
||||
final StreamController<GattCharacteristicValueChangedEventArgs>
|
||||
_characteristicValueChangedController;
|
||||
final StreamController<MyPeripheralDiscoveredEventArgs>
|
||||
_myPeripheralDiscoveredController;
|
||||
final Map<int, StreamSubscription<List<String>>>
|
||||
_devicePropertiesChangedSubscriptions;
|
||||
final Map<int, StreamSubscription<List<String>>>
|
||||
_characteristicPropertiesChangedSubscriptions;
|
||||
final Map<int, MyPeripheral> _myPeripherals;
|
||||
final Map<int, Map<int, MyGattService>> _myServices;
|
||||
final Map<int, Map<int, MyGattCharacteristic>> _myCharacteristics;
|
||||
final Map<int, Map<int, MyGattDescriptor>> _myDescriptors;
|
||||
|
||||
BlueZAdapter get _adapter => _client.adapters.first;
|
||||
CentralState _state;
|
||||
@override
|
||||
CentralState get state => _state;
|
||||
|
||||
@override
|
||||
Stream<CentralStateChangedEventArgs> get stateChanged =>
|
||||
_stateChangedController.stream;
|
||||
@override
|
||||
Stream<CentralDiscoveredEventArgs> get discovered =>
|
||||
_discoveredController.stream;
|
||||
@override
|
||||
Stream<PeripheralStateChangedEventArgs> get peripheralStateChanged =>
|
||||
_peripheralStateChangedController.stream;
|
||||
@override
|
||||
Stream<GattCharacteristicValueChangedEventArgs>
|
||||
get characteristicValueChanged =>
|
||||
_characteristicValueChangedController.stream;
|
||||
Stream<MyPeripheralDiscoveredEventArgs> get _myPeripheralDiscovered =>
|
||||
_myPeripheralDiscoveredController.stream;
|
||||
|
||||
late StreamSubscription<List<String>> _adapterPropertiesChangedSubscription;
|
||||
late StreamSubscription<BlueZDevice> _deviceAddedSubscription;
|
||||
late StreamSubscription<BlueZDevice> _deviceRemovedSubscription;
|
||||
|
||||
Future<void> _throwWithState(CentralState state) async {
|
||||
if (this.state == state) {
|
||||
throw BluetoothLowEnergyError('$state is unexpected.');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _throwWithoutState(CentralState state) async {
|
||||
if (this.state != state) {
|
||||
throw BluetoothLowEnergyError(
|
||||
'$state is expected, but current state is ${this.state}.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setUp() async {
|
||||
await _throwWithoutState(CentralState.unknown);
|
||||
await _client.connect();
|
||||
_state =
|
||||
_client.adapters.isEmpty ? CentralState.unsupported : _adapter.state;
|
||||
if (_state == CentralState.unsupported) {
|
||||
return;
|
||||
}
|
||||
for (var device in _client.devices) {
|
||||
if (device.adapter.address != _adapter.address) {
|
||||
continue;
|
||||
}
|
||||
_beginDevicePropertiesChangedListener(device);
|
||||
}
|
||||
_adapterPropertiesChangedSubscription = _adapter.propertiesChanged.listen(
|
||||
_onAdapterPropertiesChanged,
|
||||
);
|
||||
_deviceAddedSubscription = _client.deviceAdded.listen(_onDeviceAdded);
|
||||
_deviceRemovedSubscription = _client.deviceRemoved.listen(_onDeviceRemoved);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> tearDown() async {
|
||||
await _throwWithState(CentralState.unknown);
|
||||
if (_state != CentralState.unsupported && _adapter.discovering) {
|
||||
await _adapter.stopDiscovery();
|
||||
}
|
||||
for (var myPeripheral in _myPeripherals.values) {
|
||||
final device = myPeripheral.device;
|
||||
if (device.connected) {
|
||||
await device.disconnect();
|
||||
}
|
||||
}
|
||||
_myPeripherals.clear();
|
||||
_myServices.clear();
|
||||
_myCharacteristics.clear();
|
||||
_myDescriptors.clear();
|
||||
for (var device in _client.devices) {
|
||||
if (device.adapter.address != _adapter.address) {
|
||||
continue;
|
||||
}
|
||||
_endDevicePropertiesChangedListener(device);
|
||||
}
|
||||
_adapterPropertiesChangedSubscription.cancel();
|
||||
_deviceAddedSubscription.cancel();
|
||||
_deviceRemovedSubscription.cancel();
|
||||
await _client.close();
|
||||
_state = CentralState.unknown;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> startDiscovery() async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
await _adapter.startDiscovery();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stopDiscovery() async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
await _adapter.stopDiscovery();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect(Peripheral peripheral) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral;
|
||||
final device = myPeripheral.device;
|
||||
await device.connect();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> disconnect(Peripheral peripheral) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral;
|
||||
final device = myPeripheral.device;
|
||||
await device.disconnect();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> getMaximumWriteLength(
|
||||
Peripheral peripheral, {
|
||||
required GattCharacteristicWriteType type,
|
||||
}) async {
|
||||
// TODO: 当前版本 `bluez` 插件不支持获取 MTU,返回最小值 20.
|
||||
return 20;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> discoverGATT(Peripheral peripheral) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral;
|
||||
final device = myPeripheral.device;
|
||||
if (!device.connected) {
|
||||
throw BluetoothLowEnergyError('Peripheral is disconnected.');
|
||||
}
|
||||
if (device.servicesResolved) {
|
||||
return;
|
||||
}
|
||||
await _myPeripheralDiscovered.firstWhere(
|
||||
(eventArgs) => eventArgs.myPeripheral == myPeripheral,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GattService>> getServices(Peripheral peripheral) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral;
|
||||
final myServices = _myServices[myPeripheral.hashCode];
|
||||
if (myServices == null) {
|
||||
throw ArgumentError();
|
||||
}
|
||||
return myServices.values.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GattCharacteristic>> getCharacteristics(
|
||||
GattService service,
|
||||
) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myService = service as MyGattService;
|
||||
final myCharacteristics = _myCharacteristics[myService.hashCode];
|
||||
if (myCharacteristics == null) {
|
||||
throw ArgumentError();
|
||||
}
|
||||
return myCharacteristics.values.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GattDescriptor>> getDescriptors(
|
||||
GattCharacteristic characteristic,
|
||||
) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myCharacteristic = characteristic as MyGattCharacteristic;
|
||||
final myDescriptors = _myDescriptors[myCharacteristic.hashCode];
|
||||
if (myDescriptors == null) {
|
||||
throw ArgumentError();
|
||||
}
|
||||
return myDescriptors.values.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readCharacteristic(
|
||||
GattCharacteristic characteristic,
|
||||
) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myCharacteristic = characteristic as MyGattCharacteristic;
|
||||
final blueZCharacteristic = myCharacteristic.characteristic;
|
||||
final blueZValue = await blueZCharacteristic.readValue();
|
||||
return Uint8List.fromList(blueZValue);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> writeCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
required Uint8List value,
|
||||
required GattCharacteristicWriteType type,
|
||||
}) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myCharacteristic = characteristic as MyGattCharacteristic;
|
||||
final blueZCharacteristic = myCharacteristic.characteristic;
|
||||
await blueZCharacteristic.writeValue(
|
||||
value,
|
||||
type: type.toBlueZ(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> notifyCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
required bool state,
|
||||
}) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myCharacteristic = characteristic as MyGattCharacteristic;
|
||||
final blueZCharacteristic = myCharacteristic.characteristic;
|
||||
if (state) {
|
||||
await blueZCharacteristic.startNotify();
|
||||
} else {
|
||||
await blueZCharacteristic.stopNotify();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readDescriptor(GattDescriptor descriptor) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myDescriptor = descriptor as MyGattDescriptor;
|
||||
final blueZDescriptor = myDescriptor.descriptor;
|
||||
final blueZValue = await blueZDescriptor.readValue();
|
||||
return Uint8List.fromList(blueZValue);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> writeDescriptor(
|
||||
GattDescriptor descriptor, {
|
||||
required Uint8List value,
|
||||
}) async {
|
||||
await _throwWithoutState(CentralState.poweredOn);
|
||||
final myDescriptor = descriptor as MyGattDescriptor;
|
||||
final blueZDescriptor = myDescriptor.descriptor;
|
||||
await blueZDescriptor.writeValue(value);
|
||||
}
|
||||
|
||||
void _onAdapterPropertiesChanged(List<String> properties) {
|
||||
for (var property in properties) {
|
||||
switch (property) {
|
||||
case 'Powered':
|
||||
final state = _adapter.state;
|
||||
if (_state == state) {
|
||||
return;
|
||||
}
|
||||
_state = state;
|
||||
final eventArgs = CentralStateChangedEventArgs(state);
|
||||
_stateChangedController.add(eventArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _onDeviceAdded(BlueZDevice device) {
|
||||
if (device.adapter.address != _adapter.address) {
|
||||
return;
|
||||
}
|
||||
_onDiscovered(device);
|
||||
_beginDevicePropertiesChangedListener(device);
|
||||
}
|
||||
|
||||
void _onDeviceRemoved(BlueZDevice device) {
|
||||
if (device.adapter.address != _adapter.address) {
|
||||
return;
|
||||
}
|
||||
_endDevicePropertiesChangedListener(device);
|
||||
}
|
||||
|
||||
void _onDiscovered(BlueZDevice device) {
|
||||
final myPeripheral = MyPeripheral(device);
|
||||
_myPeripherals[myPeripheral.hashCode] = myPeripheral;
|
||||
final rssi = device.rssi;
|
||||
final advertisement = device.advertisement;
|
||||
final eventArgs = CentralDiscoveredEventArgs(
|
||||
myPeripheral,
|
||||
rssi,
|
||||
advertisement,
|
||||
);
|
||||
_discoveredController.add(eventArgs);
|
||||
}
|
||||
|
||||
void _beginDevicePropertiesChangedListener(BlueZDevice device) {
|
||||
final subscription = device.propertiesChanged.listen((properties) {
|
||||
for (var property in properties) {
|
||||
switch (property) {
|
||||
case 'RSSI':
|
||||
_onDiscovered(device);
|
||||
break;
|
||||
case 'Connected':
|
||||
final myPeripheral =
|
||||
_myPeripherals[device.hashCode] as MyPeripheral;
|
||||
final state = device.connected;
|
||||
final eventArgs = PeripheralStateChangedEventArgs(
|
||||
myPeripheral,
|
||||
state,
|
||||
);
|
||||
_peripheralStateChangedController.add(eventArgs);
|
||||
break;
|
||||
case 'UUIDs':
|
||||
break;
|
||||
case 'ServicesResolved':
|
||||
if (device.servicesResolved) {
|
||||
final myPeripheral =
|
||||
_myPeripherals[device.hashCode] as MyPeripheral;
|
||||
final myServices = <int, MyGattService>{};
|
||||
for (var service in device.gattServices) {
|
||||
final myService = MyGattService(service);
|
||||
myServices[myService.hashCode] = myService;
|
||||
final myCharacteristics = <int, MyGattCharacteristic>{};
|
||||
for (var characteristic in service.characteristics) {
|
||||
final myCharacteristic = MyGattCharacteristic(characteristic);
|
||||
myCharacteristics[myCharacteristic.hashCode] =
|
||||
myCharacteristic;
|
||||
_beginCharacteristicPropertiesChangedListener(
|
||||
service,
|
||||
characteristic,
|
||||
);
|
||||
final myDescriptors = <int, MyGattDescriptor>{};
|
||||
for (var descriptor in characteristic.descriptors) {
|
||||
final myDescriptor = MyGattDescriptor(descriptor);
|
||||
myDescriptors[myDescriptor.hashCode] = myDescriptor;
|
||||
}
|
||||
_myDescriptors[myCharacteristic.hashCode] = myDescriptors;
|
||||
}
|
||||
_myCharacteristics[myService.hashCode] = myCharacteristics;
|
||||
}
|
||||
_myServices[myPeripheral.hashCode] = myServices;
|
||||
final eventArgs = MyPeripheralDiscoveredEventArgs(myPeripheral);
|
||||
_myPeripheralDiscoveredController.add(eventArgs);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
_devicePropertiesChangedSubscriptions[device.hashCode] = subscription;
|
||||
}
|
||||
|
||||
void _endDevicePropertiesChangedListener(BlueZDevice device) {
|
||||
for (var service in device.gattServices) {
|
||||
for (var characteristic in service.characteristics) {
|
||||
_endCharacteristicPropertiesChangedListener(characteristic);
|
||||
}
|
||||
}
|
||||
final subscription = _devicePropertiesChangedSubscriptions.remove(
|
||||
device.address,
|
||||
);
|
||||
subscription?.cancel();
|
||||
}
|
||||
|
||||
void _beginCharacteristicPropertiesChangedListener(
|
||||
BlueZGattService service,
|
||||
BlueZGattCharacteristic characteristic,
|
||||
) {
|
||||
final subscription = characteristic.propertiesChanged.listen((properties) {
|
||||
for (var property in properties) {
|
||||
switch (property) {
|
||||
case 'Value':
|
||||
final myCharacteristics = _myCharacteristics[service.hashCode];
|
||||
if (myCharacteristics == null) {
|
||||
throw ArgumentError();
|
||||
}
|
||||
final myCharacteristic = myCharacteristics[characteristic.hashCode]
|
||||
as MyGattCharacteristic;
|
||||
final value = Uint8List.fromList(characteristic.value);
|
||||
final eventArgs = GattCharacteristicValueChangedEventArgs(
|
||||
myCharacteristic,
|
||||
value,
|
||||
);
|
||||
_characteristicValueChangedController.add(eventArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
_characteristicPropertiesChangedSubscriptions[characteristic.hashCode] =
|
||||
subscription;
|
||||
}
|
||||
|
||||
void _endCharacteristicPropertiesChangedListener(
|
||||
BlueZGattCharacteristic characteristic,
|
||||
) {
|
||||
final subscription = _characteristicPropertiesChangedSubscriptions.remove(
|
||||
characteristic.hashCode,
|
||||
);
|
||||
subscription?.cancel();
|
||||
}
|
||||
}
|
342
bluetooth_low_energy_linux/lib/src/my_central_manager.dart
Normal file
342
bluetooth_low_energy_linux/lib/src/my_central_manager.dart
Normal file
@ -0,0 +1,342 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
import 'my_event_args.dart';
|
||||
import 'my_gatt_characteristic2.dart';
|
||||
import 'my_gatt_descriptor2.dart';
|
||||
import 'my_gatt_service2.dart';
|
||||
import 'my_peripheral2.dart';
|
||||
|
||||
class MyCentralManager extends CentralManager {
|
||||
MyCentralManager()
|
||||
: _client = BlueZClient(),
|
||||
_stateChangedController = StreamController.broadcast(),
|
||||
_discoveredController = StreamController.broadcast(),
|
||||
_peripheralStateChangedController = StreamController.broadcast(),
|
||||
_characteristicValueChangedController = StreamController.broadcast(),
|
||||
_deviceServicesResolvedController = StreamController.broadcast(),
|
||||
_myServicesOfMyPeripherals = {},
|
||||
_characteristicPropertiesChangedSubscriptions = {},
|
||||
_state = BluetoothLowEnergyState.unknown;
|
||||
|
||||
final BlueZClient _client;
|
||||
final StreamController<BluetoothLowEnergyStateChangedEventArgs>
|
||||
_stateChangedController;
|
||||
final StreamController<DiscoveredEventArgs> _discoveredController;
|
||||
final StreamController<PeripheralStateChangedEventArgs>
|
||||
_peripheralStateChangedController;
|
||||
final StreamController<GattCharacteristicValueChangedEventArgs>
|
||||
_characteristicValueChangedController;
|
||||
final StreamController<BlueZDeviceServicesResolvedEventArgs>
|
||||
_deviceServicesResolvedController;
|
||||
|
||||
final Map<int, List<MyGattService2>> _myServicesOfMyPeripherals;
|
||||
final Map<int, StreamSubscription>
|
||||
_characteristicPropertiesChangedSubscriptions;
|
||||
|
||||
BlueZAdapter get _adapter => _client.adapters.first;
|
||||
BluetoothLowEnergyState _state;
|
||||
@override
|
||||
BluetoothLowEnergyState get state => _state;
|
||||
|
||||
@override
|
||||
Stream<BluetoothLowEnergyStateChangedEventArgs> get stateChanged =>
|
||||
_stateChangedController.stream;
|
||||
@override
|
||||
Stream<DiscoveredEventArgs> get discovered => _discoveredController.stream;
|
||||
@override
|
||||
Stream<PeripheralStateChangedEventArgs> get peripheralStateChanged =>
|
||||
_peripheralStateChangedController.stream;
|
||||
@override
|
||||
Stream<GattCharacteristicValueChangedEventArgs>
|
||||
get characteristicValueChanged =>
|
||||
_characteristicValueChangedController.stream;
|
||||
Stream<BlueZDeviceServicesResolvedEventArgs> get _servicesResolved =>
|
||||
_deviceServicesResolvedController.stream;
|
||||
|
||||
Future<void> _throwWithoutState(BluetoothLowEnergyState state) async {
|
||||
if (this.state != state) {
|
||||
throw BluetoothLowEnergyError(
|
||||
'$state is expected, but current state is ${this.state}.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setUp() async {
|
||||
// TODO: hot restart is not handled.
|
||||
await _client.connect();
|
||||
_state = _client.adapters.isEmpty
|
||||
? BluetoothLowEnergyState.unsupported
|
||||
: _adapter.myState;
|
||||
if (_state == BluetoothLowEnergyState.unsupported) {
|
||||
return;
|
||||
}
|
||||
for (var device in _client.devices) {
|
||||
if (device.adapter.address != _adapter.address) {
|
||||
continue;
|
||||
}
|
||||
_beginDevicePropertiesChangedListener(device);
|
||||
}
|
||||
_adapter.propertiesChanged.listen(_onAdapterPropertiesChanged);
|
||||
_client.deviceAdded.listen(_onDeviceAdded);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> startDiscovery() async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
await _adapter.startDiscovery();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stopDiscovery() async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
await _adapter.stopDiscovery();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect(Peripheral peripheral) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral2;
|
||||
final device = myPeripheral.device;
|
||||
await device.connect();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> disconnect(Peripheral peripheral) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral2;
|
||||
final device = myPeripheral.device;
|
||||
await device.disconnect();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> getMaximumWriteLength(
|
||||
Peripheral peripheral, {
|
||||
required GattCharacteristicWriteType type,
|
||||
}) async {
|
||||
// TODO: 当前版本 `bluez` 插件不支持获取 MTU,返回最小值 20.
|
||||
return 20;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> readRSSI(Peripheral peripheral) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral2;
|
||||
final device = myPeripheral.device;
|
||||
return device.rssi;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GattService>> discoverGATT(Peripheral peripheral) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myPeripheral = peripheral as MyPeripheral2;
|
||||
final device = myPeripheral.device;
|
||||
if (!device.connected) {
|
||||
throw BluetoothLowEnergyError('Peripheral is disconnected.');
|
||||
}
|
||||
if (!device.servicesResolved) {
|
||||
await _servicesResolved.firstWhere(
|
||||
(eventArgs) => eventArgs.device == device,
|
||||
);
|
||||
}
|
||||
final myServices = _myServicesOfMyPeripherals[myPeripheral.hashCode];
|
||||
if (myServices == null) {
|
||||
throw ArgumentError.notNull();
|
||||
}
|
||||
return myServices;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readCharacteristic(
|
||||
GattCharacteristic characteristic,
|
||||
) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myCharacteristic = characteristic as MyGattCharacteristic2;
|
||||
final blueZCharacteristic = myCharacteristic.characteristic;
|
||||
final blueZValue = await blueZCharacteristic.readValue();
|
||||
return Uint8List.fromList(blueZValue);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> writeCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
required Uint8List value,
|
||||
required GattCharacteristicWriteType type,
|
||||
}) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myCharacteristic = characteristic as MyGattCharacteristic2;
|
||||
final blueZCharacteristic = myCharacteristic.characteristic;
|
||||
await blueZCharacteristic.writeValue(
|
||||
value,
|
||||
type: type.toBlueZWriteType(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> notifyCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
required bool state,
|
||||
}) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myCharacteristic = characteristic as MyGattCharacteristic2;
|
||||
final blueZCharacteristic = myCharacteristic.characteristic;
|
||||
if (state) {
|
||||
await blueZCharacteristic.startNotify();
|
||||
} else {
|
||||
await blueZCharacteristic.stopNotify();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readDescriptor(GattDescriptor descriptor) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myDescriptor = descriptor as MyGattDescriptor2;
|
||||
final blueZDescriptor = myDescriptor.descriptor;
|
||||
final blueZValue = await blueZDescriptor.readValue();
|
||||
return Uint8List.fromList(blueZValue);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> writeDescriptor(
|
||||
GattDescriptor descriptor, {
|
||||
required Uint8List value,
|
||||
}) async {
|
||||
await _throwWithoutState(BluetoothLowEnergyState.poweredOn);
|
||||
final myDescriptor = descriptor as MyGattDescriptor2;
|
||||
final blueZDescriptor = myDescriptor.descriptor;
|
||||
await blueZDescriptor.writeValue(value);
|
||||
}
|
||||
|
||||
void _onAdapterPropertiesChanged(List<String> properties) {
|
||||
for (var property in properties) {
|
||||
switch (property) {
|
||||
case 'Powered':
|
||||
final myState = _adapter.myState;
|
||||
if (_state == myState) {
|
||||
return;
|
||||
}
|
||||
_state = myState;
|
||||
final eventArgs = BluetoothLowEnergyStateChangedEventArgs(myState);
|
||||
_stateChangedController.add(eventArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _onDeviceAdded(BlueZDevice device) {
|
||||
if (device.adapter.address != _adapter.address) {
|
||||
return;
|
||||
}
|
||||
_onDiscovered(device);
|
||||
_beginDevicePropertiesChangedListener(device);
|
||||
}
|
||||
|
||||
void _onDiscovered(BlueZDevice device) {
|
||||
final myPeripheral = MyPeripheral2(device);
|
||||
final myRSSI = device.rssi;
|
||||
final myAdvertiseData = device.myAdvertiseData;
|
||||
final eventArgs = DiscoveredEventArgs(
|
||||
myPeripheral,
|
||||
myRSSI,
|
||||
myAdvertiseData,
|
||||
);
|
||||
_discoveredController.add(eventArgs);
|
||||
}
|
||||
|
||||
void _beginDevicePropertiesChangedListener(BlueZDevice device) {
|
||||
device.propertiesChanged.listen((properties) {
|
||||
for (var property in properties) {
|
||||
switch (property) {
|
||||
case 'RSSI':
|
||||
_onDiscovered(device);
|
||||
break;
|
||||
case 'Connected':
|
||||
final myPeripheral = MyPeripheral2(device);
|
||||
final state = device.connected;
|
||||
final eventArgs = PeripheralStateChangedEventArgs(
|
||||
myPeripheral,
|
||||
state,
|
||||
);
|
||||
_peripheralStateChangedController.add(eventArgs);
|
||||
if (!state) {
|
||||
_endCharacteristicPropertiesChangedListener(myPeripheral);
|
||||
}
|
||||
break;
|
||||
case 'UUIDs':
|
||||
break;
|
||||
case 'ServicesResolved':
|
||||
if (device.servicesResolved) {
|
||||
final myPeripheral = MyPeripheral2(device);
|
||||
_endCharacteristicPropertiesChangedListener(myPeripheral);
|
||||
final myServices = device.myServices;
|
||||
_myServicesOfMyPeripherals[myPeripheral.hashCode] = myServices;
|
||||
_beginCharacteristicPropertiesChangedListener(myPeripheral);
|
||||
final eventArgs = BlueZDeviceServicesResolvedEventArgs(device);
|
||||
_deviceServicesResolvedController.add(eventArgs);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _beginCharacteristicPropertiesChangedListener(
|
||||
MyPeripheral myPeripheral,
|
||||
) {
|
||||
final myServices = _myServicesOfMyPeripherals[myPeripheral.hashCode];
|
||||
if (myServices == null) {
|
||||
throw ArgumentError.notNull();
|
||||
}
|
||||
for (var myService in myServices) {
|
||||
final myCharacteristics =
|
||||
myService.characteristics.cast<MyGattCharacteristic2>();
|
||||
for (var myCharacteristic in myCharacteristics) {
|
||||
final characteristic = myCharacteristic.characteristic;
|
||||
final subscription = characteristic.propertiesChanged.listen(
|
||||
(properties) {
|
||||
for (var property in properties) {
|
||||
switch (property) {
|
||||
case 'Value':
|
||||
final myValue = Uint8List.fromList(characteristic.value);
|
||||
final eventArgs = GattCharacteristicValueChangedEventArgs(
|
||||
myCharacteristic,
|
||||
myValue,
|
||||
);
|
||||
_characteristicValueChangedController.add(eventArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
_characteristicPropertiesChangedSubscriptions[
|
||||
myCharacteristic.hashCode] = subscription;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _endCharacteristicPropertiesChangedListener(MyPeripheral myPeripheral) {
|
||||
final myServices = _myServicesOfMyPeripherals.remove(myPeripheral.hashCode);
|
||||
if (myServices == null) {
|
||||
return;
|
||||
}
|
||||
for (var myService in myServices) {
|
||||
final myCharacteristics = myService.characteristics;
|
||||
for (var myCharacteristic in myCharacteristics) {
|
||||
final subscription = _characteristicPropertiesChangedSubscriptions
|
||||
.remove(myCharacteristic.hashCode);
|
||||
subscription?.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_peripheral.dart';
|
||||
class BlueZDeviceServicesResolvedEventArgs extends EventArgs {
|
||||
final BlueZDevice device;
|
||||
|
||||
class MyPeripheralDiscoveredEventArgs extends EventArgs {
|
||||
final MyPeripheral myPeripheral;
|
||||
|
||||
MyPeripheralDiscoveredEventArgs(this.myPeripheral);
|
||||
BlueZDeviceServicesResolvedEventArgs(this.device);
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
import 'my_object.dart';
|
||||
|
||||
class MyGattCharacteristic extends MyObject implements GattCharacteristic {
|
||||
final BlueZGattCharacteristic characteristic;
|
||||
|
||||
MyGattCharacteristic(this.characteristic) : super(characteristic);
|
||||
|
||||
@override
|
||||
UUID get uuid => characteristic.uuid.toUUID();
|
||||
|
||||
@override
|
||||
List<GattCharacteristicProperty> get properties => characteristic.properties;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
|
||||
class MyGattCharacteristic2 extends MyGattCharacteristic {
|
||||
final BlueZGattCharacteristic characteristic;
|
||||
|
||||
MyGattCharacteristic2(this.characteristic)
|
||||
: super(
|
||||
hashCode: characteristic.hashCode,
|
||||
uuid: characteristic.myUUID,
|
||||
properties: characteristic.myProperties,
|
||||
descriptors: characteristic.myDescriptors,
|
||||
);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
import 'my_object.dart';
|
||||
|
||||
class MyGattDescriptor extends MyObject implements GattDescriptor {
|
||||
final BlueZGattDescriptor descriptor;
|
||||
|
||||
MyGattDescriptor(this.descriptor) : super(descriptor);
|
||||
|
||||
@override
|
||||
UUID get uuid => descriptor.uuid.toUUID();
|
||||
}
|
14
bluetooth_low_energy_linux/lib/src/my_gatt_descriptor2.dart
Normal file
14
bluetooth_low_energy_linux/lib/src/my_gatt_descriptor2.dart
Normal file
@ -0,0 +1,14 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
|
||||
class MyGattDescriptor2 extends MyGattDescriptor {
|
||||
final BlueZGattDescriptor descriptor;
|
||||
|
||||
MyGattDescriptor2(this.descriptor)
|
||||
: super(
|
||||
hashCode: descriptor.hashCode,
|
||||
uuid: descriptor.myUUID,
|
||||
);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
import 'my_object.dart';
|
||||
|
||||
class MyGattService extends MyObject implements GattService {
|
||||
final BlueZGattService service;
|
||||
|
||||
MyGattService(this.service) : super(service);
|
||||
|
||||
@override
|
||||
UUID get uuid => service.uuid.toUUID();
|
||||
}
|
15
bluetooth_low_energy_linux/lib/src/my_gatt_service2.dart
Normal file
15
bluetooth_low_energy_linux/lib/src/my_gatt_service2.dart
Normal file
@ -0,0 +1,15 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
|
||||
class MyGattService2 extends MyGattService {
|
||||
final BlueZGattService service;
|
||||
|
||||
MyGattService2(this.service)
|
||||
: super(
|
||||
hashCode: service.hashCode,
|
||||
uuid: service.myUUID,
|
||||
characteristics: service.myCharacteristics,
|
||||
);
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
abstract class MyObject {
|
||||
@override
|
||||
final int hashCode;
|
||||
|
||||
MyObject(Object instance) : hashCode = instance.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MyObject && other.hashCode == hashCode;
|
||||
}
|
||||
}
|
@ -2,13 +2,13 @@ import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_pla
|
||||
import 'package:bluez/bluez.dart';
|
||||
|
||||
import 'my_bluez.dart';
|
||||
import 'my_object.dart';
|
||||
|
||||
class MyPeripheral extends MyObject implements Peripheral {
|
||||
class MyPeripheral2 extends MyPeripheral {
|
||||
final BlueZDevice device;
|
||||
|
||||
MyPeripheral(this.device) : super(device);
|
||||
|
||||
@override
|
||||
UUID get uuid => device.uuid.toUUID();
|
||||
MyPeripheral2(this.device)
|
||||
: super(
|
||||
hashCode: device.hashCode,
|
||||
uuid: device.myUUID,
|
||||
);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
name: bluetooth_low_energy_linux
|
||||
description: Linux implementation of the bluetooth_low_energy plugin.
|
||||
version: 2.2.0
|
||||
version: 3.0.0
|
||||
homepage: https://github.com/yanshouwang/bluetooth_low_energy
|
||||
|
||||
environment:
|
||||
@ -10,7 +10,7 @@ environment:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
bluetooth_low_energy_platform_interface: ^2.2.0
|
||||
bluetooth_low_energy_platform_interface: ^3.0.0
|
||||
bluez: ^0.8.1
|
||||
|
||||
dev_dependencies:
|
||||
|
Reference in New Issue
Block a user