From 79c50d638db6328edaf5d1b188b2dd31131079e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=E5=89=91=E4=BE=A0=E5=AE=A2?= Date: Tue, 10 Oct 2023 05:01:25 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=A4=96=E5=9B=B4?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E8=AE=BE=E5=A4=87=E6=8E=A5=E5=8F=A3=20(#18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 临时提交 * 临时提交 * 临时提交 * fix: 调整接口 * fix: 修复问题 * fix: 调整 iOS 实现 * fix: 添加注释 * fix: 修改预览版本号 * fix: 修复已知问题 * fix: 优化接口 * fix: 解决 32 位 UUID 报错问题 * fix: 修复问题 * fix: 修复依赖项 * fix: 移除多余代码 * fix: 修复已知问题 * fix: 修复问题 * fix: 修改版本号 * fix: 修复问题 * fix: 发布正式版本 --- bluetooth_low_energy/CHANGELOG.md | 39 + bluetooth_low_energy/README.md | 27 +- bluetooth_low_energy/example/lib/main.dart | 468 +++++++-- bluetooth_low_energy/example/pubspec.lock | 34 +- .../lib/bluetooth_low_energy.dart | 9 +- bluetooth_low_energy/pubspec.yaml | 15 +- bluetooth_low_energy_android/CHANGELOG.md | 45 + .../android/src/main/AndroidManifest.xml | 1 + .../BluetoothLowEnergyAndroid.kt | 34 +- .../MyAdvertiseCallback.kt | 16 + .../bluetooth_low_energy_android/MyApi.g.kt | 925 ++++++++++++----- .../bluetooth_low_energy_android/MyApi.kt | 233 +++++ .../MyBluetoothGattCallback.kt | 31 +- .../MyBluetoothGattServerCallback.kt | 59 ++ .../MyBluetoothLowEnergyManager.kt | 63 ++ .../MyBroadcastReceiver.kt | 4 +- .../MyCentralController.kt | 745 -------------- .../MyCentralManager.kt | 627 ++++++++++++ .../MyPeripheralManager.kt | 423 ++++++++ .../MyRequestPermissionResultListener.kt | 4 +- .../MyScanCallback.kt | 6 +- .../lib/bluetooth_low_energy_android.dart | 4 +- .../lib/src/my_api.dart | 224 +++++ .../lib/src/my_api.g.dart | 942 +++++++++++++----- .../lib/src/my_bluetooth_low_energy.dart | 15 + .../src/my_bluetooth_low_energy_manager.dart | 39 + .../lib/src/my_central_controller.dart | 366 ------- .../lib/src/my_central_manager.dart | 267 +++++ .../lib/src/my_gatt_characteristic.dart | 42 - .../lib/src/my_gatt_characteristic2.dart | 19 + .../lib/src/my_gatt_descriptor.dart | 22 - .../lib/src/my_gatt_descriptor2.dart | 12 + .../lib/src/my_gatt_service.dart | 22 - .../lib/src/my_gatt_service2.dart | 17 + .../lib/src/my_peripheral.dart | 17 - .../lib/src/my_peripheral_manager.dart | 228 +++++ bluetooth_low_energy_android/my_api.dart | 221 ++-- bluetooth_low_energy_android/pubspec.yaml | 6 +- bluetooth_low_energy_darwin/CHANGELOG.md | 34 + .../Classes/BluetoothLowEnergyDarwin.swift | 6 +- .../darwin/Classes/MyApi.g.swift | 817 ++++++++++----- .../darwin/Classes/MyApi.swift | 286 ++++++ .../darwin/Classes/MyCentralController.swift | 737 -------------- .../darwin/Classes/MyCentralManager.swift | 650 ++++++++++++ .../Classes/MyCentralManagerDelegate.swift | 19 +- .../darwin/Classes/MyPeripheralDelegate.swift | 26 +- .../darwin/Classes/MyPeripheralManager.swift | 375 +++++++ .../Classes/MyPeripheralManagerDelegate.swift | 49 + .../lib/bluetooth_low_energy_darwin.dart | 4 +- .../lib/src/my_api.dart | 224 +++++ .../lib/src/my_api.g.dart | 942 +++++++++++++----- .../lib/src/my_bluetooth_low_energy.dart | 15 + .../src/my_bluetooth_low_energy_manager.dart | 39 + .../lib/src/my_central_controller.dart | 370 ------- .../lib/src/my_central_manager.dart | 272 +++++ .../lib/src/my_gatt_characteristic.dart | 42 - .../lib/src/my_gatt_characteristic2.dart | 19 + .../lib/src/my_gatt_descriptor.dart | 22 - .../lib/src/my_gatt_descriptor2.dart | 12 + .../lib/src/my_gatt_service.dart | 22 - .../lib/src/my_gatt_service2.dart | 17 + .../lib/src/my_object.dart | 11 - .../lib/src/my_peripheral.dart | 17 - .../lib/src/my_peripheral_manager.dart | 228 +++++ bluetooth_low_energy_darwin/my_api.dart | 221 ++-- bluetooth_low_energy_darwin/pubspec.yaml | 6 +- bluetooth_low_energy_linux/CHANGELOG.md | 34 + .../lib/bluetooth_low_energy_linux.dart | 4 +- .../lib/src/my_bluetooth_low_energy.dart | 12 + .../lib/src/my_bluez.dart | 97 +- .../lib/src/my_central_controller.dart | 443 -------- .../lib/src/my_central_manager.dart | 342 +++++++ .../lib/src/my_event_args.dart | 9 +- .../lib/src/my_gatt_characteristic.dart | 17 - .../lib/src/my_gatt_characteristic2.dart | 16 + .../lib/src/my_gatt_descriptor.dart | 14 - .../lib/src/my_gatt_descriptor2.dart | 14 + .../lib/src/my_gatt_service.dart | 14 - .../lib/src/my_gatt_service2.dart | 15 + .../lib/src/my_object.dart | 11 - ...my_peripheral.dart => my_peripheral2.dart} | 12 +- bluetooth_low_energy_linux/pubspec.yaml | 4 +- .../CHANGELOG.md | 42 + ...uetooth_low_energy_platform_interface.dart | 18 +- ...advertisement.dart => advertise_data.dart} | 17 +- .../lib/src/bluetooth_low_energy.dart | 41 + .../lib/src/bluetooth_low_energy_manager.dart | 14 + .../lib/src/bluetooth_low_energy_peer.dart | 7 + .../lib/src/bluetooth_low_energy_state.dart | 17 + .../lib/src/central.dart | 4 + .../lib/src/central_controller.dart | 120 --- .../lib/src/central_manager.dart | 76 ++ .../lib/src/central_state.dart | 17 - .../lib/src/event_args.dart | 71 +- .../lib/src/gatt_attribute.dart | 7 + .../lib/src/gatt_characteristic.dart | 30 +- .../lib/src/gatt_descriptor.dart | 22 +- .../lib/src/gatt_service.dart | 23 +- .../lib/src/manufacturer_specific_data.dart | 16 + .../lib/src/my_central.dart | 13 + .../lib/src/my_gatt_characteristic.dart | 21 + .../lib/src/my_gatt_descriptor.dart | 17 + .../lib/src/my_gatt_service.dart | 17 + .../lib/src/my_object.dart | 8 +- .../lib/src/my_peripheral.dart | 13 + .../lib/src/peripheral.dart | 9 +- .../lib/src/peripheral_manager.dart | 73 ++ .../lib/src/uuid.dart | 12 +- .../pubspec.yaml | 2 +- .../lib/bluetooth_low_energy_windows.dart | 4 +- .../lib/src/my_bluetooth_low_energy.dart | 11 + .../lib/src/my_central_controller.dart | 128 --- bluetooth_low_energy_windows/pubspec.yaml | 4 +- 113 files changed, 9125 insertions(+), 4560 deletions(-) create mode 100644 bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyAdvertiseCallback.kt create mode 100644 bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.kt create mode 100644 bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattServerCallback.kt create mode 100644 bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothLowEnergyManager.kt delete mode 100644 bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralController.kt create mode 100644 bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralManager.kt create mode 100644 bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyPeripheralManager.kt create mode 100644 bluetooth_low_energy_android/lib/src/my_api.dart create mode 100644 bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy.dart create mode 100644 bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy_manager.dart delete mode 100644 bluetooth_low_energy_android/lib/src/my_central_controller.dart create mode 100644 bluetooth_low_energy_android/lib/src/my_central_manager.dart delete mode 100644 bluetooth_low_energy_android/lib/src/my_gatt_characteristic.dart create mode 100644 bluetooth_low_energy_android/lib/src/my_gatt_characteristic2.dart delete mode 100644 bluetooth_low_energy_android/lib/src/my_gatt_descriptor.dart create mode 100644 bluetooth_low_energy_android/lib/src/my_gatt_descriptor2.dart delete mode 100644 bluetooth_low_energy_android/lib/src/my_gatt_service.dart create mode 100644 bluetooth_low_energy_android/lib/src/my_gatt_service2.dart delete mode 100644 bluetooth_low_energy_android/lib/src/my_peripheral.dart create mode 100644 bluetooth_low_energy_android/lib/src/my_peripheral_manager.dart create mode 100644 bluetooth_low_energy_darwin/darwin/Classes/MyApi.swift delete mode 100644 bluetooth_low_energy_darwin/darwin/Classes/MyCentralController.swift create mode 100644 bluetooth_low_energy_darwin/darwin/Classes/MyCentralManager.swift create mode 100644 bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManager.swift create mode 100644 bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManagerDelegate.swift create mode 100644 bluetooth_low_energy_darwin/lib/src/my_api.dart create mode 100644 bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy.dart create mode 100644 bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy_manager.dart delete mode 100644 bluetooth_low_energy_darwin/lib/src/my_central_controller.dart create mode 100644 bluetooth_low_energy_darwin/lib/src/my_central_manager.dart delete mode 100644 bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic.dart create mode 100644 bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic2.dart delete mode 100644 bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor.dart create mode 100644 bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor2.dart delete mode 100644 bluetooth_low_energy_darwin/lib/src/my_gatt_service.dart create mode 100644 bluetooth_low_energy_darwin/lib/src/my_gatt_service2.dart delete mode 100644 bluetooth_low_energy_darwin/lib/src/my_object.dart delete mode 100644 bluetooth_low_energy_darwin/lib/src/my_peripheral.dart create mode 100644 bluetooth_low_energy_darwin/lib/src/my_peripheral_manager.dart create mode 100644 bluetooth_low_energy_linux/lib/src/my_bluetooth_low_energy.dart delete mode 100644 bluetooth_low_energy_linux/lib/src/my_central_controller.dart create mode 100644 bluetooth_low_energy_linux/lib/src/my_central_manager.dart delete mode 100644 bluetooth_low_energy_linux/lib/src/my_gatt_characteristic.dart create mode 100644 bluetooth_low_energy_linux/lib/src/my_gatt_characteristic2.dart delete mode 100644 bluetooth_low_energy_linux/lib/src/my_gatt_descriptor.dart create mode 100644 bluetooth_low_energy_linux/lib/src/my_gatt_descriptor2.dart delete mode 100644 bluetooth_low_energy_linux/lib/src/my_gatt_service.dart create mode 100644 bluetooth_low_energy_linux/lib/src/my_gatt_service2.dart delete mode 100644 bluetooth_low_energy_linux/lib/src/my_object.dart rename bluetooth_low_energy_linux/lib/src/{my_peripheral.dart => my_peripheral2.dart} (51%) rename bluetooth_low_energy_platform_interface/lib/src/{advertisement.dart => advertise_data.dart} (61%) create mode 100644 bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_manager.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_peer.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_state.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/central.dart delete mode 100644 bluetooth_low_energy_platform_interface/lib/src/central_controller.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/central_manager.dart delete mode 100644 bluetooth_low_energy_platform_interface/lib/src/central_state.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/gatt_attribute.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/manufacturer_specific_data.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/my_central.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/my_gatt_characteristic.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/my_gatt_descriptor.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/my_gatt_service.dart rename {bluetooth_low_energy_android => bluetooth_low_energy_platform_interface}/lib/src/my_object.dart (54%) create mode 100644 bluetooth_low_energy_platform_interface/lib/src/my_peripheral.dart create mode 100644 bluetooth_low_energy_platform_interface/lib/src/peripheral_manager.dart create mode 100644 bluetooth_low_energy_windows/lib/src/my_bluetooth_low_energy.dart delete mode 100644 bluetooth_low_energy_windows/lib/src/my_central_controller.dart diff --git a/bluetooth_low_energy/CHANGELOG.md b/bluetooth_low_energy/CHANGELOG.md index 62c8036..4210af3 100644 --- a/bluetooth_low_energy/CHANGELOG.md +++ b/bluetooth_low_energy/CHANGELOG.md @@ -1,3 +1,42 @@ +## 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` 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. +* Fix known issues. + +## 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` 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 + +* Add `PeripheralManager` api. +* Add `CentralManager#readRSSI` method. +* Move `CentralController` to `CentralManager`. +* Move `CentralState` to `BluetoothLowEnergyState`. +* Move `CentralDiscoveredEventArgs` to `DiscoveredEventArgs`. + ## 2.2.1 * `Android` Fix the issue that `CentralController#getMaximumWriteLength` may throw. diff --git a/bluetooth_low_energy/README.md b/bluetooth_low_energy/README.md index c401d9c..69c38cb 100644 --- a/bluetooth_low_energy/README.md +++ b/bluetooth_low_energy/README.md @@ -4,12 +4,14 @@ A Flutter plugin for controlling the bluetooth low energy. ## Features -### CentralController +### CentralManager -- [x] SetUp/TearDown central controller. -- [x] Get/Listen central state. +- [x] Set up the central manager. +- [x] Get/Listen the state of the central manager. - [x] Start/Stop discovery. - [x] Connect/Disconnect peripherals. +- [x] Get maximum write length of peripherals. +- [x] Read RSSI of peripherals. - [x] Discover GATT. - [x] Get GATT services. - [x] Get GATT characteristics. @@ -17,6 +19,17 @@ A Flutter plugin for controlling the bluetooth low energy. - [x] Read/Write/Notify GATT characteristics. - [x] Read/Write GATT descriptors. +### PeripheralManager + +- [x] Set up the peripheral manager. +- [x] Get/Listen the state of the peripheral manager. +- [x] Add/Remove/Clear service(s). +- [x] Start/Stop advertising. +- [x] Get maximum write length of centrals. +- [x] Listen read/write/notify characteristic requests from centrals. +- [x] Send read/write characteristic replies to centrals. +- [x] Notify characteristic value changed to centrals. + ## Getting Started Add `bluetooth_low_energy` as a [dependency in your pubspec.yaml file](https://flutter.dev/using-packages/). @@ -28,20 +41,26 @@ dependencies: Remember to call `await CentralController.setUp()` before use any apis of this plugin. -*Note*: Bluetooth Low Energy doesn't work on emulators, so use physical devices which has bluetooth features for development. +*Note:* Bluetooth Low Energy doesn't work on emulators, so use physical devices which has bluetooth features for development. ### Android Make sure you have a `miniSdkVersion` with 21 or higher in your `android/app/build.gradle` file. +*Note:* Don't call `getMaximumWriteLength` immediately when connected to a peripheral after Android 13, the `onMtuChanged` callback maybe called with connection events after Android 13, and `getMaximumWriteLength` will call `requestMtu` will also triggered `onMtuChanged`, if you called this before the connection `onMtuChanged`, you will get a fake completion and cause all methods you called before the real `onMtuChanged` triggered will never complete! + ### iOS and macOS According to Apple's [documents](https://developer.apple.com/documentation/corebluetooth/), you must include the [`NSBluetoothAlwaysUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nsbluetoothalwaysusagedescription) on or after iOS 13, and include the [`NSBluetoothPeripheralUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nsbluetoothperipheralusagedescription) key before iOS 13. +The `PeripheralManager#startAdvertising` only support `name` and `serviceUUIDs`, see [the startAdvertising document](https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393252-startadvertising) + ### Linux Not tested enough, if you occured any problems, file an issue to let me know about it, i will fix it as soon as possible. +PeripheralManager api is not supported because the `bluez` plugin doesn't support this yet, see [How to use bluez to act as bluetooth peripheral](https://github.com/canonical/bluez.dart/issues/85) + ### Windows Not implemented yet but maybe someday or someone can use the `win32` api to implement this plugin_interface or someday the flutter team support C# on windows platform or someday I am familiar with C++ language... diff --git a/bluetooth_low_energy/example/lib/main.dart b/bluetooth_low_energy/example/lib/main.dart index 284696a..3217ee7 100644 --- a/bluetooth_low_energy/example/lib/main.dart +++ b/bluetooth_low_energy/example/lib/main.dart @@ -14,6 +14,9 @@ void main() { } void onStartUp() async { + WidgetsFlutterBinding.ensureInitialized(); + await CentralManager.instance.setUp(); + await PeripheralManager.instance.setUp(); runApp(const MyApp()); } @@ -48,8 +51,7 @@ class _MyAppState extends State { routes: { 'peripheral': (context) { final route = ModalRoute.of(context); - final eventArgs = - route!.settings.arguments as CentralDiscoveredEventArgs; + final eventArgs = route!.settings.arguments as DiscoveredEventArgs; return PeripheralView( eventArgs: eventArgs, ); @@ -67,26 +69,104 @@ class HomeView extends StatefulWidget { } class _HomeViewState extends State { - CentralController get centralController => CentralController.instance; - late final ValueNotifier state; + late final PageController controller; + + @override + void initState() { + super.initState(); + controller = PageController(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: buildBody(context), + bottomNavigationBar: buildBottomNavigationBar(context), + ); + } + + Widget buildBody(BuildContext context) { + return PageView.builder( + controller: controller, + itemBuilder: (context, i) { + switch (i) { + case 0: + return const ScannerView(); + case 1: + return const AdvertiserView(); + default: + throw ArgumentError.value(i); + } + }, + itemCount: 2, + ); + } + + Widget buildBottomNavigationBar(BuildContext context) { + return ListenableBuilder( + listenable: controller, + builder: (context, child) { + return BottomNavigationBar( + onTap: (i) { + const duration = Duration(milliseconds: 300); + const curve = Curves.ease; + controller.animateToPage( + i, + duration: duration, + curve: curve, + ); + }, + currentIndex: controller.page?.toInt() ?? 0, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.radar), + label: 'scanner', + ), + BottomNavigationBarItem( + icon: Icon(Icons.sensors), + label: 'advertiser', + ), + ], + ); + }, + ); + } + + @override + void dispose() { + super.dispose(); + controller.dispose(); + } +} + +CentralManager get centralManager => CentralManager.instance; + +class ScannerView extends StatefulWidget { + const ScannerView({super.key}); + + @override + State createState() => _ScannerViewState(); +} + +class _ScannerViewState extends State { + late final ValueNotifier state; late final ValueNotifier discovering; - late final ValueNotifier> - discoveredEventArgs; + late final ValueNotifier> discoveredEventArgs; late final StreamSubscription stateChangedSubscription; late final StreamSubscription discoveredSubscription; @override void initState() { super.initState(); - state = ValueNotifier(centralController.state); + state = ValueNotifier(centralManager.state); discovering = ValueNotifier(false); discoveredEventArgs = ValueNotifier([]); - stateChangedSubscription = centralController.stateChanged.listen( + stateChangedSubscription = centralManager.stateChanged.listen( (eventArgs) { state.value = eventArgs.state; }, ); - discoveredSubscription = centralController.discovered.listen( + discoveredSubscription = centralManager.discovered.listen( (eventArgs) { final items = discoveredEventArgs.value; final i = items.indexWhere( @@ -100,22 +180,6 @@ class _HomeViewState extends State { } }, ); - setUp(); - } - - void setUp() async { - await centralController.setUp(); - state.value = centralController.state; - } - - Future startDiscovery() async { - await centralController.startDiscovery(); - discovering.value = true; - } - - Future stopDiscovery() async { - await centralController.stopDiscovery(); - discovering.value = false; } @override @@ -128,7 +192,7 @@ class _HomeViewState extends State { PreferredSizeWidget buildAppBar(BuildContext context) { return AppBar( - title: const Text('Bluetooth LowEnergy'), + title: const Text('Scanner'), actions: [ ValueListenableBuilder( valueListenable: state, @@ -137,7 +201,7 @@ class _HomeViewState extends State { valueListenable: discovering, builder: (context, discovering, child) { return TextButton( - onPressed: state == CentralState.poweredOn + onPressed: state == BluetoothLowEnergyState.poweredOn ? () async { if (discovering) { await stopDiscovery(); @@ -158,13 +222,23 @@ class _HomeViewState extends State { ); } + Future startDiscovery() async { + await centralManager.startDiscovery(); + discovering.value = true; + } + + Future stopDiscovery() async { + await centralManager.stopDiscovery(); + discovering.value = false; + } + Widget buildBody(BuildContext context) { return ValueListenableBuilder( valueListenable: discoveredEventArgs, builder: (context, discoveredEventArgs, child) { // final items = discoveredEventArgs; final items = discoveredEventArgs - .where((eventArgs) => eventArgs.advertisement.name != null) + .where((eventArgs) => eventArgs.advertiseData.name != null) .toList(); return ListView.separated( itemBuilder: (context, i) { @@ -172,8 +246,8 @@ class _HomeViewState extends State { final item = items[i]; final uuid = item.peripheral.uuid; final rssi = item.rssi; - final advertisement = item.advertisement; - final name = advertisement.name; + final advertiseData = item.advertiseData; + final name = advertiseData.name; return ListTile( onTap: () async { final discovering = this.discovering.value; @@ -200,7 +274,7 @@ class _HomeViewState extends State { clipBehavior: Clip.antiAlias, builder: (context) { final manufacturerSpecificData = - advertisement.manufacturerSpecificData; + advertiseData.manufacturerSpecificData; return ListView.separated( padding: const EdgeInsets.symmetric( horizontal: 16.0, @@ -221,11 +295,10 @@ class _HomeViewState extends State { ], ); } else { - final entry = manufacturerSpecificData.entries - .elementAt(i - 1); final id = - '0x${entry.key.toRadixString(16).padLeft(4, '0')}'; - final value = hex.encode(entry.value); + '0x${manufacturerSpecificData!.id.toRadixString(16).padLeft(4, '0')}'; + final value = + hex.encode(manufacturerSpecificData.data); return Row( children: [ SizedBox( @@ -242,7 +315,7 @@ class _HomeViewState extends State { separatorBuilder: (context, i) { return const Divider(); }, - itemCount: manufacturerSpecificData.length + 1, + itemCount: manufacturerSpecificData == null ? 1 : 2, ); }, ); @@ -274,7 +347,6 @@ class _HomeViewState extends State { @override void dispose() { super.dispose(); - centralController.tearDown().ignore(); stateChangedSubscription.cancel(); discoveredSubscription.cancel(); state.dispose(); @@ -284,7 +356,7 @@ class _HomeViewState extends State { } class PeripheralView extends StatefulWidget { - final CentralDiscoveredEventArgs eventArgs; + final DiscoveredEventArgs eventArgs; const PeripheralView({ super.key, @@ -296,9 +368,8 @@ class PeripheralView extends StatefulWidget { } class _PeripheralViewState extends State { - CentralController get centralController => CentralController.instance; late final ValueNotifier state; - late final CentralDiscoveredEventArgs eventArgs; + late final DiscoveredEventArgs eventArgs; late final ValueNotifier> services; late final ValueNotifier> characteristics; late final ValueNotifier service; @@ -323,7 +394,7 @@ class _PeripheralViewState extends State { maximumWriteLength = ValueNotifier(20); logs = ValueNotifier([]); writeController = TextEditingController(); - stateChangedSubscription = centralController.peripheralStateChanged.listen( + stateChangedSubscription = centralManager.peripheralStateChanged.listen( (eventArgs) { if (eventArgs.peripheral != this.eventArgs.peripheral) { return; @@ -339,8 +410,7 @@ class _PeripheralViewState extends State { } }, ); - valueChangedSubscription = - centralController.characteristicValueChanged.listen( + valueChangedSubscription = centralManager.characteristicValueChanged.listen( (eventArgs) { final characteristic = this.characteristic.value; if (eventArgs.characteristic != characteristic) { @@ -362,7 +432,7 @@ class _PeripheralViewState extends State { onWillPop: () async { if (state.value) { final peripheral = eventArgs.peripheral; - await centralController.disconnect(peripheral); + await centralManager.disconnect(peripheral); } return true; }, @@ -374,7 +444,7 @@ class _PeripheralViewState extends State { } PreferredSizeWidget buildAppBar(BuildContext context) { - final title = eventArgs.advertisement.name ?? ''; + final title = eventArgs.advertiseData.name ?? ''; return AppBar( title: Text(title), actions: [ @@ -385,12 +455,11 @@ class _PeripheralViewState extends State { onPressed: () async { final peripheral = eventArgs.peripheral; if (state) { - await centralController.disconnect(peripheral); + await centralManager.disconnect(peripheral); } else { - await centralController.connect(peripheral); - await centralController.discoverGATT(peripheral); + await centralManager.connect(peripheral); services.value = - await centralController.getServices(peripheral); + await centralManager.discoverGATT(peripheral); } }, child: Text(state ? 'DISCONNECT' : 'CONNECT'), @@ -436,8 +505,7 @@ class _PeripheralViewState extends State { if (service == null) { return; } - characteristics.value = - await centralController.getCharacteristics(service); + characteristics.value = service.characteristics; }, ); }, @@ -563,7 +631,7 @@ class _PeripheralViewState extends State { onPressed: state ? () async { maximumWriteLength.value = - await centralController.getMaximumWriteLength( + await centralManager.getMaximumWriteLength( eventArgs.peripheral, type: writeType.value, ); @@ -579,6 +647,14 @@ class _PeripheralViewState extends State { }, ), ), + IconButton( + onPressed: () async { + final rssi = + await centralManager.readRSSI(eventArgs.peripheral); + print('RSSI: $rssi'); + }, + icon: const Icon(Icons.signal_wifi_4_bar), + ), ], ), Container( @@ -627,7 +703,7 @@ class _PeripheralViewState extends State { TextButton( onPressed: characteristic != null && canNotify ? () async { - await centralController.notifyCharacteristic( + await centralManager.notifyCharacteristic( characteristic, state: true, ); @@ -638,7 +714,7 @@ class _PeripheralViewState extends State { TextButton( onPressed: characteristic != null && canRead ? () async { - final value = await centralController + final value = await centralManager .readCharacteristic(characteristic); const type = LogType.read; final log = Log(type, value); @@ -653,7 +729,7 @@ class _PeripheralViewState extends State { final text = writeController.text; final elements = utf8.encode(text); final value = Uint8List.fromList(elements); - await centralController.writeCharacteristic( + await centralManager.writeCharacteristic( characteristic, value: value, type: GattCharacteristicWriteType @@ -694,12 +770,286 @@ class _PeripheralViewState extends State { } } +PeripheralManager get peripheralManager => PeripheralManager.instance; + +class AdvertiserView extends StatefulWidget { + const AdvertiserView({super.key}); + + @override + State createState() => _AdvertiserViewState(); +} + +class _AdvertiserViewState extends State { + late final ValueNotifier state; + late final ValueNotifier advertising; + late final ValueNotifier> logs; + late final StreamSubscription stateChangedSubscription; + late final StreamSubscription readCharacteristicCommandReceivedSubscription; + late final StreamSubscription writeCharacteristicCommandReceivedSubscription; + late final StreamSubscription notifyCharacteristicCommandReceivedSubscription; + + @override + void initState() { + super.initState(); + state = ValueNotifier(peripheralManager.state); + advertising = ValueNotifier(false); + logs = ValueNotifier([]); + stateChangedSubscription = peripheralManager.stateChanged.listen( + (eventArgs) { + state.value = eventArgs.state; + }, + ); + readCharacteristicCommandReceivedSubscription = + peripheralManager.readCharacteristicCommandReceived.listen( + (eventArgs) async { + final central = eventArgs.central; + final characteristic = eventArgs.characteristic; + final id = eventArgs.id; + final offset = eventArgs.offset; + final log = Log( + LogType.read, + Uint8List.fromList([]), + 'central: ${central.uuid}; characteristic: ${characteristic.uuid}; id: $id; offset: $offset', + ); + logs.value = [ + ...logs.value, + log, + ]; + // final maximumWriteLength = peripheralManager.getMaximumWriteLength( + // central, + // ); + const status = true; + final value = Uint8List.fromList([0x01, 0x02, 0x03]); + await peripheralManager.sendReadCharacteristicReply( + central, + characteristic, + id, + offset, + status, + value, + ); + }, + ); + writeCharacteristicCommandReceivedSubscription = + peripheralManager.writeCharacteristicCommandReceived.listen( + (eventArgs) async { + final central = eventArgs.central; + final characteristic = eventArgs.characteristic; + final id = eventArgs.id; + final offset = eventArgs.offset; + final value = eventArgs.value; + final log = Log( + LogType.write, + value, + 'central: ${central.uuid}; characteristic: ${characteristic.uuid}; id: $id; offset: $offset', + ); + logs.value = [ + ...logs.value, + log, + ]; + const status = true; + await peripheralManager.sendWriteCharacteristicReply( + central, + characteristic, + id, + offset, + status, + ); + }, + ); + notifyCharacteristicCommandReceivedSubscription = + peripheralManager.notifyCharacteristicCommandReceived.listen( + (eventArgs) async { + final central = eventArgs.central; + final characteristic = eventArgs.characteristic; + final state = eventArgs.state; + final log = Log( + LogType.write, + Uint8List.fromList([]), + 'central: ${central.uuid}; characteristic: ${characteristic.uuid}; state: $state', + ); + logs.value = [ + ...logs.value, + log, + ]; + // Write someting to the central when notify started. + if (state) { + final value = Uint8List.fromList([0x03, 0x02, 0x01]); + await peripheralManager.notifyCharacteristicValueChanged( + central, + characteristic, + value, + ); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: buildAppBar(context), + body: buildBody(context), + ); + } + + PreferredSizeWidget buildAppBar(BuildContext context) { + return AppBar( + title: const Text('Advertiser'), + actions: [ + ValueListenableBuilder( + valueListenable: state, + builder: (context, state, child) { + return ValueListenableBuilder( + valueListenable: advertising, + builder: (context, advertising, child) { + return TextButton( + onPressed: state == BluetoothLowEnergyState.poweredOn + ? () async { + if (advertising) { + await stopAdvertising(); + } else { + await startAdvertising(); + } + } + : null, + child: Text( + advertising ? 'END' : 'BEGIN', + ), + ); + }, + ); + }, + ), + ], + ); + } + + Future startAdvertising() async { + await peripheralManager.clearServices(); + final service = GattService( + uuid: UUID.short(100), + characteristics: [ + GattCharacteristic( + uuid: UUID.short(200), + properties: [ + GattCharacteristicProperty.read, + ], + descriptors: [], + ), + GattCharacteristic( + uuid: UUID.short(201), + properties: [ + GattCharacteristicProperty.read, + GattCharacteristicProperty.write, + GattCharacteristicProperty.writeWithoutResponse, + ], + descriptors: [], + ), + GattCharacteristic( + uuid: UUID.short(202), + properties: [ + GattCharacteristicProperty.notify, + GattCharacteristicProperty.indicate, + ], + descriptors: [], + ), + ], + ); + await peripheralManager.addService(service); + final advertiseData = AdvertiseData( + name: 'flutter', + manufacturerSpecificData: ManufacturerSpecificData( + id: 0x2e19, + data: Uint8List.fromList([0x01, 0x02, 0x03]), + ), + ); + await peripheralManager.startAdvertising(advertiseData); + advertising.value = true; + } + + Future stopAdvertising() async { + await peripheralManager.stopAdvertising(); + advertising.value = false; + } + + Widget buildBody(BuildContext context) { + final theme = Theme.of(context); + return ValueListenableBuilder( + valueListenable: logs, + builder: (context, logs, child) { + return ListView.builder( + itemBuilder: (context, i) { + final log = logs[i]; + final type = log.type.name.toUpperCase().characters.first; + final Color typeColor; + switch (log.type) { + case LogType.read: + typeColor = Colors.blue; + break; + case LogType.write: + typeColor = Colors.amber; + break; + case LogType.notify: + typeColor = Colors.red; + break; + default: + typeColor = Colors.black; + } + final time = DateFormat.Hms().format(log.time); + final value = log.value; + final message = '${log.detail}; ${hex.encode(value)}'; + return Text.rich( + TextSpan( + text: '[$type:${value.length}]', + children: [ + TextSpan( + text: ' $time: ', + style: theme.textTheme.bodyMedium?.copyWith( + color: Colors.green, + ), + ), + TextSpan( + text: message, + style: theme.textTheme.bodyMedium, + ), + ], + style: theme.textTheme.bodyMedium?.copyWith( + color: typeColor, + ), + ), + ); + }, + itemCount: logs.length, + ); + }, + ); + } + + @override + void dispose() { + super.dispose(); + stateChangedSubscription.cancel(); + readCharacteristicCommandReceivedSubscription.cancel(); + writeCharacteristicCommandReceivedSubscription.cancel(); + notifyCharacteristicCommandReceivedSubscription.cancel(); + state.dispose(); + advertising.dispose(); + logs.dispose(); + } +} + class Log { final DateTime time; final LogType type; final Uint8List value; + final String? detail; - Log(this.type, this.value) : time = DateTime.now(); + Log( + this.type, + this.value, [ + this.detail, + ]) : time = DateTime.now(); @override String toString() { @@ -707,7 +1057,11 @@ class Log { final formatter = DateFormat.Hms(); final time = formatter.format(this.time); final message = hex.encode(value); - return '[$type]$time: $message'; + if (detail == null) { + return '[$type]$time: $message'; + } else { + return '[$type]$time: $message /* $detail */'; + } } } diff --git a/bluetooth_low_energy/example/pubspec.lock b/bluetooth_low_energy/example/pubspec.lock index 277f64e..8e4a2ff 100644 --- a/bluetooth_low_energy/example/pubspec.lock +++ b/bluetooth_low_energy/example/pubspec.lock @@ -23,47 +23,39 @@ packages: path: ".." relative: true source: path - version: "2.2.1" + version: "3.0.0" bluetooth_low_energy_android: dependency: transitive description: name: bluetooth_low_energy_android - sha256: "2098167f30a05cff40313fd49c459d326590b54dc6ea953cbe7ff145ce940e04" + sha256: "227468652811e769d7ff8836aa5c3f7bd0455246785c3eaf0fab2b3c31daed16" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "3.0.0" bluetooth_low_energy_darwin: dependency: transitive description: name: bluetooth_low_energy_darwin - sha256: "876f2d4a288739091296bc22ea574e64451f592154e4201b5999f174120a8b55" + sha256: f19903e1ad14da6a16de57996ca808064cb690add8b0aecc6ffecdf8da6f7eab url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "3.0.0" bluetooth_low_energy_linux: dependency: transitive description: name: bluetooth_low_energy_linux - sha256: dc3062991e0a408941829326f0a3b2e1244a8138dca7f6c4c6beadbc26deecb2 + sha256: "31a23704a4b34e7f6cea61d94c24b3e1c6698928645aaeaf1af947e4870996d7" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "3.0.0" bluetooth_low_energy_platform_interface: dependency: transitive description: name: bluetooth_low_energy_platform_interface - sha256: eecaa2c37ebd536339c292d5566cf4360c9ea3861188342791eb3a0cf65cc64c + sha256: "200e686247808591b6d3e355642ba296f0f651466c72efdd701be34116971473" url: "https://pub.dev" source: hosted - version: "2.2.0" - bluetooth_low_energy_windows: - dependency: transitive - description: - name: bluetooth_low_energy_windows - sha256: a1b5d5d5ad935f15618e6a86334c1ec682c40ffbe6a78173c3f19b67ff0edcfb - url: "https://pub.dev" - source: hosted - version: "2.2.0" + version: "3.0.0" bluez: dependency: transitive description: @@ -366,14 +358,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" - win32: - dependency: transitive - description: - name: win32 - sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" - url: "https://pub.dev" - source: hosted - version: "5.0.7" xml: dependency: transitive description: diff --git a/bluetooth_low_energy/lib/bluetooth_low_energy.dart b/bluetooth_low_energy/lib/bluetooth_low_energy.dart index bc504e4..8c822b5 100644 --- a/bluetooth_low_energy/lib/bluetooth_low_energy.dart +++ b/bluetooth_low_energy/lib/bluetooth_low_energy.dart @@ -1 +1,8 @@ -export 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; +export 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart' + hide + MyObject, + MyCentral, + MyPeripheral, + MyGattService, + MyGattCharacteristic, + MyGattDescriptor; diff --git a/bluetooth_low_energy/pubspec.yaml b/bluetooth_low_energy/pubspec.yaml index 513b060..40bcd30 100644 --- a/bluetooth_low_energy/pubspec.yaml +++ b/bluetooth_low_energy/pubspec.yaml @@ -1,20 +1,19 @@ name: bluetooth_low_energy description: A Flutter plugin for controlling the bluetooth low energy. -version: 2.2.1 +version: 3.0.0 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: - sdk: '>=3.0.0 <4.0.0' + sdk: ">=3.0.0 <4.0.0" flutter: ">=3.3.0" dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.2.0 - bluetooth_low_energy_android: ^2.2.1 - bluetooth_low_energy_darwin: ^2.2.0 - bluetooth_low_energy_linux: ^2.2.0 - bluetooth_low_energy_windows: ^2.2.0 + bluetooth_low_energy_platform_interface: ^3.0.0 + bluetooth_low_energy_android: ^3.0.0 + bluetooth_low_energy_darwin: ^3.0.0 + bluetooth_low_energy_linux: ^3.0.0 dev_dependencies: flutter_test: @@ -32,5 +31,3 @@ flutter: default_package: bluetooth_low_energy_darwin linux: default_package: bluetooth_low_energy_linux - windows: - default_package: bluetooth_low_energy_windows diff --git a/bluetooth_low_energy_android/CHANGELOG.md b/bluetooth_low_energy_android/CHANGELOG.md index d4c55a5..4d9395f 100644 --- a/bluetooth_low_energy_android/CHANGELOG.md +++ b/bluetooth_low_energy_android/CHANGELOG.md @@ -1,3 +1,48 @@ +## 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` 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.6 + +* Add default `CCCD` to GATT characteristic for notify and indicate. +* Fix the issue that callbacks must run on ui thread. +* Change requested MTU from 512 to 517 when get the maximum write length of characteristic. + +## 3.0.0-dev.5 + +* Fix the issue that the `BLUETOOTH_ADVERTISE` permission is not requested. + +## 3.0.0-dev.4 + +* Move `Advertisement` class to `AdvertiseData` class. +* Fix known issues. + +## 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` 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 api. + ## 2.2.1 * Fix the issue that `CentralController#getMaximumWriteLength` may throw. diff --git a/bluetooth_low_energy_android/android/src/main/AndroidManifest.xml b/bluetooth_low_energy_android/android/src/main/AndroidManifest.xml index 0f9ea98..f16b78f 100644 --- a/bluetooth_low_energy_android/android/src/main/AndroidManifest.xml +++ b/bluetooth_low_energy_android/android/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ + \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/BluetoothLowEnergyAndroid.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/BluetoothLowEnergyAndroid.kt index 974347b..bdd3b6d 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/BluetoothLowEnergyAndroid.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/BluetoothLowEnergyAndroid.kt @@ -6,33 +6,39 @@ import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding /** BluetoothLowEnergyAndroid */ class BluetoothLowEnergyAndroid : FlutterPlugin, ActivityAware { - private lateinit var centralController: MyCentralController + private lateinit var centralManager: MyCentralManager + private lateinit var peripheralManager: MyPeripheralManager override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { val context = binding.applicationContext val binaryMessenger = binding.binaryMessenger - centralController = MyCentralController(context, binaryMessenger) - MyCentralControllerHostApi.setUp(binaryMessenger, centralController) + centralManager = MyCentralManager(context, binaryMessenger) + peripheralManager = MyPeripheralManager(context, binaryMessenger) + MyCentralManagerHostApi.setUp(binaryMessenger, centralManager) + MyPeripheralManagerHostApi.setUp(binaryMessenger, peripheralManager) } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { val binaryMessenger = binding.binaryMessenger - MyCentralControllerHostApi.setUp(binaryMessenger, null) + MyCentralManagerHostApi.setUp(binaryMessenger, null) + MyPeripheralManagerHostApi.setUp(binaryMessenger, null) } override fun onAttachedToActivity(binding: ActivityPluginBinding) { - centralController.onAttachedToActivity(binding) - } - - override fun onDetachedFromActivityForConfigChanges() { - centralController.onDetachedFromActivity() - } - - override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { - centralController.onAttachedToActivity(binding) + centralManager.onAttachedToActivity(binding) + peripheralManager.onAttachedToActivity(binding) } override fun onDetachedFromActivity() { - centralController.onDetachedFromActivity() + centralManager.onDetachedFromActivity() + peripheralManager.onDetachedFromActivity() + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + onAttachedToActivity(binding) + } + + override fun onDetachedFromActivityForConfigChanges() { + onDetachedFromActivity() } } diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyAdvertiseCallback.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyAdvertiseCallback.kt new file mode 100644 index 0000000..59d2aff --- /dev/null +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyAdvertiseCallback.kt @@ -0,0 +1,16 @@ +package dev.yanshouwang.bluetooth_low_energy_android + +import android.bluetooth.le.AdvertiseCallback +import android.bluetooth.le.AdvertiseSettings + +class MyAdvertiseCallback(private val peripheralManager: MyPeripheralManager) : AdvertiseCallback() { + override fun onStartSuccess(settingsInEffect: AdvertiseSettings) { + super.onStartSuccess(settingsInEffect) + peripheralManager.onStartSuccess(settingsInEffect) + } + + override fun onStartFailure(errorCode: Int) { + super.onStartFailure(errorCode) + peripheralManager.onStartFailure(errorCode) + } +} \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.g.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.g.kt index 0cd40f3..3cdb6ad 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.g.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.g.kt @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.1.6), do not edit directly. +// Autogenerated from Pigeon (v11.0.1), do not edit directly. // See also: https://pub.dev/packages/pigeon package dev.yanshouwang.bluetooth_low_energy_android @@ -43,7 +43,7 @@ class FlutterError ( val details: Any? = null ) : Throwable() -enum class MyCentralStateArgs(val raw: Int) { +enum class MyBluetoothLowEnergyStateArgs(val raw: Int) { UNKNOWN(0), UNSUPPORTED(1), UNAUTHORIZED(2), @@ -51,7 +51,7 @@ enum class MyCentralStateArgs(val raw: Int) { POWEREDON(4); companion object { - fun ofRaw(raw: Int): MyCentralStateArgs? { + fun ofRaw(raw: Int): MyBluetoothLowEnergyStateArgs? { return values().firstOrNull { it.raw == raw } } } @@ -83,150 +83,224 @@ enum class MyGattCharacteristicWriteTypeArgs(val raw: Int) { } /** Generated class from Pigeon that represents data sent in messages. */ -data class MyCentralControllerArgs ( - val myStateNumber: Long +data class MyCentralManagerArgs ( + val stateNumberArgs: Long ) { companion object { @Suppress("UNCHECKED_CAST") - fun fromList(list: List): MyCentralControllerArgs { - val myStateNumber = list[0].let { if (it is Int) it.toLong() else it as Long } - return MyCentralControllerArgs(myStateNumber) + fun fromList(list: List): MyCentralManagerArgs { + val stateNumberArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + return MyCentralManagerArgs(stateNumberArgs) } } fun toList(): List { return listOf( - myStateNumber, + stateNumberArgs, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class MyPeripheralManagerArgs ( + val stateNumberArgs: Long + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): MyPeripheralManagerArgs { + val stateNumberArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + return MyPeripheralManagerArgs(stateNumberArgs) + } + } + fun toList(): List { + return listOf( + stateNumberArgs, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class MyCentralArgs ( + val hashCodeArgs: Long, + val uuidArgs: String + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): MyCentralArgs { + val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + val uuidArgs = list[1] as String + return MyCentralArgs(hashCodeArgs, uuidArgs) + } + } + fun toList(): List { + return listOf( + hashCodeArgs, + uuidArgs, ) } } /** Generated class from Pigeon that represents data sent in messages. */ data class MyPeripheralArgs ( - val key: Long, - val uuid: String + val hashCodeArgs: Long, + val uuidArgs: String ) { companion object { @Suppress("UNCHECKED_CAST") fun fromList(list: List): MyPeripheralArgs { - val key = list[0].let { if (it is Int) it.toLong() else it as Long } - val uuid = list[1] as String - return MyPeripheralArgs(key, uuid) + val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + val uuidArgs = list[1] as String + return MyPeripheralArgs(hashCodeArgs, uuidArgs) } } fun toList(): List { return listOf( - key, - uuid, + hashCodeArgs, + uuidArgs, ) } } /** Generated class from Pigeon that represents data sent in messages. */ -data class MyAdvertisementArgs ( - val name: String? = null, - val manufacturerSpecificData: Map, - val serviceUUIDs: List, - val serviceData: Map +data class MyAdvertiseDataArgs ( + val nameArgs: String? = null, + val serviceUUIDsArgs: List, + val serviceDataArgs: Map, + val manufacturerSpecificDataArgs: MyManufacturerSpecificDataArgs? = null ) { companion object { @Suppress("UNCHECKED_CAST") - fun fromList(list: List): MyAdvertisementArgs { - val name = list[0] as String? - val manufacturerSpecificData = list[1] as Map - val serviceUUIDs = list[2] as List - val serviceData = list[3] as Map - return MyAdvertisementArgs(name, manufacturerSpecificData, serviceUUIDs, serviceData) + fun fromList(list: List): MyAdvertiseDataArgs { + val nameArgs = list[0] as String? + val serviceUUIDsArgs = list[1] as List + val serviceDataArgs = list[2] as Map + val manufacturerSpecificDataArgs: MyManufacturerSpecificDataArgs? = (list[3] as List?)?.let { + MyManufacturerSpecificDataArgs.fromList(it) + } + return MyAdvertiseDataArgs(nameArgs, serviceUUIDsArgs, serviceDataArgs, manufacturerSpecificDataArgs) } } fun toList(): List { return listOf( - name, - manufacturerSpecificData, - serviceUUIDs, - serviceData, + nameArgs, + serviceUUIDsArgs, + serviceDataArgs, + manufacturerSpecificDataArgs?.toList(), + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class MyManufacturerSpecificDataArgs ( + val idArgs: Long, + val dataArgs: ByteArray + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): MyManufacturerSpecificDataArgs { + val idArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + val dataArgs = list[1] as ByteArray + return MyManufacturerSpecificDataArgs(idArgs, dataArgs) + } + } + fun toList(): List { + return listOf( + idArgs, + dataArgs, ) } } /** Generated class from Pigeon that represents data sent in messages. */ data class MyGattServiceArgs ( - val key: Long, - val uuid: String + val hashCodeArgs: Long, + val uuidArgs: String, + val characteristicsArgs: List ) { companion object { @Suppress("UNCHECKED_CAST") fun fromList(list: List): MyGattServiceArgs { - val key = list[0].let { if (it is Int) it.toLong() else it as Long } - val uuid = list[1] as String - return MyGattServiceArgs(key, uuid) + val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + val uuidArgs = list[1] as String + val characteristicsArgs = list[2] as List + return MyGattServiceArgs(hashCodeArgs, uuidArgs, characteristicsArgs) } } fun toList(): List { return listOf( - key, - uuid, + hashCodeArgs, + uuidArgs, + characteristicsArgs, ) } } /** Generated class from Pigeon that represents data sent in messages. */ data class MyGattCharacteristicArgs ( - val key: Long, - val uuid: String, - val myPropertyNumbers: List + val hashCodeArgs: Long, + val uuidArgs: String, + val propertyNumbersArgs: List, + val descriptorsArgs: List ) { companion object { @Suppress("UNCHECKED_CAST") fun fromList(list: List): MyGattCharacteristicArgs { - val key = list[0].let { if (it is Int) it.toLong() else it as Long } - val uuid = list[1] as String - val myPropertyNumbers = list[2] as List - return MyGattCharacteristicArgs(key, uuid, myPropertyNumbers) + val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + val uuidArgs = list[1] as String + val propertyNumbersArgs = list[2] as List + val descriptorsArgs = list[3] as List + return MyGattCharacteristicArgs(hashCodeArgs, uuidArgs, propertyNumbersArgs, descriptorsArgs) } } fun toList(): List { return listOf( - key, - uuid, - myPropertyNumbers, + hashCodeArgs, + uuidArgs, + propertyNumbersArgs, + descriptorsArgs, ) } } /** Generated class from Pigeon that represents data sent in messages. */ data class MyGattDescriptorArgs ( - val key: Long, - val uuid: String + val hashCodeArgs: Long, + val uuidArgs: String, + val valueArgs: ByteArray? = null ) { companion object { @Suppress("UNCHECKED_CAST") fun fromList(list: List): MyGattDescriptorArgs { - val key = list[0].let { if (it is Int) it.toLong() else it as Long } - val uuid = list[1] as String - return MyGattDescriptorArgs(key, uuid) + val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long } + val uuidArgs = list[1] as String + val valueArgs = list[2] as ByteArray? + return MyGattDescriptorArgs(hashCodeArgs, uuidArgs, valueArgs) } } fun toList(): List { return listOf( - key, - uuid, + hashCodeArgs, + uuidArgs, + valueArgs, ) } } @Suppress("UNCHECKED_CAST") -private object MyCentralControllerHostApiCodec : StandardMessageCodec() { +private object MyCentralManagerHostApiCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { 128.toByte() -> { return (readValue(buffer) as? List)?.let { - MyCentralControllerArgs.fromList(it) + MyCentralManagerArgs.fromList(it) } } 129.toByte() -> { @@ -249,7 +323,7 @@ private object MyCentralControllerHostApiCodec : StandardMessageCodec() { } override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { when (value) { - is MyCentralControllerArgs -> { + is MyCentralManagerArgs -> { stream.write(128) writeValue(stream, value.toList()) } @@ -271,37 +345,34 @@ private object MyCentralControllerHostApiCodec : StandardMessageCodec() { } /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ -interface MyCentralControllerHostApi { - fun setUp(callback: (Result) -> Unit) - fun tearDown() +interface MyCentralManagerHostApi { + fun setUp(callback: (Result) -> Unit) fun startDiscovery(callback: (Result) -> Unit) fun stopDiscovery() - fun connect(myPeripheralKey: Long, callback: (Result) -> Unit) - fun disconnect(myPeripheralKey: Long, callback: (Result) -> Unit) - fun getMaximumWriteLength(myPeripheralKey: Long, callback: (Result) -> Unit) - fun discoverGATT(myPeripheralKey: Long, callback: (Result) -> Unit) - fun getServices(myPeripheralKey: Long): List - fun getCharacteristics(myServiceKey: Long): List - fun getDescriptors(myCharacteristicKey: Long): List - fun readCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, callback: (Result) -> Unit) - fun writeCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result) -> Unit) - fun notifyCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result) -> Unit) - fun readDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, callback: (Result) -> Unit) - fun writeDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result) -> Unit) + fun connect(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) + fun disconnect(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) + fun getMaximumWriteLength(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) + fun readRSSI(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) + fun discoverGATT(peripheralHashCodeArgs: Long, callback: (Result>) -> Unit) + fun readCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, callback: (Result) -> Unit) + fun writeCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, typeNumberArgs: Long, callback: (Result) -> Unit) + fun notifyCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, stateArgs: Boolean, callback: (Result) -> Unit) + fun readDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, callback: (Result) -> Unit) + fun writeDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result) -> Unit) companion object { - /** The codec used by MyCentralControllerHostApi. */ + /** The codec used by MyCentralManagerHostApi. */ val codec: MessageCodec by lazy { - MyCentralControllerHostApiCodec + MyCentralManagerHostApiCodec } - /** Sets up an instance of `MyCentralControllerHostApi` to handle messages through the `binaryMessenger`. */ + /** Sets up an instance of `MyCentralManagerHostApi` to handle messages through the `binaryMessenger`. */ @Suppress("UNCHECKED_CAST") - fun setUp(binaryMessenger: BinaryMessenger, api: MyCentralControllerHostApi?) { + fun setUp(binaryMessenger: BinaryMessenger, api: MyCentralManagerHostApi?) { run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.setUp", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.setUp", codec) if (api != null) { channel.setMessageHandler { _, reply -> - api.setUp() { result: Result -> + api.setUp() { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -316,24 +387,7 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.tearDown", codec) - if (api != null) { - channel.setMessageHandler { _, reply -> - var wrapped: List - try { - api.tearDown() - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.startDiscovery", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.startDiscovery", codec) if (api != null) { channel.setMessageHandler { _, reply -> api.startDiscovery() { result: Result -> @@ -350,7 +404,7 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.stopDiscovery", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.stopDiscovery", codec) if (api != null) { channel.setMessageHandler { _, reply -> var wrapped: List @@ -367,12 +421,12 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.connect", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.connect", codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - api.connect(myPeripheralKeyArg) { result: Result -> + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + api.connect(peripheralHashCodeArgsArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -386,12 +440,12 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.disconnect", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.disconnect", codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - api.disconnect(myPeripheralKeyArg) { result: Result -> + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + api.disconnect(peripheralHashCodeArgsArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -405,12 +459,12 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getMaximumWriteLength", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.getMaximumWriteLength", codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - api.getMaximumWriteLength(myPeripheralKeyArg) { result: Result -> + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + api.getMaximumWriteLength(peripheralHashCodeArgsArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -425,87 +479,12 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.discoverGATT", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.readRSSI", codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - api.discoverGATT(myPeripheralKeyArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - reply.reply(wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getServices", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - var wrapped: List - try { - wrapped = listOf(api.getServices(myPeripheralKeyArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getCharacteristics", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val myServiceKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - var wrapped: List - try { - wrapped = listOf(api.getCharacteristics(myServiceKeyArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getDescriptors", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val myCharacteristicKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - var wrapped: List - try { - wrapped = listOf(api.getDescriptors(myCharacteristicKeyArg)) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readCharacteristic", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } - api.readCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg) { result: Result -> + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + api.readRSSI(peripheralHashCodeArgsArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -520,59 +499,12 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeCharacteristic", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.discoverGATT", codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } - val valueArg = args[3] as ByteArray - val myTypeNumberArg = args[4].let { if (it is Int) it.toLong() else it as Long } - api.writeCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg, valueArg, myTypeNumberArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - reply.reply(wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.notifyCharacteristic", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myServiceKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } - val stateArg = args[3] as Boolean - api.notifyCharacteristic(myPeripheralKeyArg, myServiceKeyArg, myCharacteristicKeyArg, stateArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - reply.reply(wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readDescriptor", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val myDescriptorKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } - api.readDescriptor(myPeripheralKeyArg, myCharacteristicKeyArg, myDescriptorKeyArg) { result: Result -> + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + api.discoverGATT(peripheralHashCodeArgsArg) { result: Result> -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -587,15 +519,99 @@ interface MyCentralControllerHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeDescriptor", codec) + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.readCharacteristic", codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List - val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long } - val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val myDescriptorKeyArg = args[2].let { if (it is Int) it.toLong() else it as Long } - val valueArg = args[3] as ByteArray - api.writeDescriptor(myPeripheralKeyArg, myCharacteristicKeyArg, myDescriptorKeyArg, valueArg) { result: Result -> + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + api.readCharacteristic(peripheralHashCodeArgsArg, characteristicHashCodeArgsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.writeCharacteristic", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val valueArgsArg = args[2] as ByteArray + val typeNumberArgsArg = args[3].let { if (it is Int) it.toLong() else it as Long } + api.writeCharacteristic(peripheralHashCodeArgsArg, characteristicHashCodeArgsArg, valueArgsArg, typeNumberArgsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.notifyCharacteristic", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val stateArgsArg = args[2] as Boolean + api.notifyCharacteristic(peripheralHashCodeArgsArg, characteristicHashCodeArgsArg, stateArgsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.readDescriptor", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val descriptorHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + api.readDescriptor(peripheralHashCodeArgsArg, descriptorHashCodeArgsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.writeDescriptor", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val descriptorHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val valueArgsArg = args[2] as ByteArray + api.writeDescriptor(peripheralHashCodeArgsArg, descriptorHashCodeArgsArg, valueArgsArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -612,15 +628,30 @@ interface MyCentralControllerHostApi { } } @Suppress("UNCHECKED_CAST") -private object MyCentralControllerFlutterApiCodec : StandardMessageCodec() { +private object MyCentralManagerFlutterApiCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { 128.toByte() -> { return (readValue(buffer) as? List)?.let { - MyAdvertisementArgs.fromList(it) + MyAdvertiseDataArgs.fromList(it) } } 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyGattCharacteristicArgs.fromList(it) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyGattDescriptorArgs.fromList(it) + } + } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyManufacturerSpecificDataArgs.fromList(it) + } + } + 132.toByte() -> { return (readValue(buffer) as? List)?.let { MyPeripheralArgs.fromList(it) } @@ -630,14 +661,26 @@ private object MyCentralControllerFlutterApiCodec : StandardMessageCodec() { } override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { when (value) { - is MyAdvertisementArgs -> { + is MyAdvertiseDataArgs -> { stream.write(128) writeValue(stream, value.toList()) } - is MyPeripheralArgs -> { + is MyGattCharacteristicArgs -> { stream.write(129) writeValue(stream, value.toList()) } + is MyGattDescriptorArgs -> { + stream.write(130) + writeValue(stream, value.toList()) + } + is MyManufacturerSpecificDataArgs -> { + stream.write(131) + writeValue(stream, value.toList()) + } + is MyPeripheralArgs -> { + stream.write(132) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } @@ -645,34 +688,396 @@ private object MyCentralControllerFlutterApiCodec : StandardMessageCodec() { /** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ @Suppress("UNCHECKED_CAST") -class MyCentralControllerFlutterApi(private val binaryMessenger: BinaryMessenger) { +class MyCentralManagerFlutterApi(private val binaryMessenger: BinaryMessenger) { companion object { - /** The codec used by MyCentralControllerFlutterApi. */ + /** The codec used by MyCentralManagerFlutterApi. */ val codec: MessageCodec by lazy { - MyCentralControllerFlutterApiCodec + MyCentralManagerFlutterApiCodec } } - fun onStateChanged(myStateNumberArg: Long, callback: () -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged", codec) - channel.send(listOf(myStateNumberArg)) { + fun onStateChanged(stateNumberArgsArg: Long, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onStateChanged", codec) + channel.send(listOf(stateNumberArgsArg)) { callback() } } - fun onDiscovered(myPeripheralArgsArg: MyPeripheralArgs, rssiArg: Long, myAdvertisementArgsArg: MyAdvertisementArgs, callback: () -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered", codec) - channel.send(listOf(myPeripheralArgsArg, rssiArg, myAdvertisementArgsArg)) { + fun onDiscovered(peripheralArgsArg: MyPeripheralArgs, rssiArgsArg: Long, advertiseDataArgsArg: MyAdvertiseDataArgs, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered", codec) + channel.send(listOf(peripheralArgsArg, rssiArgsArg, advertiseDataArgsArg)) { callback() } } - fun onPeripheralStateChanged(myPeripheralKeyArg: Long, stateArg: Boolean, callback: () -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged", codec) - channel.send(listOf(myPeripheralKeyArg, stateArg)) { + fun onPeripheralStateChanged(peripheralArgsArg: MyPeripheralArgs, stateArgsArg: Boolean, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onPeripheralStateChanged", codec) + channel.send(listOf(peripheralArgsArg, stateArgsArg)) { callback() } } - fun onCharacteristicValueChanged(myCharacteristicKeyArg: Long, valueArg: ByteArray, callback: () -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged", codec) - channel.send(listOf(myCharacteristicKeyArg, valueArg)) { + fun onCharacteristicValueChanged(characteristicArgsArg: MyGattCharacteristicArgs, valueArgsArg: ByteArray, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onCharacteristicValueChanged", codec) + channel.send(listOf(characteristicArgsArg, valueArgsArg)) { + callback() + } + } +} +@Suppress("UNCHECKED_CAST") +private object MyPeripheralManagerHostApiCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyAdvertiseDataArgs.fromList(it) + } + } + 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyGattCharacteristicArgs.fromList(it) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyGattDescriptorArgs.fromList(it) + } + } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyGattServiceArgs.fromList(it) + } + } + 132.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyManufacturerSpecificDataArgs.fromList(it) + } + } + 133.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyPeripheralManagerArgs.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is MyAdvertiseDataArgs -> { + stream.write(128) + writeValue(stream, value.toList()) + } + is MyGattCharacteristicArgs -> { + stream.write(129) + writeValue(stream, value.toList()) + } + is MyGattDescriptorArgs -> { + stream.write(130) + writeValue(stream, value.toList()) + } + is MyGattServiceArgs -> { + stream.write(131) + writeValue(stream, value.toList()) + } + is MyManufacturerSpecificDataArgs -> { + stream.write(132) + writeValue(stream, value.toList()) + } + is MyPeripheralManagerArgs -> { + stream.write(133) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface MyPeripheralManagerHostApi { + fun setUp(callback: (Result) -> Unit) + fun addService(serviceArgs: MyGattServiceArgs, callback: (Result) -> Unit) + fun removeService(serviceHashCodeArgs: Long) + fun clearServices() + fun startAdvertising(advertiseDataArgs: MyAdvertiseDataArgs, callback: (Result) -> Unit) + fun stopAdvertising() + fun getMaximumWriteLength(centralHashCodeArgs: Long): Long + fun sendReadCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean, valueArgs: ByteArray) + fun sendWriteCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean) + fun notifyCharacteristicValueChanged(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result) -> Unit) + + companion object { + /** The codec used by MyPeripheralManagerHostApi. */ + val codec: MessageCodec by lazy { + MyPeripheralManagerHostApiCodec + } + /** Sets up an instance of `MyPeripheralManagerHostApi` to handle messages through the `binaryMessenger`. */ + @Suppress("UNCHECKED_CAST") + fun setUp(binaryMessenger: BinaryMessenger, api: MyPeripheralManagerHostApi?) { + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.setUp", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.setUp() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.addService", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val serviceArgsArg = args[0] as MyGattServiceArgs + api.addService(serviceArgsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.removeService", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val serviceHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + var wrapped: List + try { + api.removeService(serviceHashCodeArgsArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.clearServices", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + var wrapped: List + try { + api.clearServices() + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.startAdvertising", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val advertiseDataArgsArg = args[0] as MyAdvertiseDataArgs + api.startAdvertising(advertiseDataArgsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.stopAdvertising", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + var wrapped: List + try { + api.stopAdvertising() + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.getMaximumWriteLength", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + var wrapped: List + try { + wrapped = listOf(api.getMaximumWriteLength(centralHashCodeArgsArg)) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.sendReadCharacteristicReply", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val idArgsArg = args[2].let { if (it is Int) it.toLong() else it as Long } + val offsetArgsArg = args[3].let { if (it is Int) it.toLong() else it as Long } + val statusArgsArg = args[4] as Boolean + val valueArgsArg = args[5] as ByteArray + var wrapped: List + try { + api.sendReadCharacteristicReply(centralHashCodeArgsArg, characteristicHashCodeArgsArg, idArgsArg, offsetArgsArg, statusArgsArg, valueArgsArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.sendWriteCharacteristicReply", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val idArgsArg = args[2].let { if (it is Int) it.toLong() else it as Long } + val offsetArgsArg = args[3].let { if (it is Int) it.toLong() else it as Long } + val statusArgsArg = args[4] as Boolean + var wrapped: List + try { + api.sendWriteCharacteristicReply(centralHashCodeArgsArg, characteristicHashCodeArgsArg, idArgsArg, offsetArgsArg, statusArgsArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.notifyCharacteristicValueChanged", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long } + val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val valueArgsArg = args[2] as ByteArray + api.notifyCharacteristicValueChanged(centralHashCodeArgsArg, characteristicHashCodeArgsArg, valueArgsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +@Suppress("UNCHECKED_CAST") +private object MyPeripheralManagerFlutterApiCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyCentralArgs.fromList(it) + } + } + 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyGattCharacteristicArgs.fromList(it) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + MyGattDescriptorArgs.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is MyCentralArgs -> { + stream.write(128) + writeValue(stream, value.toList()) + } + is MyGattCharacteristicArgs -> { + stream.write(129) + writeValue(stream, value.toList()) + } + is MyGattDescriptorArgs -> { + stream.write(130) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +@Suppress("UNCHECKED_CAST") +class MyPeripheralManagerFlutterApi(private val binaryMessenger: BinaryMessenger) { + companion object { + /** The codec used by MyPeripheralManagerFlutterApi. */ + val codec: MessageCodec by lazy { + MyPeripheralManagerFlutterApiCodec + } + } + fun onStateChanged(stateNumberArgsArg: Long, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onStateChanged", codec) + channel.send(listOf(stateNumberArgsArg)) { + callback() + } + } + fun onReadCharacteristicCommandReceived(centralArgsArg: MyCentralArgs, characteristicArgsArg: MyGattCharacteristicArgs, idArgsArg: Long, offsetArgsArg: Long, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived", codec) + channel.send(listOf(centralArgsArg, characteristicArgsArg, idArgsArg, offsetArgsArg)) { + callback() + } + } + fun onWriteCharacteristicCommandReceived(centralArgsArg: MyCentralArgs, characteristicArgsArg: MyGattCharacteristicArgs, idArgsArg: Long, offsetArgsArg: Long, valueArgsArg: ByteArray, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived", codec) + channel.send(listOf(centralArgsArg, characteristicArgsArg, idArgsArg, offsetArgsArg, valueArgsArg)) { + callback() + } + } + fun onNotifyCharacteristicCommandReceived(centralArgsArg: MyCentralArgs, characteristicArgsArg: MyGattCharacteristicArgs, stateArgsArg: Boolean, callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived", codec) + channel.send(listOf(centralArgsArg, characteristicArgsArg, stateArgsArg)) { callback() } } diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.kt new file mode 100644 index 0000000..dedd6a6 --- /dev/null +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyApi.kt @@ -0,0 +1,233 @@ +package dev.yanshouwang.bluetooth_low_energy_android + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothGattService +import android.bluetooth.le.AdvertiseData +import android.bluetooth.le.ScanRecord +import android.bluetooth.le.ScanResult +import android.os.ParcelUuid +import android.util.SparseArray +import java.util.UUID + +val Any.TAG get() = this::class.java.simpleName as String + +val BluetoothAdapter.stateArgs: MyBluetoothLowEnergyStateArgs + get() = state.toBluetoothLowEnergyStateArgs() + +fun Int.toBluetoothLowEnergyStateArgs(): MyBluetoothLowEnergyStateArgs { + return when (this) { + BluetoothAdapter.STATE_ON -> MyBluetoothLowEnergyStateArgs.POWEREDON + else -> MyBluetoothLowEnergyStateArgs.POWEREDOFF + } +} + +fun BluetoothDevice.toPeripheralArgs(): MyPeripheralArgs { + val hashCodeArgs = hashCode().toLong() + val uuid = this.uuid.toString() + return MyPeripheralArgs(hashCodeArgs, uuid) +} + +fun BluetoothDevice.toCentralArgs(): MyCentralArgs { + val hashCodeArgs = hashCode().toLong() + val uuid = this.uuid.toString() + return MyCentralArgs(hashCodeArgs, uuid) +} + +val BluetoothDevice.uuid: UUID + get() { + val node = address.filter { char -> char != ':' } + // We don't know the timestamp of the bluetooth device, use nil UUID as prefix. + return UUID.fromString("00000000-0000-0000-0000-$node") + } + +val ScanResult.advertiseDataArgs: MyAdvertiseDataArgs + get() { + val record = scanRecord + return if (record == null) { + val nameArgs = null + val serviceUUIDsArgs = emptyList() + val serviceDataArgs = emptyMap() + val manufacturerSpecificDataArgs = null + MyAdvertiseDataArgs(nameArgs, serviceUUIDsArgs, serviceDataArgs, manufacturerSpecificDataArgs) + } else { + val nameArgs = record.deviceName + val serviceUUIDsArgs = record.serviceUuids?.map { uuid -> uuid.toString() } + ?: emptyList() + val pairs = record.serviceData.map { (uuid, value) -> + val key = uuid.toString() + return@map Pair(key, value) + }.toTypedArray() + val serviceDataArgs = mapOf(*pairs) + val manufacturerSpecificDataArgs = record.manufacturerSpecificData.toManufacturerSpecificDataArgs() + MyAdvertiseDataArgs(nameArgs, serviceUUIDsArgs, serviceDataArgs, manufacturerSpecificDataArgs) + } + } + +fun SparseArray.toManufacturerSpecificDataArgs(): MyManufacturerSpecificDataArgs? { + var index = 0 + val size = size() + val itemsArgs = mutableListOf() + while (index < size) { + val idArgs = keyAt(index).toLong() + val dataArgs = valueAt(index) + val itemArgs = MyManufacturerSpecificDataArgs(idArgs, dataArgs) + itemsArgs.add(itemArgs) + index++ + } + return itemsArgs.lastOrNull() +} + +val ScanRecord.rawValues: Map + get() { + val rawValues = mutableMapOf() + var index = 0 + val size = bytes.size + while (index < size) { + val length = bytes[index++].toInt() and 0xff + if (length == 0) { + break + } + val end = index + length + val type = bytes[index++] + val value = bytes.slice(index until end).toByteArray() + rawValues[type] = value + index = end + } + return rawValues.toMap() + } + +fun MyAdvertiseDataArgs.toAdvertiseData(adapter: BluetoothAdapter): AdvertiseData { + val advertiseDataBuilder = AdvertiseData.Builder() + if (nameArgs == null) { + advertiseDataBuilder.setIncludeDeviceName(false) + } else { + adapter.name = nameArgs + advertiseDataBuilder.setIncludeDeviceName(true) + } + for (serviceUuidArgs in serviceUUIDsArgs) { + val serviceUUID = ParcelUuid.fromString(serviceUuidArgs) + advertiseDataBuilder.addServiceUuid(serviceUUID) + } + for (entry in serviceDataArgs) { + val serviceDataUUID = ParcelUuid.fromString(entry.key as String) + val serviceData = entry.value as ByteArray + advertiseDataBuilder.addServiceData(serviceDataUUID, serviceData) + } + if (manufacturerSpecificDataArgs != null) { + val manufacturerId = manufacturerSpecificDataArgs.idArgs.toInt() + val manufacturerSpecificData = manufacturerSpecificDataArgs.dataArgs + advertiseDataBuilder.addManufacturerData(manufacturerId, manufacturerSpecificData) + } + return advertiseDataBuilder.build() +} + +fun BluetoothGattService.toManufacturerSpecificDataArgs(characteristicsArgs: List): MyGattServiceArgs { + val hashCodeArgs = hashCode().toLong() + val uuidArgs = this.uuid.toString() + return MyGattServiceArgs(hashCodeArgs, uuidArgs, characteristicsArgs) +} + +fun BluetoothGattCharacteristic.toManufacturerSpecificDataArgs(descriptorsArgs: List): MyGattCharacteristicArgs { + val hashCodeArgs = hashCode().toLong() + val uuidArgs = this.uuid.toString() + return MyGattCharacteristicArgs(hashCodeArgs, uuidArgs, propertyNumbersArgs, descriptorsArgs) +} + +val BluetoothGattCharacteristic.propertyNumbersArgs: List + get() { + val numbersArgs = mutableListOf() + if (properties and BluetoothGattCharacteristic.PROPERTY_READ != 0) { + val number = MyGattCharacteristicPropertyArgs.READ.raw.toLong() + numbersArgs.add(number) + } + if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE != 0) { + val number = MyGattCharacteristicPropertyArgs.WRITE.raw.toLong() + numbersArgs.add(number) + } + if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE != 0) { + val number = MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE.raw.toLong() + numbersArgs.add(number) + } + if (properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) { + val number = MyGattCharacteristicPropertyArgs.NOTIFY.raw.toLong() + numbersArgs.add(number) + } + if (properties and BluetoothGattCharacteristic.PROPERTY_INDICATE != 0) { + val number = MyGattCharacteristicPropertyArgs.INDICATE.raw.toLong() + numbersArgs.add(number) + } + return numbersArgs + } + +fun BluetoothGattDescriptor.toManufacturerSpecificDataArgs(): MyGattDescriptorArgs { + val hashCodeArgs = hashCode().toLong() + val uuidArgs = this.uuid.toString() + return MyGattDescriptorArgs(hashCodeArgs, uuidArgs, null) +} + +fun MyGattServiceArgs.toService(): BluetoothGattService { + val uuid = UUID.fromString(uuidArgs) + val serviceType = BluetoothGattService.SERVICE_TYPE_PRIMARY + return BluetoothGattService(uuid, serviceType) +} + +fun MyGattCharacteristicArgs.toCharacteristic(): BluetoothGattCharacteristic { + val uuid = UUID.fromString(uuidArgs) + return BluetoothGattCharacteristic(uuid, properties, permissions) +} + +val MyGattCharacteristicArgs.properties: Int + get() { + val propertiesArgs = propertyNumbersArgs.filterNotNull().map { args -> + val raw = args.toInt() + MyGattCharacteristicPropertyArgs.ofRaw(raw) + } + val read = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.READ) + val write = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITE) + val writeWithoutResponse = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE) + val notify = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.NOTIFY) + val indicate = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.INDICATE) + var properties = 0 + if (read) properties = properties or BluetoothGattCharacteristic.PROPERTY_READ + if (write) properties = properties or BluetoothGattCharacteristic.PROPERTY_WRITE + if (writeWithoutResponse) properties = properties or BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE + if (notify) properties = properties or BluetoothGattCharacteristic.PROPERTY_NOTIFY + if (indicate) properties = properties or BluetoothGattCharacteristic.PROPERTY_INDICATE + return properties + } + +val MyGattCharacteristicArgs.permissions: Int + get() { + val propertiesArgs = propertyNumbersArgs.filterNotNull().map { args -> + val raw = args.toInt() + MyGattCharacteristicPropertyArgs.ofRaw(raw) + } + val read = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.READ) + val write = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITE) + val writeWithoutResponse = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE) + var permissions = 0 + if (read) permissions = permissions or BluetoothGattCharacteristic.PERMISSION_READ + if (write || writeWithoutResponse) permissions = permissions or BluetoothGattCharacteristic.PERMISSION_WRITE + return permissions + } + +fun MyGattDescriptorArgs.toDescriptor(): BluetoothGattDescriptor { + val uuid = UUID.fromString(uuidArgs) + val permissions = BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE + return BluetoothGattDescriptor(uuid, permissions) +} + +fun Long.toWriteTypeArgs(): MyGattCharacteristicWriteTypeArgs { + val raw = toInt() + return MyGattCharacteristicWriteTypeArgs.ofRaw(raw) ?: throw IllegalArgumentException() +} + +fun MyGattCharacteristicWriteTypeArgs.toType(): Int { + return when (this) { + MyGattCharacteristicWriteTypeArgs.WITHRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT + MyGattCharacteristicWriteTypeArgs.WITHOUTRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE + } +} \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattCallback.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattCallback.kt index 869aa9a..0efd94b 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattCallback.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattCallback.kt @@ -7,32 +7,39 @@ import android.bluetooth.BluetoothGattDescriptor import android.os.Build import java.util.concurrent.Executor -class MyBluetoothGattCallback(private val myCentralController: MyCentralController, private val executor: Executor) : BluetoothGattCallback() { +class MyBluetoothGattCallback(private val centralManager: MyCentralManager, private val executor: Executor) : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { super.onConnectionStateChange(gatt, status, newState) executor.execute { - myCentralController.onConnectionStateChange(gatt, status, newState) + centralManager.onConnectionStateChange(gatt, status, newState) } } override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { super.onMtuChanged(gatt, mtu, status) executor.execute { - myCentralController.onMtuChanged(gatt, mtu, status) + centralManager.onMtuChanged(gatt, mtu, status) + } + } + + override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) { + super.onReadRemoteRssi(gatt, rssi, status) + executor.execute { + centralManager.onReadRemoteRssi(gatt, rssi, status) } } override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { super.onServicesDiscovered(gatt, status) executor.execute { - myCentralController.onServicesDiscovered(gatt, status) + centralManager.onServicesDiscovered(gatt, status) } } override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray, status: Int) { super.onCharacteristicRead(gatt, characteristic, value, status) executor.execute { - myCentralController.onCharacteristicRead(characteristic, status, value) + centralManager.onCharacteristicRead(characteristic, status, value) } } @@ -44,21 +51,21 @@ class MyBluetoothGattCallback(private val myCentralController: MyCentralControll } val value = characteristic.value executor.execute { - myCentralController.onCharacteristicRead(characteristic, status, value) + centralManager.onCharacteristicRead(characteristic, status, value) } } override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { super.onCharacteristicWrite(gatt, characteristic, status) executor.execute { - myCentralController.onCharacteristicWrite(characteristic, status) + centralManager.onCharacteristicWrite(characteristic, status) } } override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray) { super.onCharacteristicChanged(gatt, characteristic, value) executor.execute { - myCentralController.onCharacteristicChanged(characteristic, value) + centralManager.onCharacteristicChanged(characteristic, value) } } @@ -70,14 +77,14 @@ class MyBluetoothGattCallback(private val myCentralController: MyCentralControll } val value = characteristic.value executor.execute { - myCentralController.onCharacteristicChanged(characteristic, value) + centralManager.onCharacteristicChanged(characteristic, value) } } override fun onDescriptorRead(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray) { super.onDescriptorRead(gatt, descriptor, status, value) executor.execute { - myCentralController.onDescriptorRead(descriptor, status, value) + centralManager.onDescriptorRead(descriptor, status, value) } } @@ -89,14 +96,14 @@ class MyBluetoothGattCallback(private val myCentralController: MyCentralControll } val value = descriptor.value executor.execute { - myCentralController.onDescriptorRead(descriptor, status, value) + centralManager.onDescriptorRead(descriptor, status, value) } } override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { super.onDescriptorWrite(gatt, descriptor, status) executor.execute { - myCentralController.onDescriptorWrite(descriptor, status) + centralManager.onDescriptorWrite(descriptor, status) } } } \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattServerCallback.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattServerCallback.kt new file mode 100644 index 0000000..633b3da --- /dev/null +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothGattServerCallback.kt @@ -0,0 +1,59 @@ +package dev.yanshouwang.bluetooth_low_energy_android + +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothGattServerCallback +import android.bluetooth.BluetoothGattService +import java.util.concurrent.Executor + +class MyBluetoothGattServerCallback(private val peripheralManager: MyPeripheralManager, private val executor: Executor) : BluetoothGattServerCallback() { + override fun onServiceAdded(status: Int, service: BluetoothGattService) { + super.onServiceAdded(status, service) + executor.execute { + peripheralManager.onServiceAdded(status, service) + } + } + + override fun onMtuChanged(device: BluetoothDevice, mtu: Int) { + super.onMtuChanged(device, mtu) + executor.execute { + peripheralManager.onMtuChanged(device, mtu) + } + } + + override fun onCharacteristicReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, characteristic: BluetoothGattCharacteristic) { + super.onCharacteristicReadRequest(device, requestId, offset, characteristic) + executor.execute { + peripheralManager.onCharacteristicReadRequest(device, requestId, offset, characteristic) + } + } + + override fun onCharacteristicWriteRequest(device: BluetoothDevice, requestId: Int, characteristic: BluetoothGattCharacteristic, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) { + super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value) + executor.execute { + peripheralManager.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value) + } + } + + override fun onNotificationSent(device: BluetoothDevice, status: Int) { + super.onNotificationSent(device, status) + executor.execute { + peripheralManager.onNotificationSent(device, status) + } + } + + override fun onDescriptorReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, descriptor: BluetoothGattDescriptor) { + super.onDescriptorReadRequest(device, requestId, offset, descriptor) + executor.execute { + peripheralManager.onDescriptorReadRequest(device, requestId, offset, descriptor) + } + } + + override fun onDescriptorWriteRequest(device: BluetoothDevice, requestId: Int, descriptor: BluetoothGattDescriptor, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) { + super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value) + executor.execute { + peripheralManager.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value) + } + } +} \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothLowEnergyManager.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothLowEnergyManager.kt new file mode 100644 index 0000000..6148c5c --- /dev/null +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBluetoothLowEnergyManager.kt @@ -0,0 +1,63 @@ +package dev.yanshouwang.bluetooth_low_energy_android + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothManager +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.PackageManager +import androidx.annotation.CallSuper +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import java.util.UUID +import java.util.concurrent.Executor + +abstract class MyBluetoothLowEnergyManager(private val context: Context) { + companion object { + const val DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xff.toByte() + const val REQUEST_CODE = 443 + + val HEART_RATE_MEASUREMENT_UUID: UUID = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb") + val CLIENT_CHARACTERISTIC_CONFIG_UUID: UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") + } + + private lateinit var binding: ActivityPluginBinding + + protected val unsupported = !context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) + protected val executor = ContextCompat.getMainExecutor(context) as Executor + + protected val manager get() = ContextCompat.getSystemService(context, BluetoothManager::class.java) as BluetoothManager + protected val adapter get() = manager.adapter as BluetoothAdapter + + private val listener by lazy { MyRequestPermissionResultListener(this) } + private val receiver by lazy { MyBroadcastReceiver(this) } + + fun onAttachedToActivity(binding: ActivityPluginBinding) { + binding.addRequestPermissionsResultListener(listener) + this.binding = binding + } + + fun onDetachedFromActivity() { + binding.removeRequestPermissionsResultListener(listener) + } + + protected fun authorize(permissions: Array) { + val activity = binding.activity + ActivityCompat.requestPermissions(activity, permissions, REQUEST_CODE) + } + + @CallSuper + protected open fun register() { + val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) + context.registerReceiver(receiver, filter) + } + + @CallSuper + protected open fun unregister() { + context.unregisterReceiver(receiver) + } + + abstract fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean + abstract fun onReceive(intent: Intent) +} \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBroadcastReceiver.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBroadcastReceiver.kt index ae85a8c..767c269 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBroadcastReceiver.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyBroadcastReceiver.kt @@ -4,8 +4,8 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -class MyBroadcastReceiver(private val myCentralController: MyCentralController) : BroadcastReceiver() { +class MyBroadcastReceiver(private val bluetoothLowEnergyManager: MyBluetoothLowEnergyManager) : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - myCentralController.onReceive(intent) + bluetoothLowEnergyManager.onReceive(intent) } } diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralController.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralController.kt deleted file mode 100644 index bb5d47a..0000000 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralController.kt +++ /dev/null @@ -1,745 +0,0 @@ -package dev.yanshouwang.bluetooth_low_energy_android - -import android.bluetooth.BluetoothAdapter -import android.bluetooth.BluetoothDevice -import android.bluetooth.BluetoothGatt -import android.bluetooth.BluetoothGattCharacteristic -import android.bluetooth.BluetoothGattDescriptor -import android.bluetooth.BluetoothGattService -import android.bluetooth.BluetoothManager -import android.bluetooth.BluetoothProfile -import android.bluetooth.BluetoothStatusCodes -import android.bluetooth.le.ScanFilter -import android.bluetooth.le.ScanResult -import android.bluetooth.le.ScanSettings -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.content.pm.PackageManager -import android.os.Build -import android.util.SparseArray -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat -import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding -import io.flutter.plugin.common.BinaryMessenger -import java.util.UUID - -class MyCentralController(private val context: Context, binaryMessenger: BinaryMessenger) : MyCentralControllerHostApi { - companion object { - // const val DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xff.toByte() - private const val REQUEST_CODE = 443 - - // private val UUID_HEART_RATE_MEASUREMENT = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb") - private val UUID_CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") - } - - private lateinit var binding: ActivityPluginBinding - - private val manager = ContextCompat.getSystemService(context, BluetoothManager::class.java) as BluetoothManager - private val adapter = manager.adapter - private val scanner = adapter.bluetoothLeScanner - private val executor = ContextCompat.getMainExecutor(context) - - private val myApi = MyCentralControllerFlutterApi(binaryMessenger) - private val myRequestPermissionResultListener = MyRequestPermissionResultListener(this) - private val myBroadcastReceiver = MyBroadcastReceiver(this) - private val myScanCallback = MyScanCallback(this) - private val myBluetoothGattCallback = MyBluetoothGattCallback(this, executor) - - private val cachedDevices = mutableMapOf() - private val cachedGATTs = mutableMapOf() - private val cachedServices = mutableMapOf>() - private val cachedCharacteristics = mutableMapOf>() - private val cachedDescriptors = mutableMapOf>() - - private var registered = false - private var discovering = false - - private var setUpCallback: ((Result) -> Unit)? = null - private var startDiscoveryCallback: ((Result) -> Unit)? = null - private val connectCallbacks = mutableMapOf) -> Unit>() - private val disconnectCallbacks = mutableMapOf) -> Unit>() - private val getMaximumWriteLengthCallbacks = mutableMapOf) -> Unit>() - private val discoverGattCallbacks = mutableMapOf) -> Unit>() - private val readCharacteristicCallbacks = mutableMapOf) -> Unit>() - private val writeCharacteristicCallbacks = mutableMapOf) -> Unit>() - private val readDescriptorCallbacks = mutableMapOf) -> Unit>() - private val writeDescriptorCallbacks = mutableMapOf) -> Unit>() - - override fun setUp(callback: (Result) -> Unit) { - try { - val available = context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) - if (!available) { - val stateNumber = MyCentralStateArgs.UNSUPPORTED.raw.toLong() - val args = MyCentralControllerArgs(stateNumber) - callback(Result.success(args)) - } - val unfinishedCallback = setUpCallback - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_CONNECT) - } else { - arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION) - } - val activity = binding.activity - ActivityCompat.requestPermissions(activity, permissions, REQUEST_CODE) - setUpCallback = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun tearDown() { - if (registered) { - unregister() - } - if (discovering) { - stopDiscovery() - } - for (gatt in cachedGATTs.values) { - gatt.disconnect() - } - cachedDevices.clear() - cachedGATTs.clear() - cachedServices.clear() - cachedCharacteristics.clear() - cachedDescriptors.clear() - } - - private fun register() { - val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) - context.registerReceiver(myBroadcastReceiver, filter) - registered = true - } - - private fun unregister() { - context.unregisterReceiver(myBroadcastReceiver) - registered = false - } - - override fun startDiscovery(callback: (Result) -> Unit) { - try { - val unfinishedCallback = startDiscoveryCallback - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val filters = emptyList() - val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build() - scanner.startScan(filters, settings, myScanCallback) - executor.execute { - val finishedCallback = startDiscoveryCallback ?: return@execute - startDiscoveryCallback = null - finishedCallback(Result.success(Unit)) - } - startDiscoveryCallback = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun stopDiscovery() { - scanner.stopScan(myScanCallback) - discovering = false - } - - override fun connect(myPeripheralKey: Long, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val unfinishedCallback = connectCallbacks[deviceKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val device = cachedDevices[deviceKey] as BluetoothDevice - val autoConnect = false - cachedGATTs[deviceKey] = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val transport = BluetoothDevice.TRANSPORT_LE - device.connectGatt(context, autoConnect, myBluetoothGattCallback, transport) - } else { - device.connectGatt(context, autoConnect, myBluetoothGattCallback) - } - connectCallbacks[deviceKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun disconnect(myPeripheralKey: Long, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val unfinishedCallback = disconnectCallbacks[deviceKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - gatt.disconnect() - disconnectCallbacks[deviceKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun getMaximumWriteLength(myPeripheralKey: Long, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val unfinishedCallback = getMaximumWriteLengthCallbacks[deviceKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - val requesting = gatt.requestMtu(512) - if (!requesting) { - throw IllegalStateException() - } - getMaximumWriteLengthCallbacks[deviceKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun discoverGATT(myPeripheralKey: Long, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val unfinishedCallback = discoverGattCallbacks[deviceKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - val discovering = gatt.discoverServices() - if (!discovering) { - throw IllegalStateException() - } - discoverGattCallbacks[deviceKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun getServices(myPeripheralKey: Long): List { - val deviceKey = myPeripheralKey.toInt() - val services = cachedServices[deviceKey] ?: throw IllegalStateException() - return services.values.map { service -> service.toMyArgs() } - } - - override fun getCharacteristics(myServiceKey: Long): List { - val serviceKey = myServiceKey.toInt() - val characteristics = cachedCharacteristics[serviceKey] ?: throw IllegalStateException() - return characteristics.values.map { characteristic -> characteristic.toMyArgs() } - } - - override fun getDescriptors(myCharacteristicKey: Long): List { - val characteristicKey = myCharacteristicKey.toInt() - val descriptors = cachedDescriptors[characteristicKey] ?: throw IllegalStateException() - return descriptors.values.map { descriptor -> descriptor.toMyArgs() } - } - - override fun readCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - val serviceKey = myServiceKey.toInt() - val characteristics = cachedCharacteristics[serviceKey] - ?: throw IllegalArgumentException() - val characteristicKey = myCharacteristicKey.toInt() - val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic - val unfinishedCallback = readCharacteristicCallbacks[characteristicKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val reading = gatt.readCharacteristic(characteristic) - if (!reading) { - throw IllegalStateException() - } - readCharacteristicCallbacks[characteristicKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun writeCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - val serviceKey = myServiceKey.toInt() - val characteristics = cachedCharacteristics[serviceKey] - ?: throw IllegalArgumentException() - val characteristicKey = myCharacteristicKey.toInt() - val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic - val unfinishedCallback = writeCharacteristicCallbacks[characteristicKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val myTypeArgs = myTypeNumber.toMyGattCharacteristicTypeArgs() - val writeType = myTypeArgs.toType() - val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - val writeCode = gatt.writeCharacteristic(characteristic, value, writeType) - writeCode == BluetoothStatusCodes.SUCCESS - } else { - // TODO: remove this when minSdkVersion >= 33 - characteristic.value = value - characteristic.writeType = writeType - gatt.writeCharacteristic(characteristic) - } - if (!writing) { - throw IllegalStateException() - } - writeCharacteristicCallbacks[characteristicKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun notifyCharacteristic(myPeripheralKey: Long, myServiceKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - val serviceKey = myServiceKey.toInt() - val characteristics = cachedCharacteristics[serviceKey] - ?: throw IllegalArgumentException() - val characteristicKey = myCharacteristicKey.toInt() - val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic - val notifying = gatt.setCharacteristicNotification(characteristic, state) - if (!notifying) { - throw IllegalStateException() - } - // TODO: Seems the docs is not correct, this operation is necessary for all characteristics. - // https://developer.android.com/guide/topics/connectivity/bluetooth/transfer-ble-data#notification - // This is specific to Heart Rate Measurement. -// if (characteristic.uuid == UUID_HEART_RATE_MEASUREMENT) { - val descriptor = characteristic.getDescriptor(UUID_CLIENT_CHARACTERISTIC_CONFIG) - val descriptorKey = descriptor.hashCode() - val unfinishedCallback = writeDescriptorCallbacks[descriptorKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val value = if (state) BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE - else BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE - val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - val writeCode = gatt.writeDescriptor(descriptor, value) - writeCode == BluetoothStatusCodes.SUCCESS - } else { - // TODO: remove this when minSdkVersion >= 33 - descriptor.value = value - gatt.writeDescriptor(descriptor) - } - if (!writing) { - throw IllegalStateException() - } - writeDescriptorCallbacks[descriptorKey] = callback -// } else { -// callback(Result.success(Unit)) -// } - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun readDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - val characteristicKey = myCharacteristicKey.toInt() - val descriptors = cachedDescriptors[characteristicKey] - ?: throw IllegalArgumentException() - val descriptorKey = myDescriptorKey.toInt() - val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor - val unfinishedCallback = readDescriptorCallbacks[descriptorKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val reading = gatt.readDescriptor(descriptor) - if (!reading) { - throw IllegalStateException() - } - readDescriptorCallbacks[descriptorKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - override fun writeDescriptor(myPeripheralKey: Long, myCharacteristicKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result) -> Unit) { - try { - val deviceKey = myPeripheralKey.toInt() - val gatt = cachedGATTs[deviceKey] as BluetoothGatt - val characteristicKey = myCharacteristicKey.toInt() - val descriptors = cachedDescriptors[characteristicKey] - ?: throw IllegalArgumentException() - val descriptorKey = myDescriptorKey.toInt() - val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor - val unfinishedCallback = writeDescriptorCallbacks[descriptorKey] - if (unfinishedCallback != null) { - throw IllegalStateException() - } - val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - val writeCode = gatt.writeDescriptor(descriptor, value) - writeCode == BluetoothStatusCodes.SUCCESS - } else { - // TODO: remove this when minSdkVersion >= 33 - descriptor.value = value - gatt.writeDescriptor(descriptor) - } - if (!writing) { - throw IllegalStateException() - } - writeDescriptorCallbacks[descriptorKey] = callback - } catch (e: Throwable) { - callback(Result.failure(e)) - } - } - - fun onAttachedToActivity(binding: ActivityPluginBinding) { - binding.addRequestPermissionsResultListener(myRequestPermissionResultListener) - this.binding = binding - } - - fun onDetachedFromActivity() { - binding.removeRequestPermissionsResultListener(myRequestPermissionResultListener) - } - - fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean { - if (requestCode != REQUEST_CODE) { - return false - } - val callback = setUpCallback ?: return false - val isGranted = results.all { r -> r == PackageManager.PERMISSION_GRANTED } - if (isGranted) { - register() - } - val myStateArgs = if (isGranted) adapter.myStateArgs - else MyCentralStateArgs.UNAUTHORIZED - val myStateNumber = myStateArgs.raw.toLong() - val myArgs = MyCentralControllerArgs(myStateNumber) - callback(Result.success(myArgs)) - return true - } - - fun onReceive(intent: Intent) { - val action = intent.action - if (action != BluetoothAdapter.ACTION_STATE_CHANGED) { - return - } - val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF) - val myStateArgs = state.toMyCentralStateArgs() - val myStateNumber = myStateArgs.raw.toLong() - myApi.onStateChanged(myStateNumber) {} - } - - fun onScanFailed(errorCode: Int) { - val callback = startDiscoveryCallback ?: return - startDiscoveryCallback = null - val error = IllegalStateException("Start discovery failed with error code: $errorCode") - callback(Result.failure(error)) - } - - fun onScanResult(result: ScanResult) { - val device = result.device - val deviceKey = device.hashCode() - cachedDevices[deviceKey] = device - val myPeripheralArgs = device.toMyArgs() - val rssi = result.rssi.toLong() - val myAdvertisementArgs = result.myAdvertisementArgs - myApi.onDiscovered(myPeripheralArgs, rssi, myAdvertisementArgs) {} - } - - fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { - val device = gatt.device - val deviceKey = device.hashCode() - val myPeripheralKey = deviceKey.toLong() - if (newState != BluetoothProfile.STATE_CONNECTED) { - gatt.close() - cachedGATTs.remove(deviceKey) - val error = IllegalStateException("GATT is disconnected with status: $status") - val getMaximumWriteLengthCallback = getMaximumWriteLengthCallbacks.remove(deviceKey) - if (getMaximumWriteLengthCallback != null) { - getMaximumWriteLengthCallback(Result.failure(error)) - } - val discoverGattCallback = discoverGattCallbacks.remove(deviceKey) - if (discoverGattCallback != null) { - discoverGattCallback(Result.failure(error)) - } - val services = cachedServices[deviceKey] ?: emptyMap() - for (service in services) { - val characteristics = cachedCharacteristics[service.key] ?: emptyMap() - for (characteristic in characteristics) { - val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristic.key) - val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristic.key) - if (readCharacteristicCallback != null) { - readCharacteristicCallback(Result.failure(error)) - } - if (writeCharacteristicCallback != null) { - writeCharacteristicCallback(Result.failure(error)) - } - val descriptors = cachedDescriptors[characteristic.key] ?: emptyMap() - for (descriptor in descriptors) { - val readDescriptorCallback = readDescriptorCallbacks.remove(descriptor.key) - val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptor.key) - if (readDescriptorCallback != null) { - readDescriptorCallback(Result.failure(error)) - } - if (writeDescriptorCallback != null) { - writeDescriptorCallback(Result.failure(error)) - } - } - } - } - } - val connectCallback = connectCallbacks.remove(deviceKey) - val disconnectCallback = disconnectCallbacks.remove(deviceKey) - if (connectCallback == null && disconnectCallback == null) { - // State changed. - val state = newState == BluetoothProfile.STATE_CONNECTED - myApi.onPeripheralStateChanged(myPeripheralKey, state) {} - } else { - if (connectCallback != null) { - if (status == BluetoothGatt.GATT_SUCCESS) { - // Connect succeed. - connectCallback(Result.success(Unit)) - myApi.onPeripheralStateChanged(myPeripheralKey, true) {} - } else { - // Connect failed. - val error = IllegalStateException("Connect failed with status: $status") - connectCallback(Result.failure(error)) - } - } - if (disconnectCallback != null) { - if (status == BluetoothGatt.GATT_SUCCESS) { - // Disconnect succeed. - disconnectCallback(Result.success(Unit)) - myApi.onPeripheralStateChanged(myPeripheralKey, false) {} - } else { - // Disconnect failed. - val error = IllegalStateException("Connect failed with status: $status") - disconnectCallback(Result.failure(error)) - } - } - } - } - - fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { - val device = gatt.device - val deviceKey = device.hashCode() - val callback = getMaximumWriteLengthCallbacks.remove(deviceKey) ?: return - if (status == BluetoothGatt.GATT_SUCCESS) { - val maximumWriteLength = (mtu - 3).toLong() - callback(Result.success(maximumWriteLength)) - } else { - val error = IllegalStateException("Get maximum write length failed with status: $status") - callback(Result.failure(error)) - } - } - - fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { - val device = gatt.device - val deviceKey = device.hashCode() - val callback = discoverGattCallbacks.remove(deviceKey) ?: return - if (status == BluetoothGatt.GATT_SUCCESS) { - val cachedServices = mutableMapOf() - for (service in gatt.services) { - val serviceKey = service.hashCode() - cachedServices[serviceKey] = service - val cachedCharacteristics = mutableMapOf() - for (characteristic in service.characteristics) { - val characteristicKey = characteristic.hashCode() - cachedCharacteristics[characteristicKey] = characteristic - val cachedDescriptors = mutableMapOf() - for (descriptor in characteristic.descriptors) { - val descriptorKey = descriptor.hashCode() - cachedDescriptors[descriptorKey] = descriptor - } - this.cachedDescriptors[characteristicKey] = cachedDescriptors - } - this.cachedCharacteristics[serviceKey] = cachedCharacteristics - } - this.cachedServices[deviceKey] = cachedServices - callback(Result.success(Unit)) - } else { - val error = IllegalStateException("Discover GATT failed with status: $status") - callback(Result.failure(error)) - } - } - - fun onCharacteristicRead(characteristic: BluetoothGattCharacteristic, status: Int, value: ByteArray) { - val characteristicKey = characteristic.hashCode() - val callback = readCharacteristicCallbacks.remove(characteristicKey) ?: return - if (status == BluetoothGatt.GATT_SUCCESS) { - callback(Result.success(value)) - } else { - val error = IllegalStateException("Read characteristic failed with status: $status.") - callback(Result.failure(error)) - } - } - - fun onCharacteristicWrite(characteristic: BluetoothGattCharacteristic, status: Int) { - val characteristicKey = characteristic.hashCode() - val callback = writeCharacteristicCallbacks.remove(characteristicKey) ?: return - if (status == BluetoothGatt.GATT_SUCCESS) { - callback(Result.success(Unit)) - } else { - val error = IllegalStateException("Write characteristic failed with status: $status.") - callback(Result.failure(error)) - } - } - - fun onCharacteristicChanged(characteristic: BluetoothGattCharacteristic, value: ByteArray) { - val characteristicKey = characteristic.hashCode() - val myCharacteristicKey = characteristicKey.toLong() - myApi.onCharacteristicValueChanged(myCharacteristicKey, value) {} - } - - fun onDescriptorRead(descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray) { - val descriptorKey = descriptor.hashCode() - val callback = readDescriptorCallbacks.remove(descriptorKey) ?: return - if (status == BluetoothGatt.GATT_SUCCESS) { - callback(Result.success(value)) - } else { - val error = IllegalStateException("Read descriptor failed with status: $status.") - callback(Result.failure(error)) - } - } - - fun onDescriptorWrite(descriptor: BluetoothGattDescriptor, status: Int) { - val descriptorKey = descriptor.hashCode() - val callback = writeDescriptorCallbacks.remove(descriptorKey) ?: return - if (status == BluetoothGatt.GATT_SUCCESS) { - callback(Result.success(Unit)) - } else { - val error = IllegalStateException("Write descriptor failed with status: $status.") - callback(Result.failure(error)) - } - } -} - -private val BluetoothAdapter.myStateArgs: MyCentralStateArgs - get() = state.toMyCentralStateArgs() - -private fun Int.toMyCentralStateArgs(): MyCentralStateArgs { - return when (this) { - BluetoothAdapter.STATE_ON -> MyCentralStateArgs.POWEREDON - else -> MyCentralStateArgs.POWEREDOFF - } -} - -private fun BluetoothDevice.toMyArgs(): MyPeripheralArgs { - val key = hashCode().toLong() - val uuid = this.uuid.toString() - return MyPeripheralArgs(key, uuid) -} - -private val BluetoothDevice.uuid: UUID - get() { - val node = address.filter { char -> char != ':' } - // We don't know the timestamp of the bluetooth device, use nil UUID as prefix. - return UUID.fromString("00000000-0000-0000-0000-$node") - } - -private val ScanResult.myAdvertisementArgs: MyAdvertisementArgs - get() { - val record = scanRecord - return if (record == null) { - val name = null - val manufacturerSpecificData = emptyMap() - val serviceUUIDs = emptyList() - val serviceData = emptyMap() - MyAdvertisementArgs(name, manufacturerSpecificData, serviceUUIDs, serviceData) - } else { - val name = record.deviceName - val manufacturerSpecificData = record.manufacturerSpecificData.toMyArgs() - val serviceUUIDs = record.serviceUuids?.map { uuid -> uuid.toString() } - ?: emptyList() - val pairs = record.serviceData.entries.map { (uuid, value) -> - val key = uuid.toString() - return@map Pair(key, value) - }.toTypedArray() - val serviceData = mapOf(*pairs) - MyAdvertisementArgs(name, manufacturerSpecificData, serviceUUIDs, serviceData) - } - } - -private fun SparseArray.toMyArgs(): Map { - var index = 0 - val size = size() - val values = mutableMapOf() - while (index < size) { - val key = keyAt(index).toLong() - val value = valueAt(index) - values[key] = value - index++ - } - return values -} - -//private val ScanRecord.rawValues: Map -// get() { -// val rawValues = mutableMapOf() -// var index = 0 -// val size = bytes.size -// while (index < size) { -// val length = bytes[index++].toInt() and 0xff -// if (length == 0) { -// break -// } -// val end = index + length -// val type = bytes[index++] -// val value = bytes.slice(index until end).toByteArray() -// rawValues[type] = value -// index = end -// } -// return rawValues.toMap() -// } - -private fun BluetoothGattService.toMyArgs(): MyGattServiceArgs { - val key = hashCode().toLong() - val uuid = this.uuid.toString() - return MyGattServiceArgs(key, uuid) -} - -private fun BluetoothGattCharacteristic.toMyArgs(): MyGattCharacteristicArgs { - val key = hashCode().toLong() - val uuid = this.uuid.toString() - return MyGattCharacteristicArgs(key, uuid, myPropertyNumbers) -} - -private val BluetoothGattCharacteristic.myPropertyNumbers: List - get() { - val numbers = mutableListOf() - if (properties and BluetoothGattCharacteristic.PROPERTY_READ != 0) { - val number = MyGattCharacteristicPropertyArgs.READ.raw.toLong() - numbers.add(number) - } - if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE != 0) { - val number = MyGattCharacteristicPropertyArgs.WRITE.raw.toLong() - numbers.add(number) - } - if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE != 0) { - val number = MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE.raw.toLong() - numbers.add(number) - } - if (properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) { - val number = MyGattCharacteristicPropertyArgs.NOTIFY.raw.toLong() - numbers.add(number) - } - if (properties and BluetoothGattCharacteristic.PROPERTY_INDICATE != 0) { - val number = MyGattCharacteristicPropertyArgs.INDICATE.raw.toLong() - numbers.add(number) - } - return numbers - } - -private fun BluetoothGattDescriptor.toMyArgs(): MyGattDescriptorArgs { - val key = hashCode().toLong() - val uuid = this.uuid.toString() - return MyGattDescriptorArgs(key, uuid) -} - -private fun Long.toMyGattCharacteristicTypeArgs(): MyGattCharacteristicWriteTypeArgs { - val raw = toInt() - return MyGattCharacteristicWriteTypeArgs.ofRaw(raw) ?: throw IllegalArgumentException() -} - -private fun MyGattCharacteristicWriteTypeArgs.toType(): Int { - return when (this) { - MyGattCharacteristicWriteTypeArgs.WITHRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT - MyGattCharacteristicWriteTypeArgs.WITHOUTRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - } -} \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralManager.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralManager.kt new file mode 100644 index 0000000..c591b3c --- /dev/null +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyCentralManager.kt @@ -0,0 +1,627 @@ +package dev.yanshouwang.bluetooth_low_energy_android + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothGattService +import android.bluetooth.BluetoothProfile +import android.bluetooth.BluetoothStatusCodes +import android.bluetooth.le.ScanFilter +import android.bluetooth.le.ScanResult +import android.bluetooth.le.ScanSettings +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import io.flutter.plugin.common.BinaryMessenger + +class MyCentralManager(private val context: Context, binaryMessenger: BinaryMessenger) : MyBluetoothLowEnergyManager(context), MyCentralManagerHostApi { + private val scanner get() = adapter.bluetoothLeScanner + + private val api = MyCentralManagerFlutterApi(binaryMessenger) + private val scanCallback = MyScanCallback(this) + private val bluetoothGattCallback = MyBluetoothGattCallback(this, executor) + + private val devices = mutableMapOf() + private val bluetoothGATTs = mutableMapOf() + private val services = mutableMapOf() + private val characteristics = mutableMapOf() + private val descriptors = mutableMapOf() + + private val peripheralsArgs = mutableMapOf() + private val servicesArgsOfPeripherals = mutableMapOf>() + private val servicesArgs = mutableMapOf() + private val characteristicsArgs = mutableMapOf() + private val descriptorsArgs = mutableMapOf() + + private var registered = false + private var discovering = false + + private var setUpCallback: ((Result) -> Unit)? = null + private var startDiscoveryCallback: ((Result) -> Unit)? = null + private val connectCallbacks = mutableMapOf) -> Unit>() + private val disconnectCallbacks = mutableMapOf) -> Unit>() + private val getMaximumWriteLengthCallbacks = mutableMapOf) -> Unit>() + private val readRssiCallbacks = mutableMapOf) -> Unit>() + private val discoverGattCallbacks = mutableMapOf>) -> Unit>() + private val readCharacteristicCallbacks = mutableMapOf) -> Unit>() + private val writeCharacteristicCallbacks = mutableMapOf) -> Unit>() + private val readDescriptorCallbacks = mutableMapOf) -> Unit>() + private val writeDescriptorCallbacks = mutableMapOf) -> Unit>() + + override fun setUp(callback: (Result) -> Unit) { + try { + if (setUpCallback != null) { + throw IllegalStateException() + } + tearDown() + if (unsupported) { + val stateNumberArgs = MyBluetoothLowEnergyStateArgs.UNSUPPORTED.raw.toLong() + val args = MyCentralManagerArgs(stateNumberArgs) + callback(Result.success(args)) + } + val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_CONNECT) + } else { + arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION) + } + authorize(permissions) + setUpCallback = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + private fun tearDown() { + if (registered) { + unregister() + } + if (discovering) { + stopDiscovery() + } + for (gatt in bluetoothGATTs.values) { + gatt.disconnect() + } + devices.clear() + bluetoothGATTs.clear() + services.clear() + characteristics.clear() + descriptors.clear() + peripheralsArgs.clear() + servicesArgsOfPeripherals.clear() + servicesArgs.clear() + characteristicsArgs.clear() + descriptorsArgs.clear() + setUpCallback = null + startDiscoveryCallback = null + connectCallbacks.clear() + disconnectCallbacks.clear() + getMaximumWriteLengthCallbacks.clear() + readRssiCallbacks.clear() + discoverGattCallbacks.clear() + readCharacteristicCallbacks.clear() + writeCharacteristicCallbacks.clear() + readDescriptorCallbacks.clear() + writeDescriptorCallbacks.clear() + } + + override fun register() { + super.register() + registered = true + } + + override fun unregister() { + super.unregister() + registered = false + } + + override fun startDiscovery(callback: (Result) -> Unit) { + try { + if (startDiscoveryCallback != null) { + throw IllegalStateException() + } + val filters = emptyList() + val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build() + scanner.startScan(filters, settings, scanCallback) + executor.execute { onScanSucceed() } + startDiscoveryCallback = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun stopDiscovery() { + scanner.stopScan(scanCallback) + discovering = false + } + + override fun connect(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) { + try { + val unfinishedCallback = connectCallbacks[peripheralHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val device = devices[peripheralHashCodeArgs] as BluetoothDevice + val autoConnect = false + // Add to bluetoothGATTs cache. + bluetoothGATTs[peripheralHashCodeArgs] = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val transport = BluetoothDevice.TRANSPORT_LE + device.connectGatt(context, autoConnect, bluetoothGattCallback, transport) + } else { + device.connectGatt(context, autoConnect, bluetoothGattCallback) + } + connectCallbacks[peripheralHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun disconnect(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) { + try { + val unfinishedCallback = disconnectCallbacks[peripheralHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + gatt.disconnect() + disconnectCallbacks[peripheralHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun getMaximumWriteLength(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) { + try { + val unfinishedCallback = getMaximumWriteLengthCallbacks[peripheralHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val requesting = gatt.requestMtu(517) + if (!requesting) { + throw IllegalStateException() + } + getMaximumWriteLengthCallbacks[peripheralHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun readRSSI(peripheralHashCodeArgs: Long, callback: (Result) -> Unit) { + try { + val unfinishedCallback = readRssiCallbacks[peripheralHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val reading = gatt.readRemoteRssi() + if (!reading) { + throw IllegalStateException() + } + readRssiCallbacks[peripheralHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun discoverGATT(peripheralHashCodeArgs: Long, callback: (Result>) -> Unit) { + try { + val unfinishedCallback = discoverGattCallbacks[peripheralHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val discovering = gatt.discoverServices() + if (!discovering) { + throw IllegalStateException() + } + discoverGattCallbacks[peripheralHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun readCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, callback: (Result) -> Unit) { + try { + val unfinishedCallback = readCharacteristicCallbacks[characteristicHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic + val reading = gatt.readCharacteristic(characteristic) + if (!reading) { + throw IllegalStateException() + } + readCharacteristicCallbacks[characteristicHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun writeCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, typeNumberArgs: Long, callback: (Result) -> Unit) { + try { + val unfinishedCallback = writeCharacteristicCallbacks[characteristicHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic + val typeArgs = typeNumberArgs.toWriteTypeArgs() + val type = typeArgs.toType() + val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val code = gatt.writeCharacteristic(characteristic, valueArgs, type) + code == BluetoothStatusCodes.SUCCESS + } else { + // TODO: remove this when minSdkVersion >= 33 + characteristic.value = valueArgs + characteristic.writeType = type + gatt.writeCharacteristic(characteristic) + } + if (!writing) { + throw IllegalStateException() + } + writeCharacteristicCallbacks[characteristicHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun notifyCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, stateArgs: Boolean, callback: (Result) -> Unit) { + try { + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic + val notifying = gatt.setCharacteristicNotification(characteristic, stateArgs) + if (!notifying) { + throw IllegalStateException() + } + // TODO: Seems the docs is not correct, this operation is necessary for all characteristics. + // https://developer.android.com/guide/topics/connectivity/bluetooth/transfer-ble-data#notification + // This is specific to Heart Rate Measurement. +// if (characteristic.uuid == UUID_HEART_RATE_MEASUREMENT) { + val descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID) + val descriptorHashCode = descriptor.hashCode() + val descriptorArgs = descriptorsArgs[descriptorHashCode] as MyGattDescriptorArgs + val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + val unfinishedCallback = writeDescriptorCallbacks[descriptorHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val value = if (stateArgs) BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + else BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE + val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val code = gatt.writeDescriptor(descriptor, value) + code == BluetoothStatusCodes.SUCCESS + } else { + // TODO: remove this when minSdkVersion >= 33 + descriptor.value = value + gatt.writeDescriptor(descriptor) + } + if (!writing) { + throw IllegalStateException() + } + writeDescriptorCallbacks[descriptorHashCodeArgs] = callback +// } else { +// callback(Result.success(Unit)) +// } + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun readDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, callback: (Result) -> Unit) { + try { + val unfinishedCallback = readDescriptorCallbacks[descriptorHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val descriptor = descriptors[descriptorHashCodeArgs] as BluetoothGattDescriptor + val reading = gatt.readDescriptor(descriptor) + if (!reading) { + throw IllegalStateException() + } + readDescriptorCallbacks[descriptorHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun writeDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result) -> Unit) { + try { + val unfinishedCallback = writeDescriptorCallbacks[descriptorHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt + val descriptor = descriptors[descriptorHashCodeArgs] as BluetoothGattDescriptor + val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val code = gatt.writeDescriptor(descriptor, valueArgs) + code == BluetoothStatusCodes.SUCCESS + } else { + // TODO: remove this when minSdkVersion >= 33 + descriptor.value = valueArgs + gatt.writeDescriptor(descriptor) + } + if (!writing) { + throw IllegalStateException() + } + writeDescriptorCallbacks[descriptorHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean { + if (requestCode != REQUEST_CODE) { + return false + } + val authorized = results.all { r -> r == PackageManager.PERMISSION_GRANTED } + val callback = setUpCallback ?: return false + setUpCallback = null + val stateArgs = if (authorized) adapter.stateArgs + else MyBluetoothLowEnergyStateArgs.UNAUTHORIZED + val stateNumberArgs = stateArgs.raw.toLong() + val args = MyCentralManagerArgs(stateNumberArgs) + callback(Result.success(args)) + if (authorized) { + register() + } + return true + } + + override fun onReceive(intent: Intent) { + val action = intent.action + if (action != BluetoothAdapter.ACTION_STATE_CHANGED) { + return + } + val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF) + val stateArgs = state.toBluetoothLowEnergyStateArgs() + val stateNumberArgs = stateArgs.raw.toLong() + api.onStateChanged(stateNumberArgs) {} + } + + private fun onScanSucceed() { + discovering = true + val callback = startDiscoveryCallback ?: return + startDiscoveryCallback = null + callback(Result.success(Unit)) + } + + fun onScanFailed(errorCode: Int) { + val callback = startDiscoveryCallback ?: return + startDiscoveryCallback = null + val error = IllegalStateException("Start discovery failed with error code: $errorCode") + callback(Result.failure(error)) + } + + fun onScanResult(result: ScanResult) { + val device = result.device + val peripheralArgs = device.toPeripheralArgs() + val hashCode = device.hashCode() + val hashCodeArgs = peripheralArgs.hashCodeArgs + this.devices[hashCodeArgs] = device + this.peripheralsArgs[hashCode] = peripheralArgs + val rssiArgs = result.rssi.toLong() + val advertiseDataArgs = result.advertiseDataArgs + api.onDiscovered(peripheralArgs, rssiArgs, advertiseDataArgs) {} + } + + fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { + val device = gatt.device + val deviceHashCode = device.hashCode() + val peripheralArgs = peripheralsArgs[deviceHashCode] as MyPeripheralArgs + val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + // Check callbacks + if (newState != BluetoothProfile.STATE_CONNECTED) { + gatt.close() + bluetoothGATTs.remove(peripheralHashCodeArgs) + val error = IllegalStateException("GATT is disconnected with status: $status") + val getMaximumWriteLengthCallback = getMaximumWriteLengthCallbacks.remove(peripheralHashCodeArgs) + if (getMaximumWriteLengthCallback != null) { + getMaximumWriteLengthCallback(Result.failure(error)) + } + val readRssiCallback = readRssiCallbacks.remove(peripheralHashCodeArgs) + if (readRssiCallback != null) { + readRssiCallback(Result.failure(error)) + } + val discoverGattCallback = discoverGattCallbacks.remove(peripheralHashCodeArgs) + if (discoverGattCallback != null) { + discoverGattCallback(Result.failure(error)) + } + val servicesArgs = servicesArgsOfPeripherals[peripheralHashCodeArgs] ?: emptyList() + for (serviceArgs in servicesArgs) { + val characteristicsArgs = serviceArgs.characteristicsArgs.filterNotNull() + for (characteristicArgs in characteristicsArgs) { + val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristicHashCodeArgs) + val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristicHashCodeArgs) + if (readCharacteristicCallback != null) { + readCharacteristicCallback(Result.failure(error)) + } + if (writeCharacteristicCallback != null) { + writeCharacteristicCallback(Result.failure(error)) + } + val descriptorsArgs = characteristicArgs.descriptorsArgs.filterNotNull() + for (descriptorArgs in descriptorsArgs) { + val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + val readDescriptorCallback = readDescriptorCallbacks.remove(descriptorHashCodeArgs) + val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptorHashCodeArgs) + if (readDescriptorCallback != null) { + readDescriptorCallback(Result.failure(error)) + } + if (writeDescriptorCallback != null) { + writeDescriptorCallback(Result.failure(error)) + } + } + } + } + } + // Check state + val connectCallback = connectCallbacks.remove(peripheralHashCodeArgs) + val disconnectCallback = disconnectCallbacks.remove(peripheralHashCodeArgs) + if (connectCallback == null && disconnectCallback == null) { + // State changed. + val stateArgs = newState == BluetoothProfile.STATE_CONNECTED + api.onPeripheralStateChanged(peripheralArgs, stateArgs) {} + } else { + if (connectCallback != null) { + if (status == BluetoothGatt.GATT_SUCCESS) { + // Connect succeed. + connectCallback(Result.success(Unit)) + api.onPeripheralStateChanged(peripheralArgs, true) {} + } else { + // Connect failed. + val error = IllegalStateException("Connect failed with status: $status") + connectCallback(Result.failure(error)) + } + } + if (disconnectCallback != null) { + if (status == BluetoothGatt.GATT_SUCCESS) { + // Disconnect succeed. + disconnectCallback(Result.success(Unit)) + api.onPeripheralStateChanged(peripheralArgs, false) {} + } else { + // Disconnect failed. + val error = IllegalStateException("Connect failed with status: $status") + disconnectCallback(Result.failure(error)) + } + } + } + } + + fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { + val device = gatt.device + val hashCode = device.hashCode() + val peripheralArgs = peripheralsArgs[hashCode] as MyPeripheralArgs + val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + val callback = getMaximumWriteLengthCallbacks.remove(peripheralHashCodeArgs) ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + val maximumWriteLengthArgs = (mtu - 3).toLong() + callback(Result.success(maximumWriteLengthArgs)) + } else { + val error = IllegalStateException("Get maximum write length failed with status: $status") + callback(Result.failure(error)) + } + } + + fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) { + val device = gatt.device + val hashCode = device.hashCode() + val peripheralArgs = peripheralsArgs[hashCode] as MyPeripheralArgs + val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + val callback = readRssiCallbacks.remove(peripheralHashCodeArgs) ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + val rssiArgs = rssi.toLong() + callback(Result.success(rssiArgs)) + } else { + val error = IllegalStateException("Read rssi failed with status: $status") + callback(Result.failure(error)) + } + } + + fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { + val device = gatt.device + val deviceHashCode = device.hashCode() + val peripheralArgs = peripheralsArgs[deviceHashCode] as MyPeripheralArgs + val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + val callback = discoverGattCallbacks.remove(peripheralHashCodeArgs) ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + val services = gatt.services + val servicesArgs = mutableListOf() + for (service in services) { + val characteristics = service.characteristics + val characteristicsArgs = mutableListOf() + for (characteristic in characteristics) { + val descriptors = characteristic.descriptors + val descriptorsArgs = mutableListOf() + for (descriptor in descriptors) { + val descriptorArgs = descriptor.toManufacturerSpecificDataArgs() + val descriptorHashCode = descriptor.hashCode() + val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + this.descriptors[descriptorHashCodeArgs] = descriptor + this.descriptorsArgs[descriptorHashCode] = descriptorArgs + descriptorsArgs.add(descriptorArgs) + } + val characteristicArgs = characteristic.toManufacturerSpecificDataArgs(descriptorsArgs) + val characteristicHashCode = characteristic.hashCode() + val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + this.characteristics[characteristicHashCodeArgs] = characteristic + this.characteristicsArgs[characteristicHashCode] = characteristicArgs + characteristicsArgs.add(characteristicArgs) + } + val serviceArgs = service.toManufacturerSpecificDataArgs(characteristicsArgs) + val serviceHashCode = service.hashCode() + val serviceHashCodeArgs = serviceArgs.hashCodeArgs + this.services[serviceHashCodeArgs] = service + this.servicesArgs[serviceHashCode] = serviceArgs + servicesArgs.add(serviceArgs) + } + servicesArgsOfPeripherals[peripheralHashCodeArgs] = servicesArgs + callback(Result.success(servicesArgs)) + } else { + val error = IllegalStateException("Discover GATT failed with status: $status") + callback(Result.failure(error)) + } + } + + fun onCharacteristicRead(characteristic: BluetoothGattCharacteristic, status: Int, value: ByteArray) { + val hashCode = characteristic.hashCode() + val characteristicArgs = characteristicsArgs[hashCode] as MyGattCharacteristicArgs + val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + val callback = readCharacteristicCallbacks.remove(characteristicHashCodeArgs) ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + callback(Result.success(value)) + } else { + val error = IllegalStateException("Read characteristic failed with status: $status.") + callback(Result.failure(error)) + } + } + + fun onCharacteristicWrite(characteristic: BluetoothGattCharacteristic, status: Int) { + val hashCode = characteristic.hashCode() + val characteristicArgs = characteristicsArgs[hashCode] as MyGattCharacteristicArgs + val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + val callback = writeCharacteristicCallbacks.remove(characteristicHashCodeArgs) ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + callback(Result.success(Unit)) + } else { + val error = IllegalStateException("Write characteristic failed with status: $status.") + callback(Result.failure(error)) + } + } + + fun onCharacteristicChanged(characteristic: BluetoothGattCharacteristic, value: ByteArray) { + val hashCode = characteristic.hashCode() + val characteristicArgs = characteristicsArgs[hashCode] as MyGattCharacteristicArgs + api.onCharacteristicValueChanged(characteristicArgs, value) {} + } + + fun onDescriptorRead(descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray) { + val hashCode = descriptor.hashCode() + val descriptorArgs = descriptorsArgs[hashCode] as MyGattDescriptorArgs + val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + val callback = readDescriptorCallbacks.remove(descriptorHashCodeArgs) ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + callback(Result.success(value)) + } else { + val error = IllegalStateException("Read descriptor failed with status: $status.") + callback(Result.failure(error)) + } + } + + fun onDescriptorWrite(descriptor: BluetoothGattDescriptor, status: Int) { + val hashCode = descriptor.hashCode() + val descriptorArgs = descriptorsArgs[hashCode] as MyGattDescriptorArgs + val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + val callback = writeDescriptorCallbacks.remove(descriptorHashCodeArgs) ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + callback(Result.success(Unit)) + } else { + val error = IllegalStateException("Write descriptor failed with status: $status.") + callback(Result.failure(error)) + } + } +} diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyPeripheralManager.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyPeripheralManager.kt new file mode 100644 index 0000000..9ae546c --- /dev/null +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyPeripheralManager.kt @@ -0,0 +1,423 @@ +package dev.yanshouwang.bluetooth_low_energy_android + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothGattService +import android.bluetooth.BluetoothStatusCodes +import android.bluetooth.le.AdvertiseSettings +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.util.Log +import io.flutter.plugin.common.BinaryMessenger + +class MyPeripheralManager(private val context: Context, binaryMessenger: BinaryMessenger) : MyBluetoothLowEnergyManager(context), MyPeripheralManagerHostApi { + private val server by lazy { manager.openGattServer(context, bluetoothGattServerCallback) } + private val advertiser get() = adapter.bluetoothLeAdvertiser + + private val api = MyPeripheralManagerFlutterApi(binaryMessenger) + private val bluetoothGattServerCallback = MyBluetoothGattServerCallback(this, executor) + private val advertiseCallback = MyAdvertiseCallback(this) + + private val devices = mutableMapOf() + private val services = mutableMapOf() + private val characteristics = mutableMapOf() + private val descriptors = mutableMapOf() + private val mtus = mutableMapOf() + private val confirms = mutableMapOf() + + private val centralsArgs = mutableMapOf() + private val servicesArgs = mutableMapOf() + private val characteristicsArgs = mutableMapOf() + private val descriptorsArgs = mutableMapOf() + + private var registered = false + private var advertising = false + + private var setUpCallback: ((Result) -> Unit)? = null + private var addServiceCallback: ((Result) -> Unit)? = null + private var startAdvertisingCallback: ((Result) -> Unit)? = null + private val notifyCharacteristicValueChangedCallbacks = mutableMapOf) -> Unit>() + + override fun setUp(callback: (Result) -> Unit) { + try { + val unfinishedCallback = setUpCallback + if (unfinishedCallback != null) { + throw IllegalStateException() + } + tearDown() + if (unsupported) { + val stateNumberArgs = MyBluetoothLowEnergyStateArgs.UNSUPPORTED.raw.toLong() + val args = MyPeripheralManagerArgs(stateNumberArgs) + callback(Result.success(args)) + } + val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT) + } else { + arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION) + } + authorize(permissions) + setUpCallback = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + private fun tearDown() { + if (registered) { + unregister() + } + if (advertising) { + stopAdvertising() + } + devices.clear() + services.clear() + characteristics.clear() + descriptors.clear() + mtus.clear() + confirms.clear() + centralsArgs.clear() + servicesArgs.clear() + characteristicsArgs.clear() + descriptorsArgs.clear() + setUpCallback = null + addServiceCallback = null + startAdvertisingCallback = null + notifyCharacteristicValueChangedCallbacks.clear() + } + + override fun register() { + super.register() + registered = true + } + + override fun unregister() { + super.unregister() + registered = false + } + + override fun addService(serviceArgs: MyGattServiceArgs, callback: (Result) -> Unit) { + try { + val unfinishedCallback = addServiceCallback + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val service = serviceArgs.toService() + val characteristicsArgs = serviceArgs.characteristicsArgs.filterNotNull() + for (characteristicArgs in characteristicsArgs) { + val characteristic = characteristicArgs.toCharacteristic() + val cccDescriptor = BluetoothGattDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID, BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE) + val cccDescriptorAdded = characteristic.addDescriptor(cccDescriptor) + if (!cccDescriptorAdded) { + throw IllegalStateException() + } + val descriptorsArgs = characteristicArgs.descriptorsArgs.filterNotNull() + for (descriptorArgs in descriptorsArgs) { + val descriptor = descriptorArgs.toDescriptor() + if (descriptor.uuid == CLIENT_CHARACTERISTIC_CONFIG_UUID) { + // Already added. + continue + } + val descriptorAdded = characteristic.addDescriptor(descriptor) + if (!descriptorAdded) { + throw IllegalStateException() + } + val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + val descriptorHashCode = descriptor.hashCode() + this.descriptorsArgs[descriptorHashCode] = descriptorArgs + this.descriptors[descriptorHashCodeArgs] = descriptor + } + val characteristicAdded = service.addCharacteristic(characteristic) + if (!characteristicAdded) { + throw IllegalStateException() + } + val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + val characteristicHashCode = characteristic.hashCode() + this.characteristicsArgs[characteristicHashCode] = characteristicArgs + this.characteristics[characteristicHashCodeArgs] = characteristic + } + val adding = server.addService(service) + if (!adding) { + throw IllegalStateException() + } + val serviceHashCodeArgs = serviceArgs.hashCodeArgs + val serviceHashCode = service.hashCode() + this.servicesArgs[serviceHashCode] = serviceArgs + this.services[serviceHashCodeArgs] = service + addServiceCallback = callback + } catch (e: Throwable) { + freeService(serviceArgs) + callback(Result.failure(e)) + } + } + + override fun removeService(serviceHashCodeArgs: Long) { + val service = services[serviceHashCodeArgs] as BluetoothGattService + val serviceHashCode = service.hashCode() + val serviceArgs = servicesArgs[serviceHashCode] as MyGattServiceArgs + val removed = server.removeService(service) + if (!removed) { + throw IllegalStateException() + } + freeService(serviceArgs) + } + + private fun freeService(serviceArgs: MyGattServiceArgs) { + val characteristicsArgs = serviceArgs.characteristicsArgs.filterNotNull() + for (characteristicArgs in characteristicsArgs) { + val descriptorsArgs = characteristicArgs.descriptorsArgs.filterNotNull() + for (descriptorArgs in descriptorsArgs) { + val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + val descriptor = this.descriptors.remove(descriptorHashCodeArgs) ?: continue + val descriptorHashCode = descriptor.hashCode() + this.descriptorsArgs.remove(descriptorHashCode) + } + val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + val characteristic = this.characteristics.remove(characteristicHashCodeArgs) ?: continue + this.confirms.remove(characteristicHashCodeArgs) + val characteristicHashCode = characteristic.hashCode() + this.characteristicsArgs.remove(characteristicHashCode) + } + val serviceHashCodeArgs = serviceArgs.hashCodeArgs + val service = services.remove(serviceHashCodeArgs) ?: return + val serviceHashCode = service.hashCode() + servicesArgs.remove(serviceHashCode) + } + + override fun clearServices() { + server.clearServices() + val servicesArgs = this.servicesArgs.values + for (serviceArgs in servicesArgs) { + freeService(serviceArgs) + } + } + + override fun startAdvertising(advertiseDataArgs: MyAdvertiseDataArgs, callback: (Result) -> Unit) { + try { + if (startAdvertisingCallback != null) { + throw IllegalStateException() + } + val settings = AdvertiseSettings.Builder().setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED).setConnectable(true).build() + val advertiseData = advertiseDataArgs.toAdvertiseData(adapter) + advertiser.startAdvertising(settings, advertiseData, advertiseCallback) + startAdvertisingCallback = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun stopAdvertising() { + advertiser.stopAdvertising(advertiseCallback) + advertising = false + } + + override fun getMaximumWriteLength(centralHashCodeArgs: Long): Long { + val mtu = mtus[centralHashCodeArgs] ?: 23 + return (mtu - 3).toLong() + } + + override fun sendReadCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean, valueArgs: ByteArray) { + val device = devices[centralHashCodeArgs] as BluetoothDevice + val requestId = idArgs.toInt() + val status = if (statusArgs) BluetoothGatt.GATT_SUCCESS + else BluetoothGatt.GATT_FAILURE + val offset = offsetArgs.toInt() + val sent = server.sendResponse(device, requestId, status, offset, valueArgs) + if (!sent) { + throw IllegalStateException("Send read characteristic reply failed.") + } + } + + override fun sendWriteCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean) { + val device = devices[centralHashCodeArgs] as BluetoothDevice + val requestId = idArgs.toInt() + val status = if (statusArgs) BluetoothGatt.GATT_SUCCESS + else BluetoothGatt.GATT_FAILURE + val offset = offsetArgs.toInt() + val value = null + val sent = server.sendResponse(device, requestId, status, offset, value) + if (!sent) { + throw IllegalStateException("Send write characteristic reply failed.") + } + } + + override fun notifyCharacteristicValueChanged(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result) -> Unit) { + try { + val unfinishedCallback = notifyCharacteristicValueChangedCallbacks[centralHashCodeArgs] + if (unfinishedCallback != null) { + throw IllegalStateException() + } + val device = devices[centralHashCodeArgs] as BluetoothDevice + val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic + val confirm = confirms[characteristicHashCodeArgs] + ?: throw IllegalStateException("The characteristic is not subscribed.") + val notifying = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val statusCode = server.notifyCharacteristicChanged(device, characteristic, confirm, valueArgs) + statusCode == BluetoothStatusCodes.SUCCESS + } else { + characteristic.value = valueArgs + server.notifyCharacteristicChanged(device, characteristic, confirm) + } + if (!notifying) { + throw IllegalStateException() + } + notifyCharacteristicValueChangedCallbacks[centralHashCodeArgs] = callback + } catch (e: Throwable) { + callback(Result.failure(e)) + } + } + + override fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean { + if (requestCode != REQUEST_CODE) { + return false + } + val authorized = results.all { r -> r == PackageManager.PERMISSION_GRANTED } + val callback = setUpCallback ?: return false + setUpCallback = null + val stateArgs = if (authorized) adapter.stateArgs + else MyBluetoothLowEnergyStateArgs.UNAUTHORIZED + val stateNumberArgs = stateArgs.raw.toLong() + val args = MyPeripheralManagerArgs(stateNumberArgs) + callback(Result.success(args)) + if (authorized) { + register() + } + return true + } + + override fun onReceive(intent: Intent) { + val action = intent.action + if (action != BluetoothAdapter.ACTION_STATE_CHANGED) { + return + } + val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF) + val stateArgs = state.toBluetoothLowEnergyStateArgs() + val stateNumberArgs = stateArgs.raw.toLong() + api.onStateChanged(stateNumberArgs) {} + } + + fun onServiceAdded(status: Int, service: BluetoothGattService) { + val callback = addServiceCallback ?: return + addServiceCallback = null + if (status == BluetoothGatt.GATT_SUCCESS) { + callback(Result.success(Unit)) + } else { + val hashCode = service.hashCode() + val serviceArgs = servicesArgs[hashCode] as MyGattServiceArgs + freeService(serviceArgs) + val error = IllegalStateException("Read rssi failed with status: $status") + callback(Result.failure(error)) + } + } + + fun onStartSuccess(settingsInEffect: AdvertiseSettings) { + advertising = true + val callback = startAdvertisingCallback ?: return + startAdvertisingCallback = null + callback(Result.success(Unit)) + } + + fun onStartFailure(errorCode: Int) { + val callback = startAdvertisingCallback ?: return + startAdvertisingCallback = null + val error = IllegalStateException("Start advertising failed with error code: $errorCode") + callback(Result.failure(error)) + } + + fun onMtuChanged(device: BluetoothDevice, mtu: Int) { + val hashCode = device.hashCode() + val centralArgs = centralsArgs.getOrPut(hashCode) { device.toCentralArgs() } + val centralHashCodeArgs = centralArgs.hashCodeArgs + devices[centralHashCodeArgs] = device + mtus[centralHashCodeArgs] = mtu + } + + fun onCharacteristicReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, characteristic: BluetoothGattCharacteristic) { + val deviceHashCode = device.hashCode() + val centralArgs = centralsArgs.getOrPut(deviceHashCode) { device.toCentralArgs() } + val centralHashCodeArgs = centralArgs.hashCodeArgs + devices[centralHashCodeArgs] = device + val characteristicHashCode = characteristic.hashCode() + val characteristicArgs = characteristicsArgs[characteristicHashCode] as MyGattCharacteristicArgs + val idArgs = requestId.toLong() + val offsetArgs = offset.toLong() + api.onReadCharacteristicCommandReceived(centralArgs, characteristicArgs, idArgs, offsetArgs) {} + } + + fun onCharacteristicWriteRequest(device: BluetoothDevice, requestId: Int, characteristic: BluetoothGattCharacteristic, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) { + val deviceHashCode = device.hashCode() + val centralArgs = centralsArgs.getOrPut(deviceHashCode) { device.toCentralArgs() } + val centralHashCodeArgs = centralArgs.hashCodeArgs + devices[centralHashCodeArgs] = device + val characteristicHashCode = characteristic.hashCode() + val characteristicArgs = characteristicsArgs[characteristicHashCode] as MyGattCharacteristicArgs + val idArgs = requestId.toLong() + val offsetArgs = offset.toLong() + api.onWriteCharacteristicCommandReceived(centralArgs, characteristicArgs, idArgs, offsetArgs, value) {} + } + + fun onDescriptorReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, descriptor: BluetoothGattDescriptor) { + val status = BluetoothGatt.GATT_SUCCESS + val descriptorHashCode = descriptor.hashCode() + val descriptorArgs = descriptorsArgs[descriptorHashCode] as MyGattDescriptorArgs + val value = descriptorArgs.valueArgs + val sent = server.sendResponse(device, requestId, status, offset, value) + if (!sent) { + Log.e(TAG, "onDescriptorReadRequest: send response failed.") + } + } + + fun onDescriptorWriteRequest(device: BluetoothDevice, requestId: Int, descriptor: BluetoothGattDescriptor, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) { + val status = if (descriptor.uuid == CLIENT_CHARACTERISTIC_CONFIG_UUID) { + val deviceHashCode = device.hashCode() + val centralArgs = centralsArgs.getOrPut(deviceHashCode) { device.toCentralArgs() } + val centralHashCodeArgs = centralArgs.hashCodeArgs + devices[centralHashCodeArgs] = device + val characteristic = descriptor.characteristic + val characteristicHashCode = characteristic.hashCode() + val characteristicArgs = characteristicsArgs[characteristicHashCode] as MyGattCharacteristicArgs + val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + // TODO: what is 中缀? + if (value contentEquals BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) { + confirms[characteristicHashCodeArgs] = false + val stateArgs = true + api.onNotifyCharacteristicCommandReceived(centralArgs, characteristicArgs, stateArgs) {} + BluetoothGatt.GATT_SUCCESS + } else if (value contentEquals BluetoothGattDescriptor.ENABLE_INDICATION_VALUE) { + confirms[characteristicHashCodeArgs] = true + val stateArgs = true + api.onNotifyCharacteristicCommandReceived(centralArgs, characteristicArgs, stateArgs) {} + BluetoothGatt.GATT_SUCCESS + } else if (value contentEquals BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) { + confirms.remove(characteristicHashCodeArgs) + val stateArgs = false + api.onNotifyCharacteristicCommandReceived(centralArgs, characteristicArgs, stateArgs) {} + BluetoothGatt.GATT_SUCCESS + } else { + BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED + } + } else BluetoothGatt.GATT_SUCCESS + val sent = server.sendResponse(device, requestId, status, offset, value) + if (!sent) { + Log.e(TAG, "onDescriptorReadRequest: send response failed.") + } + } + + fun onNotificationSent(device: BluetoothDevice, status: Int) { + val deviceHashCode = device.hashCode() + val centralArgs = centralsArgs[deviceHashCode] as MyCentralArgs + val centralHashCodeArgs = centralArgs.hashCodeArgs + val callback = notifyCharacteristicValueChangedCallbacks.remove(centralHashCodeArgs) + ?: return + if (status == BluetoothGatt.GATT_SUCCESS) { + callback(Result.success(Unit)) + } else { + val error = IllegalStateException("Notify characteristic value changed failed with status: $status") + callback(Result.failure(error)) + } + } +} \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyRequestPermissionResultListener.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyRequestPermissionResultListener.kt index 90c285e..a16e994 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyRequestPermissionResultListener.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyRequestPermissionResultListener.kt @@ -2,8 +2,8 @@ package dev.yanshouwang.bluetooth_low_energy_android import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener -class MyRequestPermissionResultListener(private val myCentralController: MyCentralController) : RequestPermissionsResultListener { +class MyRequestPermissionResultListener(private val bluetoothLowEnergyManager: MyBluetoothLowEnergyManager) : RequestPermissionsResultListener { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, results: IntArray): Boolean { - return myCentralController.onRequestPermissionsResult(requestCode, results) + return bluetoothLowEnergyManager.onRequestPermissionsResult(requestCode, results) } } \ No newline at end of file diff --git a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyScanCallback.kt b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyScanCallback.kt index e576746..cf0ace4 100644 --- a/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyScanCallback.kt +++ b/bluetooth_low_energy_android/android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy_android/MyScanCallback.kt @@ -3,14 +3,14 @@ package dev.yanshouwang.bluetooth_low_energy_android import android.bluetooth.le.ScanCallback import android.bluetooth.le.ScanResult -class MyScanCallback(private val myCentralController: MyCentralController) : ScanCallback() { +class MyScanCallback(private val centralManager: MyCentralManager) : ScanCallback() { override fun onScanFailed(errorCode: Int) { super.onScanFailed(errorCode) - myCentralController.onScanFailed(errorCode) + centralManager.onScanFailed(errorCode) } override fun onScanResult(callbackType: Int, result: ScanResult) { super.onScanResult(callbackType, result) - myCentralController.onScanResult(result) + centralManager.onScanResult(result) } } \ No newline at end of file diff --git a/bluetooth_low_energy_android/lib/bluetooth_low_energy_android.dart b/bluetooth_low_energy_android/lib/bluetooth_low_energy_android.dart index 59e70e3..3833335 100644 --- a/bluetooth_low_energy_android/lib/bluetooth_low_energy_android.dart +++ b/bluetooth_low_energy_android/lib/bluetooth_low_energy_android.dart @@ -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 BluetoothLowEnergyAndroid { static void registerWith() { - CentralController.instance = MyCentralController(); + BluetoothLowEnergy.instance = MyBluetoothLowEnergy(); } } diff --git a/bluetooth_low_energy_android/lib/src/my_api.dart b/bluetooth_low_energy_android/lib/src/my_api.dart new file mode 100644 index 0000000..e68f13e --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_api.dart @@ -0,0 +1,224 @@ +import 'dart:typed_data'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_api.g.dart'; +import 'my_gatt_characteristic2.dart'; +import 'my_gatt_descriptor2.dart'; +import 'my_gatt_service2.dart'; + +export 'my_api.g.dart'; + +extension MyBluetoothLowEnergyStateArgsX on MyBluetoothLowEnergyStateArgs { + BluetoothLowEnergyState toState() { + return BluetoothLowEnergyState.values[index]; + } +} + +extension MyAdvertiseDataArgsX on MyAdvertiseDataArgs { + AdvertiseData toAdvertiseData() { + final name = nameArgs; + final serviceUUIDs = serviceUUIDsArgs + .cast() + .map((args) => UUID.fromString(args)) + .toList(); + final serviceData = serviceDataArgs.cast().map( + (uuidArgs, dataArgs) { + final uuid = UUID.fromString(uuidArgs); + final data = dataArgs; + return MapEntry(uuid, data); + }, + ); + final manufacturerSpecificData = + manufacturerSpecificDataArgs?.toManufacturerSpecificData(); + return AdvertiseData( + name: name, + serviceUUIDs: serviceUUIDs, + serviceData: serviceData, + manufacturerSpecificData: manufacturerSpecificData, + ); + } +} + +extension MyManufacturerSpecificDataArgsX on MyManufacturerSpecificDataArgs { + ManufacturerSpecificData toManufacturerSpecificData() { + final id = idArgs; + final data = dataArgs; + return ManufacturerSpecificData( + id: id, + data: data, + ); + } +} + +extension MyGattCharacteristicPropertyArgsX + on MyGattCharacteristicPropertyArgs { + GattCharacteristicProperty toProperty() { + return GattCharacteristicProperty.values[index]; + } +} + +extension GattCharacteristicWriteTypeX on GattCharacteristicWriteType { + MyGattCharacteristicWriteTypeArgs toArgs() { + return MyGattCharacteristicWriteTypeArgs.values[index]; + } +} + +extension MyPeripheralArgsX on MyPeripheralArgs { + MyPeripheral toPeripheral() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + return MyPeripheral( + hashCode: hashCode, + uuid: uuid, + ); + } +} + +extension MyGattServiceArgsX on MyGattServiceArgs { + MyGattService2 toService2() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + final characteristics = characteristicsArgs + .cast() + .map((args) => args.toCharacteristic2()) + .toList(); + return MyGattService2( + hashCode: hashCode, + uuid: uuid, + characteristics: characteristics, + ); + } +} + +extension MyGattCharacteristicArgsX on MyGattCharacteristicArgs { + MyGattCharacteristic2 toCharacteristic2() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + final properties = propertyNumbersArgs.cast().map( + (args) { + final propertyArgs = MyGattCharacteristicPropertyArgs.values[args]; + return propertyArgs.toProperty(); + }, + ).toList(); + final descriptors = descriptorsArgs + .cast() + .map((args) => args.toDescriptor2()) + .toList(); + return MyGattCharacteristic2( + hashCode: hashCode, + uuid: uuid, + properties: properties, + descriptors: descriptors, + ); + } +} + +extension MyGattDescriptorArgsX on MyGattDescriptorArgs { + MyGattDescriptor2 toDescriptor2() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + return MyGattDescriptor2( + hashCode: hashCode, + uuid: uuid, + ); + } +} + +extension MyCentralArgsX on MyCentralArgs { + MyCentral toCentral() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + return MyCentral( + hashCode: hashCode, + uuid: uuid, + ); + } +} + +extension AdvertiseDataX on AdvertiseData { + MyAdvertiseDataArgs toArgs() { + final nameArgs = name; + final serviceUUIDsArgs = + serviceUUIDs.map((uuid) => uuid.toString()).toList(); + final serviceDataArgs = serviceData.map((uuid, data) { + final uuidArgs = uuid.toString(); + final dataArgs = data; + return MapEntry(uuidArgs, dataArgs); + }); + final manufacturerSpecificDataArgs = manufacturerSpecificData?.toArgs(); + return MyAdvertiseDataArgs( + nameArgs: nameArgs, + serviceUUIDsArgs: serviceUUIDsArgs, + serviceDataArgs: serviceDataArgs, + manufacturerSpecificDataArgs: manufacturerSpecificDataArgs, + ); + } +} + +extension ManufacturerSpecificDataX on ManufacturerSpecificData { + MyManufacturerSpecificDataArgs toArgs() { + final idArgs = id; + final dataArgs = data; + return MyManufacturerSpecificDataArgs( + idArgs: idArgs, + dataArgs: dataArgs, + ); + } +} + +extension MyGattServiceX on MyGattService { + MyGattServiceArgs toArgs() { + final hashCodeArgs = hashCode; + final uuidArgs = uuid.toString(); + final characteristicsArgs = characteristics + .cast() + .map((characteristic) => characteristic.toArgs()) + .toList(); + return MyGattServiceArgs( + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + characteristicsArgs: characteristicsArgs, + ); + } +} + +extension MyGattCharacteristicX on MyGattCharacteristic { + MyGattCharacteristicArgs toArgs() { + final hashCodeArgs = hashCode; + final uuidArgs = uuid.toString(); + final propertyNumbersArgs = properties.map((property) { + final propertyArgs = property.toArgs(); + return propertyArgs.index; + }).toList(); + final descriptorsArgs = descriptors + .cast() + .map((descriptor) => descriptor.toArgs()) + .toList(); + return MyGattCharacteristicArgs( + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + propertyNumbersArgs: propertyNumbersArgs, + descriptorsArgs: descriptorsArgs, + ); + } +} + +extension MyGattDescriptorX on MyGattDescriptor { + MyGattDescriptorArgs toArgs() { + final hashCodeArgs = hashCode; + final uuidArgs = uuid.toString(); + final valueArgs = value; + return MyGattDescriptorArgs( + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + valueArgs: valueArgs, + ); + } +} + +extension GattCharacteristicPropertyX on GattCharacteristicProperty { + MyGattCharacteristicPropertyArgs toArgs() { + return MyGattCharacteristicPropertyArgs.values[index]; + } +} diff --git a/bluetooth_low_energy_android/lib/src/my_api.g.dart b/bluetooth_low_energy_android/lib/src/my_api.g.dart index e76744a..3c7ee65 100644 --- a/bluetooth_low_energy_android/lib/src/my_api.g.dart +++ b/bluetooth_low_energy_android/lib/src/my_api.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.1.6), do not edit directly. +// Autogenerated from Pigeon (v11.0.1), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import @@ -8,7 +8,7 @@ import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; -enum MyCentralStateArgs { +enum MyBluetoothLowEnergyStateArgs { unknown, unsupported, unauthorized, @@ -29,177 +29,267 @@ enum MyGattCharacteristicWriteTypeArgs { withoutResponse, } -class MyCentralControllerArgs { - MyCentralControllerArgs({ - required this.myStateNumber, +class MyCentralManagerArgs { + MyCentralManagerArgs({ + required this.stateNumberArgs, }); - int myStateNumber; + int stateNumberArgs; Object encode() { return [ - myStateNumber, + stateNumberArgs, ]; } - static MyCentralControllerArgs decode(Object result) { + static MyCentralManagerArgs decode(Object result) { result as List; - return MyCentralControllerArgs( - myStateNumber: result[0]! as int, + return MyCentralManagerArgs( + stateNumberArgs: result[0]! as int, + ); + } +} + +class MyPeripheralManagerArgs { + MyPeripheralManagerArgs({ + required this.stateNumberArgs, + }); + + int stateNumberArgs; + + Object encode() { + return [ + stateNumberArgs, + ]; + } + + static MyPeripheralManagerArgs decode(Object result) { + result as List; + return MyPeripheralManagerArgs( + stateNumberArgs: result[0]! as int, + ); + } +} + +class MyCentralArgs { + MyCentralArgs({ + required this.hashCodeArgs, + required this.uuidArgs, + }); + + int hashCodeArgs; + + String uuidArgs; + + Object encode() { + return [ + hashCodeArgs, + uuidArgs, + ]; + } + + static MyCentralArgs decode(Object result) { + result as List; + return MyCentralArgs( + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, ); } } class MyPeripheralArgs { MyPeripheralArgs({ - required this.key, - required this.uuid, + required this.hashCodeArgs, + required this.uuidArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; Object encode() { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, ]; } static MyPeripheralArgs decode(Object result) { result as List; return MyPeripheralArgs( - key: result[0]! as int, - uuid: result[1]! as String, + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, ); } } -class MyAdvertisementArgs { - MyAdvertisementArgs({ - this.name, - required this.manufacturerSpecificData, - required this.serviceUUIDs, - required this.serviceData, +class MyAdvertiseDataArgs { + MyAdvertiseDataArgs({ + this.nameArgs, + required this.serviceUUIDsArgs, + required this.serviceDataArgs, + this.manufacturerSpecificDataArgs, }); - String? name; + String? nameArgs; - Map manufacturerSpecificData; + List serviceUUIDsArgs; - List serviceUUIDs; + Map serviceDataArgs; - Map serviceData; + MyManufacturerSpecificDataArgs? manufacturerSpecificDataArgs; Object encode() { return [ - name, - manufacturerSpecificData, - serviceUUIDs, - serviceData, + nameArgs, + serviceUUIDsArgs, + serviceDataArgs, + manufacturerSpecificDataArgs?.encode(), ]; } - static MyAdvertisementArgs decode(Object result) { + static MyAdvertiseDataArgs decode(Object result) { result as List; - return MyAdvertisementArgs( - name: result[0] as String?, - manufacturerSpecificData: (result[1] as Map?)!.cast(), - serviceUUIDs: (result[2] as List?)!.cast(), - serviceData: (result[3] as Map?)!.cast(), + return MyAdvertiseDataArgs( + nameArgs: result[0] as String?, + serviceUUIDsArgs: (result[1] as List?)!.cast(), + serviceDataArgs: (result[2] as Map?)!.cast(), + manufacturerSpecificDataArgs: result[3] != null + ? MyManufacturerSpecificDataArgs.decode(result[3]! as List) + : null, + ); + } +} + +class MyManufacturerSpecificDataArgs { + MyManufacturerSpecificDataArgs({ + required this.idArgs, + required this.dataArgs, + }); + + int idArgs; + + Uint8List dataArgs; + + Object encode() { + return [ + idArgs, + dataArgs, + ]; + } + + static MyManufacturerSpecificDataArgs decode(Object result) { + result as List; + return MyManufacturerSpecificDataArgs( + idArgs: result[0]! as int, + dataArgs: result[1]! as Uint8List, ); } } class MyGattServiceArgs { MyGattServiceArgs({ - required this.key, - required this.uuid, + required this.hashCodeArgs, + required this.uuidArgs, + required this.characteristicsArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; + + List characteristicsArgs; Object encode() { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, + characteristicsArgs, ]; } static MyGattServiceArgs decode(Object result) { result as List; return MyGattServiceArgs( - key: result[0]! as int, - uuid: result[1]! as String, + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, + characteristicsArgs: (result[2] as List?)!.cast(), ); } } class MyGattCharacteristicArgs { MyGattCharacteristicArgs({ - required this.key, - required this.uuid, - required this.myPropertyNumbers, + required this.hashCodeArgs, + required this.uuidArgs, + required this.propertyNumbersArgs, + required this.descriptorsArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; - List myPropertyNumbers; + List propertyNumbersArgs; + + List descriptorsArgs; Object encode() { return [ - key, - uuid, - myPropertyNumbers, + hashCodeArgs, + uuidArgs, + propertyNumbersArgs, + descriptorsArgs, ]; } static MyGattCharacteristicArgs decode(Object result) { result as List; return MyGattCharacteristicArgs( - key: result[0]! as int, - uuid: result[1]! as String, - myPropertyNumbers: (result[2] as List?)!.cast(), + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, + propertyNumbersArgs: (result[2] as List?)!.cast(), + descriptorsArgs: (result[3] as List?)!.cast(), ); } } class MyGattDescriptorArgs { MyGattDescriptorArgs({ - required this.key, - required this.uuid, + required this.hashCodeArgs, + required this.uuidArgs, + this.valueArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; + + Uint8List? valueArgs; Object encode() { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, + valueArgs, ]; } static MyGattDescriptorArgs decode(Object result) { result as List; return MyGattDescriptorArgs( - key: result[0]! as int, - uuid: result[1]! as String, + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, + valueArgs: result[2] as Uint8List?, ); } } -class _MyCentralControllerHostApiCodec extends StandardMessageCodec { - const _MyCentralControllerHostApiCodec(); +class _MyCentralManagerHostApiCodec extends StandardMessageCodec { + const _MyCentralManagerHostApiCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is MyCentralControllerArgs) { + if (value is MyCentralManagerArgs) { buffer.putUint8(128); writeValue(buffer, value.encode()); } else if (value is MyGattCharacteristicArgs) { @@ -220,7 +310,7 @@ class _MyCentralControllerHostApiCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 128: - return MyCentralControllerArgs.decode(readValue(buffer)!); + return MyCentralManagerArgs.decode(readValue(buffer)!); case 129: return MyGattCharacteristicArgs.decode(readValue(buffer)!); case 130: @@ -233,19 +323,19 @@ class _MyCentralControllerHostApiCodec extends StandardMessageCodec { } } -class MyCentralControllerHostApi { - /// Constructor for [MyCentralControllerHostApi]. The [binaryMessenger] named argument is +class MyCentralManagerHostApi { + /// Constructor for [MyCentralManagerHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - MyCentralControllerHostApi({BinaryMessenger? binaryMessenger}) + MyCentralManagerHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; - static const MessageCodec codec = _MyCentralControllerHostApiCodec(); + static const MessageCodec codec = _MyCentralManagerHostApiCodec(); - Future setUp() async { + Future setUp() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.setUp', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.setUp', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -266,35 +356,13 @@ class MyCentralControllerHostApi { message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as MyCentralControllerArgs?)!; - } - } - - Future tearDown() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.tearDown', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return; + return (replyList[0] as MyCentralManagerArgs?)!; } } Future startDiscovery() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.startDiscovery', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.startDiscovery', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -316,7 +384,7 @@ class MyCentralControllerHostApi { Future stopDiscovery() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.stopDiscovery', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.stopDiscovery', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -336,12 +404,12 @@ class MyCentralControllerHostApi { } } - Future connect(int arg_myPeripheralKey) async { + Future connect(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.connect', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.connect', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -358,12 +426,12 @@ class MyCentralControllerHostApi { } } - Future disconnect(int arg_myPeripheralKey) async { + Future disconnect(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.disconnect', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.disconnect', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -380,12 +448,12 @@ class MyCentralControllerHostApi { } } - Future getMaximumWriteLength(int arg_myPeripheralKey) async { + Future getMaximumWriteLength(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getMaximumWriteLength', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.getMaximumWriteLength', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -407,12 +475,12 @@ class MyCentralControllerHostApi { } } - Future discoverGATT(int arg_myPeripheralKey) async { + Future readRSSI(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.discoverGATT', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.readRSSI', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -424,17 +492,22 @@ class MyCentralControllerHostApi { message: replyList[1] as String?, details: replyList[2], ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); } else { - return; + return (replyList[0] as int?)!; } } - Future> getServices(int arg_myPeripheralKey) async { + Future> discoverGATT(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getServices', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.discoverGATT', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -456,66 +529,12 @@ class MyCentralControllerHostApi { } } - Future> getCharacteristics(int arg_myServiceKey) async { + Future readCharacteristic(int arg_peripheralHashCodeArgs, int arg_characteristicHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getCharacteristics', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.readCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myServiceKey]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as List?)!.cast(); - } - } - - Future> getDescriptors(int arg_myCharacteristicKey) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getDescriptors', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_myCharacteristicKey]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as List?)!.cast(); - } - } - - Future readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readCharacteristic', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_characteristicHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -537,12 +556,12 @@ class MyCentralControllerHostApi { } } - Future writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { + Future writeCharacteristic(int arg_peripheralHashCodeArgs, int arg_characteristicHashCodeArgs, Uint8List arg_valueArgs, int arg_typeNumberArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeCharacteristic', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.writeCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_characteristicHashCodeArgs, arg_valueArgs, arg_typeNumberArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -559,12 +578,12 @@ class MyCentralControllerHostApi { } } - Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async { + Future notifyCharacteristic(int arg_peripheralHashCodeArgs, int arg_characteristicHashCodeArgs, bool arg_stateArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.notifyCharacteristic', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.notifyCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_characteristicHashCodeArgs, arg_stateArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -581,12 +600,12 @@ class MyCentralControllerHostApi { } } - Future readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async { + Future readDescriptor(int arg_peripheralHashCodeArgs, int arg_descriptorHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readDescriptor', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.readDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_descriptorHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -608,12 +627,12 @@ class MyCentralControllerHostApi { } } - Future writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async { + Future writeDescriptor(int arg_peripheralHashCodeArgs, int arg_descriptorHashCodeArgs, Uint8List arg_valueArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeDescriptor', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.writeDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_descriptorHashCodeArgs, arg_valueArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -631,16 +650,25 @@ class MyCentralControllerHostApi { } } -class _MyCentralControllerFlutterApiCodec extends StandardMessageCodec { - const _MyCentralControllerFlutterApiCodec(); +class _MyCentralManagerFlutterApiCodec extends StandardMessageCodec { + const _MyCentralManagerFlutterApiCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is MyAdvertisementArgs) { + if (value is MyAdvertiseDataArgs) { buffer.putUint8(128); writeValue(buffer, value.encode()); - } else if (value is MyPeripheralArgs) { + } else if (value is MyGattCharacteristicArgs) { buffer.putUint8(129); writeValue(buffer, value.encode()); + } else if (value is MyGattDescriptorArgs) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is MyManufacturerSpecificDataArgs) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is MyPeripheralArgs) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -650,8 +678,14 @@ class _MyCentralControllerFlutterApiCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 128: - return MyAdvertisementArgs.decode(readValue(buffer)!); + return MyAdvertiseDataArgs.decode(readValue(buffer)!); case 129: + return MyGattCharacteristicArgs.decode(readValue(buffer)!); + case 130: + return MyGattDescriptorArgs.decode(readValue(buffer)!); + case 131: + return MyManufacturerSpecificDataArgs.decode(readValue(buffer)!); + case 132: return MyPeripheralArgs.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -659,102 +693,542 @@ class _MyCentralControllerFlutterApiCodec extends StandardMessageCodec { } } -abstract class MyCentralControllerFlutterApi { - static const MessageCodec codec = _MyCentralControllerFlutterApiCodec(); +abstract class MyCentralManagerFlutterApi { + static const MessageCodec codec = _MyCentralManagerFlutterApiCodec(); - void onStateChanged(int myStateNumber); + void onStateChanged(int stateNumberArgs); - void onDiscovered(MyPeripheralArgs myPeripheralArgs, int rssi, MyAdvertisementArgs myAdvertisementArgs); + void onDiscovered(MyPeripheralArgs peripheralArgs, int rssiArgs, MyAdvertiseDataArgs advertiseDataArgs); - void onPeripheralStateChanged(int myPeripheralKey, bool state); + void onPeripheralStateChanged(MyPeripheralArgs peripheralArgs, bool stateArgs); - void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value); + void onCharacteristicValueChanged(MyGattCharacteristicArgs characteristicArgs, Uint8List valueArgs); - static void setup(MyCentralControllerFlutterApi? api, {BinaryMessenger? binaryMessenger}) { + static void setup(MyCentralManagerFlutterApi? api, {BinaryMessenger? binaryMessenger}) { { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onStateChanged', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onStateChanged was null.'); final List args = (message as List?)!; - final int? arg_myStateNumber = (args[0] as int?); - assert(arg_myStateNumber != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged was null, expected non-null int.'); - api.onStateChanged(arg_myStateNumber!); + final int? arg_stateNumberArgs = (args[0] as int?); + assert(arg_stateNumberArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onStateChanged was null, expected non-null int.'); + api.onStateChanged(arg_stateNumberArgs!); return; }); } } { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered was null.'); final List args = (message as List?)!; - final MyPeripheralArgs? arg_myPeripheralArgs = (args[0] as MyPeripheralArgs?); - assert(arg_myPeripheralArgs != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null MyPeripheralArgs.'); - final int? arg_rssi = (args[1] as int?); - assert(arg_rssi != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null int.'); - final MyAdvertisementArgs? arg_myAdvertisementArgs = (args[2] as MyAdvertisementArgs?); - assert(arg_myAdvertisementArgs != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null MyAdvertisementArgs.'); - api.onDiscovered(arg_myPeripheralArgs!, arg_rssi!, arg_myAdvertisementArgs!); + final MyPeripheralArgs? arg_peripheralArgs = (args[0] as MyPeripheralArgs?); + assert(arg_peripheralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered was null, expected non-null MyPeripheralArgs.'); + final int? arg_rssiArgs = (args[1] as int?); + assert(arg_rssiArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered was null, expected non-null int.'); + final MyAdvertiseDataArgs? arg_advertiseDataArgs = (args[2] as MyAdvertiseDataArgs?); + assert(arg_advertiseDataArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered was null, expected non-null MyAdvertiseDataArgs.'); + api.onDiscovered(arg_peripheralArgs!, arg_rssiArgs!, arg_advertiseDataArgs!); return; }); } } { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onPeripheralStateChanged', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onPeripheralStateChanged was null.'); final List args = (message as List?)!; - final int? arg_myPeripheralKey = (args[0] as int?); - assert(arg_myPeripheralKey != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged was null, expected non-null int.'); - final bool? arg_state = (args[1] as bool?); - assert(arg_state != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged was null, expected non-null bool.'); - api.onPeripheralStateChanged(arg_myPeripheralKey!, arg_state!); + final MyPeripheralArgs? arg_peripheralArgs = (args[0] as MyPeripheralArgs?); + assert(arg_peripheralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onPeripheralStateChanged was null, expected non-null MyPeripheralArgs.'); + final bool? arg_stateArgs = (args[1] as bool?); + assert(arg_stateArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onPeripheralStateChanged was null, expected non-null bool.'); + api.onPeripheralStateChanged(arg_peripheralArgs!, arg_stateArgs!); return; }); } } { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onCharacteristicValueChanged', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onCharacteristicValueChanged was null.'); final List args = (message as List?)!; - final int? arg_myCharacteristicKey = (args[0] as int?); - assert(arg_myCharacteristicKey != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null, expected non-null int.'); - final Uint8List? arg_value = (args[1] as Uint8List?); - assert(arg_value != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null, expected non-null Uint8List.'); - api.onCharacteristicValueChanged(arg_myCharacteristicKey!, arg_value!); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[0] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onCharacteristicValueChanged was null, expected non-null MyGattCharacteristicArgs.'); + final Uint8List? arg_valueArgs = (args[1] as Uint8List?); + assert(arg_valueArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onCharacteristicValueChanged was null, expected non-null Uint8List.'); + api.onCharacteristicValueChanged(arg_characteristicArgs!, arg_valueArgs!); + return; + }); + } + } + } +} + +class _MyPeripheralManagerHostApiCodec extends StandardMessageCodec { + const _MyPeripheralManagerHostApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is MyAdvertiseDataArgs) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is MyGattCharacteristicArgs) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is MyGattDescriptorArgs) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is MyGattServiceArgs) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is MyManufacturerSpecificDataArgs) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else if (value is MyPeripheralManagerArgs) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return MyAdvertiseDataArgs.decode(readValue(buffer)!); + case 129: + return MyGattCharacteristicArgs.decode(readValue(buffer)!); + case 130: + return MyGattDescriptorArgs.decode(readValue(buffer)!); + case 131: + return MyGattServiceArgs.decode(readValue(buffer)!); + case 132: + return MyManufacturerSpecificDataArgs.decode(readValue(buffer)!); + case 133: + return MyPeripheralManagerArgs.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class MyPeripheralManagerHostApi { + /// Constructor for [MyPeripheralManagerHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MyPeripheralManagerHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _MyPeripheralManagerHostApiCodec(); + + Future setUp() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.setUp', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as MyPeripheralManagerArgs?)!; + } + } + + Future addService(MyGattServiceArgs arg_serviceArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.addService', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_serviceArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future removeService(int arg_serviceHashCodeArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.removeService', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_serviceHashCodeArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future clearServices() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.clearServices', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future startAdvertising(MyAdvertiseDataArgs arg_advertiseDataArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.startAdvertising', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_advertiseDataArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future stopAdvertising() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.stopAdvertising', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future getMaximumWriteLength(int arg_centralHashCodeArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.getMaximumWriteLength', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as int?)!; + } + } + + Future sendReadCharacteristicReply(int arg_centralHashCodeArgs, int arg_characteristicHashCodeArgs, int arg_idArgs, int arg_offsetArgs, bool arg_statusArgs, Uint8List arg_valueArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.sendReadCharacteristicReply', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs, arg_characteristicHashCodeArgs, arg_idArgs, arg_offsetArgs, arg_statusArgs, arg_valueArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future sendWriteCharacteristicReply(int arg_centralHashCodeArgs, int arg_characteristicHashCodeArgs, int arg_idArgs, int arg_offsetArgs, bool arg_statusArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.sendWriteCharacteristicReply', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs, arg_characteristicHashCodeArgs, arg_idArgs, arg_offsetArgs, arg_statusArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future notifyCharacteristicValueChanged(int arg_centralHashCodeArgs, int arg_characteristicHashCodeArgs, Uint8List arg_valueArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.notifyCharacteristicValueChanged', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs, arg_characteristicHashCodeArgs, arg_valueArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } +} + +class _MyPeripheralManagerFlutterApiCodec extends StandardMessageCodec { + const _MyPeripheralManagerFlutterApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is MyCentralArgs) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is MyGattCharacteristicArgs) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is MyGattDescriptorArgs) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return MyCentralArgs.decode(readValue(buffer)!); + case 129: + return MyGattCharacteristicArgs.decode(readValue(buffer)!); + case 130: + return MyGattDescriptorArgs.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class MyPeripheralManagerFlutterApi { + static const MessageCodec codec = _MyPeripheralManagerFlutterApiCodec(); + + void onStateChanged(int stateNumberArgs); + + void onReadCharacteristicCommandReceived(MyCentralArgs centralArgs, MyGattCharacteristicArgs characteristicArgs, int idArgs, int offsetArgs); + + void onWriteCharacteristicCommandReceived(MyCentralArgs centralArgs, MyGattCharacteristicArgs characteristicArgs, int idArgs, int offsetArgs, Uint8List valueArgs); + + void onNotifyCharacteristicCommandReceived(MyCentralArgs centralArgs, MyGattCharacteristicArgs characteristicArgs, bool stateArgs); + + static void setup(MyPeripheralManagerFlutterApi? api, {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onStateChanged', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onStateChanged was null.'); + final List args = (message as List?)!; + final int? arg_stateNumberArgs = (args[0] as int?); + assert(arg_stateNumberArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onStateChanged was null, expected non-null int.'); + api.onStateChanged(arg_stateNumberArgs!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null.'); + final List args = (message as List?)!; + final MyCentralArgs? arg_centralArgs = (args[0] as MyCentralArgs?); + assert(arg_centralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null MyCentralArgs.'); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[1] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null MyGattCharacteristicArgs.'); + final int? arg_idArgs = (args[2] as int?); + assert(arg_idArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null int.'); + final int? arg_offsetArgs = (args[3] as int?); + assert(arg_offsetArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null int.'); + api.onReadCharacteristicCommandReceived(arg_centralArgs!, arg_characteristicArgs!, arg_idArgs!, arg_offsetArgs!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null.'); + final List args = (message as List?)!; + final MyCentralArgs? arg_centralArgs = (args[0] as MyCentralArgs?); + assert(arg_centralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null MyCentralArgs.'); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[1] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null MyGattCharacteristicArgs.'); + final int? arg_idArgs = (args[2] as int?); + assert(arg_idArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null int.'); + final int? arg_offsetArgs = (args[3] as int?); + assert(arg_offsetArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null int.'); + final Uint8List? arg_valueArgs = (args[4] as Uint8List?); + assert(arg_valueArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null Uint8List.'); + api.onWriteCharacteristicCommandReceived(arg_centralArgs!, arg_characteristicArgs!, arg_idArgs!, arg_offsetArgs!, arg_valueArgs!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null.'); + final List args = (message as List?)!; + final MyCentralArgs? arg_centralArgs = (args[0] as MyCentralArgs?); + assert(arg_centralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null, expected non-null MyCentralArgs.'); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[1] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null, expected non-null MyGattCharacteristicArgs.'); + final bool? arg_stateArgs = (args[2] as bool?); + assert(arg_stateArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null, expected non-null bool.'); + api.onNotifyCharacteristicCommandReceived(arg_centralArgs!, arg_characteristicArgs!, arg_stateArgs!); return; }); } diff --git a/bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy.dart b/bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy.dart new file mode 100644 index 0000000..752d659 --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy.dart @@ -0,0 +1,15 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_central_manager.dart'; +import 'my_peripheral_manager.dart'; + +class MyBluetoothLowEnergy extends BluetoothLowEnergy { + @override + final MyCentralManager centralManager; + @override + final MyPeripheralManager peripheralManager; + + MyBluetoothLowEnergy() + : centralManager = MyCentralManager(), + peripheralManager = MyPeripheralManager(); +} diff --git a/bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy_manager.dart b/bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy_manager.dart new file mode 100644 index 0000000..8082f8b --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_bluetooth_low_energy_manager.dart @@ -0,0 +1,39 @@ +import 'dart:async'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; +import 'package:flutter/foundation.dart'; + +abstract class MyBluetoothLowEnergyManager extends BluetoothLowEnergyManager { + MyBluetoothLowEnergyManager() + : _state = BluetoothLowEnergyState.unknown, + _stateChangedController = StreamController.broadcast(); + + final StreamController + _stateChangedController; + + BluetoothLowEnergyState _state; + @override + BluetoothLowEnergyState get state => _state; + @protected + set state(BluetoothLowEnergyState value) { + if (_state == value) { + return; + } + _state = value; + final eventArgs = BluetoothLowEnergyStateChangedEventArgs(state); + _stateChangedController.add(eventArgs); + } + + @override + Stream get stateChanged => + _stateChangedController.stream; + + @protected + Future throwWithoutState(BluetoothLowEnergyState state) async { + if (this.state != state) { + throw BluetoothLowEnergyError( + '$state is expected, but current state is ${this.state}.', + ); + } + } +} diff --git a/bluetooth_low_energy_android/lib/src/my_central_controller.dart b/bluetooth_low_energy_android/lib/src/my_central_controller.dart deleted file mode 100644 index 0ce6201..0000000 --- a/bluetooth_low_energy_android/lib/src/my_central_controller.dart +++ /dev/null @@ -1,366 +0,0 @@ -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_gatt_characteristic.dart'; -import 'my_gatt_descriptor.dart'; -import 'my_gatt_service.dart'; -import 'my_peripheral.dart'; - -class MyCentralController extends CentralController - implements MyCentralControllerFlutterApi { - MyCentralController() - : _myApi = MyCentralControllerHostApi(), - _stateChangedController = StreamController.broadcast(), - _discoveredController = StreamController.broadcast(), - _peripheralStateChangedController = StreamController.broadcast(), - _characteristicValueChangedController = StreamController.broadcast(), - _myPeripherals = {}, - _myServices = {}, - _myCharacteristics = {}, - _myDescriptors = {}, - _state = CentralState.unknown; - - final MyCentralControllerHostApi _myApi; - final StreamController _stateChangedController; - final StreamController _discoveredController; - final StreamController - _peripheralStateChangedController; - final StreamController - _characteristicValueChangedController; - final Map _myPeripherals; - final Map _myServices; - final Map _myCharacteristics; - final Map _myDescriptors; - - CentralState _state; - @override - CentralState get state => _state; - - @override - Stream get stateChanged => - _stateChangedController.stream; - @override - Stream get discovered => - _discoveredController.stream; - @override - Stream get peripheralStateChanged => - _peripheralStateChangedController.stream; - @override - Stream - get characteristicValueChanged => - _characteristicValueChangedController.stream; - - Future _throwWithState(CentralState state) async { - if (this.state == state) { - throw BluetoothLowEnergyError('$state is unexpected.'); - } - } - - Future _throwWithoutState(CentralState state) async { - if (this.state != state) { - throw BluetoothLowEnergyError( - '$state is expected, but current state is ${this.state}.', - ); - } - } - - @override - Future setUp() async { - await _throwWithoutState(CentralState.unknown); - final args = await _myApi.setUp(); - final myStateArgs = MyCentralStateArgs.values[args.myStateNumber]; - _state = myStateArgs.toState(); - MyCentralControllerFlutterApi.setup(this); - } - - @override - Future tearDown() async { - await _throwWithState(CentralState.unknown); - await _myApi.tearDown(); - MyCentralControllerFlutterApi.setup(null); - _myPeripherals.clear(); - _myServices.clear(); - _myCharacteristics.clear(); - _myDescriptors.clear(); - _state = CentralState.unknown; - } - - @override - Future startDiscovery() async { - await _throwWithoutState(CentralState.poweredOn); - await _myApi.startDiscovery(); - } - - @override - Future stopDiscovery() async { - await _throwWithoutState(CentralState.poweredOn); - await _myApi.stopDiscovery(); - } - - @override - Future connect(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - await _myApi.connect(myPeripheral.hashCode); - } - - @override - Future disconnect(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - await _myApi.disconnect(myPeripheral.hashCode); - } - - @override - Future getMaximumWriteLength( - Peripheral peripheral, { - required GattCharacteristicWriteType type, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - final maximumWriteLength = await _myApi.getMaximumWriteLength( - myPeripheral.hashCode, - ); - return maximumWriteLength; - } - - @override - Future discoverGATT(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - await _myApi.discoverGATT(myPeripheral.hashCode); - } - - @override - Future> getServices(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); - return myServiceArgses.cast().map( - (myServiceArgs) { - final myService = MyGattService.fromMyArgs( - myPeripheral, - myServiceArgs, - ); - _myServices[myService.hashCode] = myService; - return myService; - }, - ).toList(); - } - - @override - Future> getCharacteristics( - GattService service, - ) async { - await _throwWithoutState(CentralState.poweredOn); - final myService = service as MyGattService; - final myCharactersiticArgses = await _myApi.getCharacteristics( - myService.hashCode, - ); - return myCharactersiticArgses.cast().map( - (myCharacteristicArgs) { - final myCharacteristic = MyGattCharacteristic.fromMyArgs( - myService, - myCharacteristicArgs, - ); - _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic; - return myCharacteristic; - }, - ).toList(); - } - - @override - Future> getDescriptors( - GattCharacteristic characteristic, - ) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myDescriptorArgses = await _myApi.getDescriptors( - myCharacteristic.hashCode, - ); - return myDescriptorArgses.cast().map( - (myDescriptorArgs) { - final myDescriptor = MyGattDescriptor.fromMyArgs( - myCharacteristic, - myDescriptorArgs, - ); - _myDescriptors[myDescriptor.hashCode] = myDescriptor; - return myDescriptor; - }, - ).toList(); - } - - @override - Future readCharacteristic( - GattCharacteristic characteristic) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - final value = await _myApi.readCharacteristic( - myPeripheral.hashCode, - myService.hashCode, - myCharacteristic.hashCode, - ); - return value; - } - - @override - Future writeCharacteristic( - GattCharacteristic characteristic, { - required Uint8List value, - required GattCharacteristicWriteType type, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - final myTypeArgs = type.toMyArgs(); - final myTypeNumber = myTypeArgs.index; - await _myApi.writeCharacteristic( - myPeripheral.hashCode, - myService.hashCode, - myCharacteristic.hashCode, - value, - myTypeNumber, - ); - } - - @override - Future notifyCharacteristic( - GattCharacteristic characteristic, { - required bool state, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - await _myApi.notifyCharacteristic( - myPeripheral.hashCode, - myService.hashCode, - myCharacteristic.hashCode, - state, - ); - } - - @override - Future readDescriptor(GattDescriptor descriptor) async { - await _throwWithoutState(CentralState.poweredOn); - final myDescriptor = descriptor as MyGattDescriptor; - final myCharacteristic = myDescriptor.myCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - final value = await _myApi.readDescriptor( - myPeripheral.hashCode, - myCharacteristic.hashCode, - myDescriptor.hashCode, - ); - return value; - } - - @override - Future writeDescriptor( - GattDescriptor descriptor, { - required Uint8List value, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myDescriptor = descriptor as MyGattDescriptor; - final myCharacteristic = myDescriptor.myCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - await _myApi.writeDescriptor( - myPeripheral.hashCode, - myCharacteristic.hashCode, - myDescriptor.hashCode, - value, - ); - } - - @override - void onStateChanged(int myStateNumber) { - final myStateArgs = MyCentralStateArgs.values[myStateNumber]; - final state = myStateArgs.toState(); - if (_state == state) { - return; - } - _state = state; - final eventArgs = CentralStateChangedEventArgs(state); - _stateChangedController.add(eventArgs); - } - - @override - void onDiscovered( - MyPeripheralArgs myPeripheralArgs, - int rssi, - MyAdvertisementArgs myAdvertisementArgs, - ) { - final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs); - _myPeripherals[myPeripheral.hashCode] = myPeripheral; - final advertisement = myAdvertisementArgs.toAdvertisement(); - final eventArgs = CentralDiscoveredEventArgs( - myPeripheral, - rssi, - advertisement, - ); - _discoveredController.add(eventArgs); - } - - @override - void onPeripheralStateChanged(int myPeripheralKey, bool state) { - final myPeripheral = _myPeripherals[myPeripheralKey]; - if (myPeripheral == null) { - return; - } - final eventArgs = PeripheralStateChangedEventArgs(myPeripheral, state); - _peripheralStateChangedController.add(eventArgs); - } - - @override - void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value) { - final myCharacteristic = - _myCharacteristics[myCharacteristicKey] as MyGattCharacteristic; - final eventArgs = GattCharacteristicValueChangedEventArgs( - myCharacteristic, - value, - ); - _characteristicValueChangedController.add(eventArgs); - } -} - -extension on MyAdvertisementArgs { - Advertisement toAdvertisement() { - final serviceUUIDs = this - .serviceUUIDs - .cast() - .map((uuid) => UUID.fromString(uuid)) - .toList(); - final serviceData = this.serviceData.cast().map( - (uuid, data) { - final key = UUID.fromString(uuid); - final value = data; - return MapEntry(key, value); - }, - ); - return Advertisement( - name: name, - manufacturerSpecificData: manufacturerSpecificData.cast(), - serviceUUIDs: serviceUUIDs, - serviceData: serviceData, - ); - } -} - -extension on MyCentralStateArgs { - CentralState toState() { - return CentralState.values[index]; - } -} - -extension on GattCharacteristicWriteType { - MyGattCharacteristicWriteTypeArgs toMyArgs() { - return MyGattCharacteristicWriteTypeArgs.values[index]; - } -} diff --git a/bluetooth_low_energy_android/lib/src/my_central_manager.dart b/bluetooth_low_energy_android/lib/src/my_central_manager.dart new file mode 100644 index 0000000..0f9f4a7 --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_central_manager.dart @@ -0,0 +1,267 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_api.dart'; +import 'my_bluetooth_low_energy_manager.dart'; +import 'my_gatt_characteristic2.dart'; +import 'my_gatt_descriptor2.dart'; + +class MyCentralManager extends MyBluetoothLowEnergyManager + implements CentralManager, MyCentralManagerFlutterApi { + final MyCentralManagerHostApi _api; + final StreamController _discoveredController; + final StreamController + _peripheralStateChangedController; + final StreamController + _characteristicValueChangedController; + + MyCentralManager() + : _api = MyCentralManagerHostApi(), + _discoveredController = StreamController.broadcast(), + _peripheralStateChangedController = StreamController.broadcast(), + _characteristicValueChangedController = StreamController.broadcast(); + + @override + Stream get discovered => _discoveredController.stream; + @override + Stream get peripheralStateChanged => + _peripheralStateChangedController.stream; + @override + Stream + get characteristicValueChanged => + _characteristicValueChangedController.stream; + + @override + Future setUp() async { + final args = await _api.setUp(); + final stateArgs = + MyBluetoothLowEnergyStateArgs.values[args.stateNumberArgs]; + state = stateArgs.toState(); + MyCentralManagerFlutterApi.setup(this); + } + + @override + Future startDiscovery() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.startDiscovery(); + } + + @override + Future stopDiscovery() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.stopDiscovery(); + } + + @override + Future connect(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + await _api.connect(peripheralHashCodeArgs); + } + + @override + Future disconnect(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + await _api.disconnect(peripheralHashCodeArgs); + } + + @override + Future getMaximumWriteLength( + Peripheral peripheral, { + required GattCharacteristicWriteType type, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + final maximumWriteLength = + await _api.getMaximumWriteLength(peripheralHashCodeArgs); + return maximumWriteLength; + } + + @override + Future readRSSI(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + final rssi = await _api.readRSSI(peripheralHashCodeArgs); + return rssi; + } + + @override + Future> discoverGATT(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (peripheral is! MyPeripheral) { + throw TypeError(); + } + final peripheralHashCodeArgs = peripheral.hashCode; + final servicesArgs = await _api.discoverGATT(peripheralHashCodeArgs); + final services = servicesArgs + .cast() + .map((args) => args.toService2()) + .toList(); + for (var service in services) { + for (var charactersitic in service.characteristics) { + for (var descriptor in charactersitic.descriptors) { + descriptor.characteristic = charactersitic; + } + charactersitic.service = service; + } + service.peripheral = peripheral; + } + return services; + } + + @override + Future readCharacteristic( + GattCharacteristic characteristic, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (characteristic is! MyGattCharacteristic2) { + throw TypeError(); + } + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final characteristcHashCodeArgs = characteristic.hashCode; + final value = await _api.readCharacteristic( + peripheralHashCodeArgs, + characteristcHashCodeArgs, + ); + return value; + } + + @override + Future writeCharacteristic( + GattCharacteristic characteristic, { + required Uint8List value, + required GattCharacteristicWriteType type, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (characteristic is! MyGattCharacteristic2) { + throw TypeError(); + } + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final characteristcHashCodeArgs = characteristic.hashCode; + final valueArgs = value; + final typeArgs = type.toArgs(); + final typeNumberArgs = typeArgs.index; + await _api.writeCharacteristic( + peripheralHashCodeArgs, + characteristcHashCodeArgs, + valueArgs, + typeNumberArgs, + ); + } + + @override + Future notifyCharacteristic( + GattCharacteristic characteristic, { + required bool state, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (characteristic is! MyGattCharacteristic2) { + throw TypeError(); + } + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final characteristcHashCodeArgs = characteristic.hashCode; + final stateArgs = state; + await _api.notifyCharacteristic( + peripheralHashCodeArgs, + characteristcHashCodeArgs, + stateArgs, + ); + } + + @override + Future readDescriptor(GattDescriptor descriptor) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (descriptor is! MyGattDescriptor2) { + throw TypeError(); + } + final characteristic = descriptor.characteristic; + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final descriptorHashCodeArgs = descriptor.hashCode; + final value = await _api.readDescriptor( + peripheralHashCodeArgs, + descriptorHashCodeArgs, + ); + return value; + } + + @override + Future writeDescriptor( + GattDescriptor descriptor, { + required Uint8List value, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (descriptor is! MyGattDescriptor2) { + throw TypeError(); + } + final characteristic = descriptor.characteristic; + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final descriptorHashCodeArgs = descriptor.hashCode; + final valueArgs = value; + await _api.writeDescriptor( + peripheralHashCodeArgs, + descriptorHashCodeArgs, + valueArgs, + ); + } + + @override + void onStateChanged(int stateNumberArgs) { + final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs]; + state = stateArgs.toState(); + } + + @override + void onDiscovered( + MyPeripheralArgs peripheralArgs, + int rssiArgs, + MyAdvertiseDataArgs advertiseDataArgs, + ) { + final peripheral = peripheralArgs.toPeripheral(); + final rssi = rssiArgs; + final advertiseData = advertiseDataArgs.toAdvertiseData(); + final eventArgs = DiscoveredEventArgs( + peripheral, + rssi, + advertiseData, + ); + _discoveredController.add(eventArgs); + } + + @override + void onPeripheralStateChanged( + MyPeripheralArgs peripheralArgs, + bool stateArgs, + ) { + final peripheral = peripheralArgs.toPeripheral(); + final state = stateArgs; + final eventArgs = PeripheralStateChangedEventArgs(peripheral, state); + _peripheralStateChangedController.add(eventArgs); + } + + @override + void onCharacteristicValueChanged( + MyGattCharacteristicArgs characteristicArgs, + Uint8List valueArgs, + ) { + final characteristic = characteristicArgs.toCharacteristic2(); + final value = valueArgs; + final eventArgs = GattCharacteristicValueChangedEventArgs( + characteristic, + value, + ); + _characteristicValueChangedController.add(eventArgs); + } +} diff --git a/bluetooth_low_energy_android/lib/src/my_gatt_characteristic.dart b/bluetooth_low_energy_android/lib/src/my_gatt_characteristic.dart deleted file mode 100644 index 811fb23..0000000 --- a/bluetooth_low_energy_android/lib/src/my_gatt_characteristic.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_gatt_service.dart'; -import 'my_object.dart'; - -class MyGattCharacteristic extends MyObject implements GattCharacteristic { - final MyGattService myService; - @override - final UUID uuid; - @override - final List properties; - - MyGattCharacteristic( - super.hashCode, - this.myService, - this.uuid, - this.properties, - ); - - factory MyGattCharacteristic.fromMyArgs( - MyGattService myService, - MyGattCharacteristicArgs myArgs, - ) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - final properties = myArgs.myPropertyNumbers.cast().map( - (myPropertyNumber) { - final myPropertyArgs = - MyGattCharacteristicPropertyArgs.values[myPropertyNumber]; - return myPropertyArgs.toProperty(); - }, - ).toList(); - return MyGattCharacteristic(hashCode, myService, uuid, properties); - } -} - -extension on MyGattCharacteristicPropertyArgs { - GattCharacteristicProperty toProperty() { - return GattCharacteristicProperty.values[index]; - } -} diff --git a/bluetooth_low_energy_android/lib/src/my_gatt_characteristic2.dart b/bluetooth_low_energy_android/lib/src/my_gatt_characteristic2.dart new file mode 100644 index 0000000..b8c8a15 --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_gatt_characteristic2.dart @@ -0,0 +1,19 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_gatt_descriptor2.dart'; +import 'my_gatt_service2.dart'; + +class MyGattCharacteristic2 extends MyGattCharacteristic { + late final MyGattService2 service; + + MyGattCharacteristic2({ + super.hashCode, + required super.uuid, + required super.properties, + required List descriptors, + }) : super(descriptors: descriptors); + + @override + List get descriptors => + super.descriptors.cast(); +} diff --git a/bluetooth_low_energy_android/lib/src/my_gatt_descriptor.dart b/bluetooth_low_energy_android/lib/src/my_gatt_descriptor.dart deleted file mode 100644 index 6798f4a..0000000 --- a/bluetooth_low_energy_android/lib/src/my_gatt_descriptor.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_gatt_characteristic.dart'; -import 'my_object.dart'; - -class MyGattDescriptor extends MyObject implements GattDescriptor { - final MyGattCharacteristic myCharacteristic; - @override - final UUID uuid; - - MyGattDescriptor(super.hashCode, this.myCharacteristic, this.uuid); - - factory MyGattDescriptor.fromMyArgs( - MyGattCharacteristic myCharacteristic, - MyGattDescriptorArgs myArgs, - ) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - return MyGattDescriptor(hashCode, myCharacteristic, uuid); - } -} diff --git a/bluetooth_low_energy_android/lib/src/my_gatt_descriptor2.dart b/bluetooth_low_energy_android/lib/src/my_gatt_descriptor2.dart new file mode 100644 index 0000000..5bc7dc4 --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_gatt_descriptor2.dart @@ -0,0 +1,12 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_gatt_characteristic2.dart'; + +class MyGattDescriptor2 extends MyGattDescriptor { + late final MyGattCharacteristic2 characteristic; + + MyGattDescriptor2({ + super.hashCode, + required super.uuid, + }); +} diff --git a/bluetooth_low_energy_android/lib/src/my_gatt_service.dart b/bluetooth_low_energy_android/lib/src/my_gatt_service.dart deleted file mode 100644 index 37babdb..0000000 --- a/bluetooth_low_energy_android/lib/src/my_gatt_service.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_object.dart'; -import 'my_peripheral.dart'; - -class MyGattService extends MyObject implements GattService { - final MyPeripheral myPeripheral; - @override - final UUID uuid; - - MyGattService(super.hashCode, this.myPeripheral, this.uuid); - - factory MyGattService.fromMyArgs( - MyPeripheral myPeripheral, - MyGattServiceArgs myArgs, - ) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - return MyGattService(hashCode, myPeripheral, uuid); - } -} diff --git a/bluetooth_low_energy_android/lib/src/my_gatt_service2.dart b/bluetooth_low_energy_android/lib/src/my_gatt_service2.dart new file mode 100644 index 0000000..ac74a6d --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_gatt_service2.dart @@ -0,0 +1,17 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_gatt_characteristic2.dart'; + +class MyGattService2 extends MyGattService { + late final MyPeripheral peripheral; + + MyGattService2({ + super.hashCode, + required super.uuid, + required List characteristics, + }) : super(characteristics: characteristics); + + @override + List get characteristics => + super.characteristics.cast(); +} diff --git a/bluetooth_low_energy_android/lib/src/my_peripheral.dart b/bluetooth_low_energy_android/lib/src/my_peripheral.dart deleted file mode 100644 index 7be1bd3..0000000 --- a/bluetooth_low_energy_android/lib/src/my_peripheral.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_object.dart'; - -class MyPeripheral extends MyObject implements Peripheral { - @override - final UUID uuid; - - MyPeripheral(super.hashCode, this.uuid); - - factory MyPeripheral.fromMyArgs(MyPeripheralArgs myArgs) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - return MyPeripheral(hashCode, uuid); - } -} diff --git a/bluetooth_low_energy_android/lib/src/my_peripheral_manager.dart b/bluetooth_low_energy_android/lib/src/my_peripheral_manager.dart new file mode 100644 index 0000000..628ec37 --- /dev/null +++ b/bluetooth_low_energy_android/lib/src/my_peripheral_manager.dart @@ -0,0 +1,228 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_api.dart'; +import 'my_bluetooth_low_energy_manager.dart'; + +class MyPeripheralManager extends MyBluetoothLowEnergyManager + implements PeripheralManager, MyPeripheralManagerFlutterApi { + final MyPeripheralManagerHostApi _api; + final StreamController + _readCharacteristicCommandReceivedController; + final StreamController + _writeCharacteristicCommandReceivedController; + final StreamController + _notifyCharacteristicCommandReceivedController; + + MyPeripheralManager() + : _api = MyPeripheralManagerHostApi(), + _readCharacteristicCommandReceivedController = + StreamController.broadcast(), + _writeCharacteristicCommandReceivedController = + StreamController.broadcast(), + _notifyCharacteristicCommandReceivedController = + StreamController.broadcast(); + + @override + Stream + get readCharacteristicCommandReceived => + _readCharacteristicCommandReceivedController.stream; + + @override + Stream + get writeCharacteristicCommandReceived => + _writeCharacteristicCommandReceivedController.stream; + + @override + Stream + get notifyCharacteristicCommandReceived => + _notifyCharacteristicCommandReceivedController.stream; + + @override + Future setUp() async { + final args = await _api.setUp(); + final stateArgs = + MyBluetoothLowEnergyStateArgs.values[args.stateNumberArgs]; + state = stateArgs.toState(); + MyPeripheralManagerFlutterApi.setup(this); + } + + @override + Future addService(GattService service) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (service is! MyGattService) { + throw TypeError(); + } + final serviceArgs = service.toArgs(); + await _api.addService(serviceArgs); + } + + @override + Future removeService(GattService service) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final serviceHashCodeArgs = service.hashCode; + await _api.removeService(serviceHashCodeArgs); + } + + @override + Future clearServices() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.clearServices(); + } + + @override + Future startAdvertising(AdvertiseData advertiseData) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final advertiseDataArgs = advertiseData.toArgs(); + await _api.startAdvertising(advertiseDataArgs); + } + + @override + Future stopAdvertising() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.stopAdvertising(); + } + + @override + Future getMaximumWriteLength(Central central) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final maximumWriteLength = + await _api.getMaximumWriteLength(centralHashCodeArgs); + return maximumWriteLength; + } + + @override + Future sendReadCharacteristicReply( + Central central, + GattCharacteristic characteristic, + int id, + int offset, + bool status, + Uint8List value, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final idArgs = id; + final offsetArgs = offset; + final statusArgs = status; + final valueArgs = value; + await _api.sendReadCharacteristicReply( + centralHashCodeArgs, + characteristicHashCodeArgs, + idArgs, + offsetArgs, + statusArgs, + valueArgs, + ); + } + + @override + Future sendWriteCharacteristicReply( + Central central, + GattCharacteristic characteristic, + int id, + int offset, + bool status, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final idArgs = id; + final offsetArgs = offset; + final statusArgs = status; + await _api.sendWriteCharacteristicReply( + centralHashCodeArgs, + characteristicHashCodeArgs, + idArgs, + offsetArgs, + statusArgs, + ); + } + + @override + Future notifyCharacteristicValueChanged( + Central central, + GattCharacteristic characteristic, + Uint8List value, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final valueArgs = value; + await _api.notifyCharacteristicValueChanged( + centralHashCodeArgs, + characteristicHashCodeArgs, + valueArgs, + ); + } + + @override + void onStateChanged(int stateNumberArgs) { + final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs]; + state = stateArgs.toState(); + } + + @override + void onReadCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + ) { + final central = centralArgs.toCentral(); + final characteristic = characteristicArgs.toCharacteristic2(); + final id = idArgs; + final offset = offsetArgs; + final eventArgs = ReadGattCharacteristicCommandEventArgs( + central, + characteristic, + id, + offset, + ); + _readCharacteristicCommandReceivedController.add(eventArgs); + } + + @override + void onWriteCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + Uint8List valueArgs, + ) { + final central = centralArgs.toCentral(); + final characteristic = characteristicArgs.toCharacteristic2(); + final id = idArgs; + final offset = offsetArgs; + final value = valueArgs; + final eventArgs = WriteGattCharacteristicCommandEventArgs( + central, + characteristic, + id, + offset, + value, + ); + _writeCharacteristicCommandReceivedController.add(eventArgs); + } + + @override + void onNotifyCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + bool stateArgs, + ) { + final central = centralArgs.toCentral(); + final characteristic = characteristicArgs.toCharacteristic2(); + final state = stateArgs; + final eventArgs = NotifyGattCharacteristicCommandEventArgs( + central, + characteristic, + state, + ); + _notifyCharacteristicCommandReceivedController.add(eventArgs); + } +} diff --git a/bluetooth_low_energy_android/my_api.dart b/bluetooth_low_energy_android/my_api.dart index 10dc609..b5d2b05 100644 --- a/bluetooth_low_energy_android/my_api.dart +++ b/bluetooth_low_energy_android/my_api.dart @@ -12,126 +12,215 @@ import 'package:pigeon/pigeon.dart'; ), ) @HostApi() -abstract class MyCentralControllerHostApi { +abstract class MyCentralManagerHostApi { @async - MyCentralControllerArgs setUp(); - void tearDown(); + MyCentralManagerArgs setUp(); @async void startDiscovery(); void stopDiscovery(); @async - void connect(int myPeripheralKey); + void connect(int peripheralHashCodeArgs); @async - void disconnect(int myPeripheralKey); + void disconnect(int peripheralHashCodeArgs); @async - int getMaximumWriteLength(int myPeripheralKey); + int getMaximumWriteLength(int peripheralHashCodeArgs); @async - void discoverGATT(int myPeripheralKey); - List getServices(int myPeripheralKey); - List getCharacteristics(int myServiceKey); - List getDescriptors(int myCharacteristicKey); + int readRSSI(int peripheralHashCodeArgs); + @async + List discoverGATT(int peripheralHashCodeArgs); @async Uint8List readCharacteristic( - int myPeripheralKey, - int myServiceKey, - int myCharacteristicKey, + int peripheralHashCodeArgs, + int characteristicHashCodeArgs, ); @async void writeCharacteristic( - int myPeripheralKey, - int myServiceKey, - int myCharacteristicKey, - Uint8List value, - int myTypeNumber, + int peripheralHashCodeArgs, + int characteristicHashCodeArgs, + Uint8List valueArgs, + int typeNumberArgs, ); @async void notifyCharacteristic( - int myPeripheralKey, - int myServiceKey, - int myCharacteristicKey, - bool state, + int peripheralHashCodeArgs, + int characteristicHashCodeArgs, + bool stateArgs, ); @async Uint8List readDescriptor( - int myPeripheralKey, - int myCharacteristicKey, - int myDescriptorKey, + int peripheralHashCodeArgs, + int descriptorHashCodeArgs, ); @async void writeDescriptor( - int myPeripheralKey, - int myCharacteristicKey, - int myDescriptorKey, - Uint8List value, + int peripheralHashCodeArgs, + int descriptorHashCodeArgs, + Uint8List valueArgs, ); } @FlutterApi() -abstract class MyCentralControllerFlutterApi { - void onStateChanged(int myStateNumber); +abstract class MyCentralManagerFlutterApi { + void onStateChanged(int stateNumberArgs); void onDiscovered( - MyPeripheralArgs myPeripheralArgs, - int rssi, - MyAdvertisementArgs myAdvertisementArgs, + MyPeripheralArgs peripheralArgs, + int rssiArgs, + MyAdvertiseDataArgs advertiseDataArgs, + ); + void onPeripheralStateChanged( + MyPeripheralArgs peripheralArgs, + bool stateArgs, + ); + void onCharacteristicValueChanged( + MyGattCharacteristicArgs characteristicArgs, + Uint8List valueArgs, ); - void onPeripheralStateChanged(int myPeripheralKey, bool state); - void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value); } -class MyCentralControllerArgs { - final int myStateNumber; +@HostApi() +abstract class MyPeripheralManagerHostApi { + @async + MyPeripheralManagerArgs setUp(); + @async + void addService(MyGattServiceArgs serviceArgs); + void removeService(int serviceHashCodeArgs); + void clearServices(); + @async + void startAdvertising(MyAdvertiseDataArgs advertiseDataArgs); + void stopAdvertising(); + int getMaximumWriteLength(int centralHashCodeArgs); + void sendReadCharacteristicReply( + int centralHashCodeArgs, + int characteristicHashCodeArgs, + int idArgs, + int offsetArgs, + bool statusArgs, + Uint8List valueArgs, + ); + void sendWriteCharacteristicReply( + int centralHashCodeArgs, + int characteristicHashCodeArgs, + int idArgs, + int offsetArgs, + bool statusArgs, + ); + @async + void notifyCharacteristicValueChanged( + int centralHashCodeArgs, + int characteristicHashCodeArgs, + Uint8List valueArgs, + ); +} - MyCentralControllerArgs(this.myStateNumber); +@FlutterApi() +abstract class MyPeripheralManagerFlutterApi { + void onStateChanged(int stateNumberArgs); + void onReadCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + ); + void onWriteCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + Uint8List valueArgs, + ); + void onNotifyCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + bool stateArgs, + ); +} + +class MyCentralManagerArgs { + final int stateNumberArgs; + + MyCentralManagerArgs(this.stateNumberArgs); +} + +class MyPeripheralManagerArgs { + final int stateNumberArgs; + + MyPeripheralManagerArgs(this.stateNumberArgs); +} + +class MyCentralArgs { + final int hashCodeArgs; + final String uuidArgs; + + MyCentralArgs(this.hashCodeArgs, this.uuidArgs); } class MyPeripheralArgs { - final int key; - final String uuid; + final int hashCodeArgs; + final String uuidArgs; - MyPeripheralArgs(this.key, this.uuid); + MyPeripheralArgs(this.hashCodeArgs, this.uuidArgs); } -class MyAdvertisementArgs { - final String? name; - final Map manufacturerSpecificData; - final List serviceUUIDs; - final Map serviceData; +class MyAdvertiseDataArgs { + final String? nameArgs; + final List serviceUUIDsArgs; + final Map serviceDataArgs; + final MyManufacturerSpecificDataArgs? manufacturerSpecificDataArgs; - MyAdvertisementArgs( - this.name, - this.manufacturerSpecificData, - this.serviceUUIDs, - this.serviceData, + MyAdvertiseDataArgs( + this.nameArgs, + this.serviceUUIDsArgs, + this.serviceDataArgs, + this.manufacturerSpecificDataArgs, ); } -class MyGattServiceArgs { - final int key; - final String uuid; +class MyManufacturerSpecificDataArgs { + final int idArgs; + final Uint8List dataArgs; - MyGattServiceArgs(this.key, this.uuid); + MyManufacturerSpecificDataArgs(this.idArgs, this.dataArgs); +} + +class MyGattServiceArgs { + final int hashCodeArgs; + final String uuidArgs; + final List characteristicsArgs; + + MyGattServiceArgs( + this.hashCodeArgs, + this.uuidArgs, + this.characteristicsArgs, + ); } class MyGattCharacteristicArgs { - final int key; - final String uuid; - final List myPropertyNumbers; + final int hashCodeArgs; + final String uuidArgs; + final List propertyNumbersArgs; + final List descriptorsArgs; MyGattCharacteristicArgs( - this.key, - this.uuid, - this.myPropertyNumbers, + this.hashCodeArgs, + this.uuidArgs, + this.propertyNumbersArgs, + this.descriptorsArgs, ); } class MyGattDescriptorArgs { - final int key; - final String uuid; + final int hashCodeArgs; + final String uuidArgs; + final Uint8List? valueArgs; - MyGattDescriptorArgs(this.key, this.uuid); + MyGattDescriptorArgs( + this.hashCodeArgs, + this.uuidArgs, + this.valueArgs, + ); } -enum MyCentralStateArgs { +enum MyBluetoothLowEnergyStateArgs { unknown, unsupported, unauthorized, diff --git a/bluetooth_low_energy_android/pubspec.yaml b/bluetooth_low_energy_android/pubspec.yaml index 5549a03..9d83264 100644 --- a/bluetooth_low_energy_android/pubspec.yaml +++ b/bluetooth_low_energy_android/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_android description: Android implementation of the bluetooth_low_energy plugin. -version: 2.2.1 +version: 3.0.0 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: @@ -10,13 +10,13 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.2.0 + bluetooth_low_energy_platform_interface: ^3.0.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - pigeon: ^10.1.6 + pigeon: ^11.0.1 flutter: plugin: diff --git a/bluetooth_low_energy_darwin/CHANGELOG.md b/bluetooth_low_energy_darwin/CHANGELOG.md index e57523f..f81a22f 100644 --- a/bluetooth_low_energy_darwin/CHANGELOG.md +++ b/bluetooth_low_energy_darwin/CHANGELOG.md @@ -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` 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` 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 api. + ## 2.2.0 * Add `CentralController#getMaximumWriteLength` method. diff --git a/bluetooth_low_energy_darwin/darwin/Classes/BluetoothLowEnergyDarwin.swift b/bluetooth_low_energy_darwin/darwin/Classes/BluetoothLowEnergyDarwin.swift index 9ab8c9d..e335bee 100644 --- a/bluetooth_low_energy_darwin/darwin/Classes/BluetoothLowEnergyDarwin.swift +++ b/bluetooth_low_energy_darwin/darwin/Classes/BluetoothLowEnergyDarwin.swift @@ -17,7 +17,9 @@ public class BluetoothLowEnergyDarwin: NSObject, FlutterPlugin { #else #error("Unsupported platform.") #endif - let centralController = MyCentralController(binaryMessenger) - MyCentralControllerHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: centralController) + let centralManager = MyCentralManager(binaryMessenger) + let peripheralManager = MyPeripheralManager(binaryMessenger) + MyCentralManagerHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: centralManager) + MyPeripheralManagerHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: peripheralManager) } } diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyApi.g.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyApi.g.swift index 2376e31..f6f3f79 100644 --- a/bluetooth_low_energy_darwin/darwin/Classes/MyApi.g.swift +++ b/bluetooth_low_energy_darwin/darwin/Classes/MyApi.g.swift @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.1.6), do not edit directly. +// Autogenerated from Pigeon (v11.0.1), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -10,6 +10,10 @@ import FlutterMacOS #error("Unsupported platform.") #endif +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + private func wrapResult(_ result: Any?) -> [Any?] { return [result] } @@ -34,7 +38,7 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } -enum MyCentralStateArgs: Int { +enum MyBluetoothLowEnergyStateArgs: Int { case unknown = 0 case unsupported = 1 case unauthorized = 2 @@ -56,150 +60,227 @@ enum MyGattCharacteristicWriteTypeArgs: Int { } /// Generated class from Pigeon that represents data sent in messages. -struct MyCentralControllerArgs { - var myStateNumber: Int64 +struct MyCentralManagerArgs { + var stateNumberArgs: Int64 - static func fromList(_ list: [Any?]) -> MyCentralControllerArgs? { - let myStateNumber = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + static func fromList(_ list: [Any?]) -> MyCentralManagerArgs? { + let stateNumberArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) - return MyCentralControllerArgs( - myStateNumber: myStateNumber + return MyCentralManagerArgs( + stateNumberArgs: stateNumberArgs ) } func toList() -> [Any?] { return [ - myStateNumber, + stateNumberArgs, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct MyPeripheralManagerArgs { + var stateNumberArgs: Int64 + + static func fromList(_ list: [Any?]) -> MyPeripheralManagerArgs? { + let stateNumberArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + + return MyPeripheralManagerArgs( + stateNumberArgs: stateNumberArgs + ) + } + func toList() -> [Any?] { + return [ + stateNumberArgs, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct MyCentralArgs { + var hashCodeArgs: Int64 + var uuidArgs: String + + static func fromList(_ list: [Any?]) -> MyCentralArgs? { + let hashCodeArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let uuidArgs = list[1] as! String + + return MyCentralArgs( + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs + ) + } + func toList() -> [Any?] { + return [ + hashCodeArgs, + uuidArgs, ] } } /// Generated class from Pigeon that represents data sent in messages. struct MyPeripheralArgs { - var key: Int64 - var uuid: String + var hashCodeArgs: Int64 + var uuidArgs: String static func fromList(_ list: [Any?]) -> MyPeripheralArgs? { - let key = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) - let uuid = list[1] as! String + let hashCodeArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let uuidArgs = list[1] as! String return MyPeripheralArgs( - key: key, - uuid: uuid + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs ) } func toList() -> [Any?] { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, ] } } /// Generated class from Pigeon that represents data sent in messages. -struct MyAdvertisementArgs { - var name: String? = nil - var manufacturerSpecificData: [Int64?: FlutterStandardTypedData?] - var serviceUUIDs: [String?] - var serviceData: [String?: FlutterStandardTypedData?] +struct MyAdvertiseDataArgs { + var nameArgs: String? = nil + var serviceUUIDsArgs: [String?] + var serviceDataArgs: [String?: FlutterStandardTypedData?] + var manufacturerSpecificDataArgs: MyManufacturerSpecificDataArgs? = nil - static func fromList(_ list: [Any?]) -> MyAdvertisementArgs? { - let name: String? = nilOrValue(list[0]) - let manufacturerSpecificData = list[1] as! [Int64?: FlutterStandardTypedData?] - let serviceUUIDs = list[2] as! [String?] - let serviceData = list[3] as! [String?: FlutterStandardTypedData?] + static func fromList(_ list: [Any?]) -> MyAdvertiseDataArgs? { + let nameArgs: String? = nilOrValue(list[0]) + let serviceUUIDsArgs = list[1] as! [String?] + let serviceDataArgs = list[2] as! [String?: FlutterStandardTypedData?] + var manufacturerSpecificDataArgs: MyManufacturerSpecificDataArgs? = nil + if let manufacturerSpecificDataArgsList: [Any?] = nilOrValue(list[3]) { + manufacturerSpecificDataArgs = MyManufacturerSpecificDataArgs.fromList(manufacturerSpecificDataArgsList) + } - return MyAdvertisementArgs( - name: name, - manufacturerSpecificData: manufacturerSpecificData, - serviceUUIDs: serviceUUIDs, - serviceData: serviceData + return MyAdvertiseDataArgs( + nameArgs: nameArgs, + serviceUUIDsArgs: serviceUUIDsArgs, + serviceDataArgs: serviceDataArgs, + manufacturerSpecificDataArgs: manufacturerSpecificDataArgs ) } func toList() -> [Any?] { return [ - name, - manufacturerSpecificData, - serviceUUIDs, - serviceData, + nameArgs, + serviceUUIDsArgs, + serviceDataArgs, + manufacturerSpecificDataArgs?.toList(), + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct MyManufacturerSpecificDataArgs { + var idArgs: Int64 + var dataArgs: FlutterStandardTypedData + + static func fromList(_ list: [Any?]) -> MyManufacturerSpecificDataArgs? { + let idArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let dataArgs = list[1] as! FlutterStandardTypedData + + return MyManufacturerSpecificDataArgs( + idArgs: idArgs, + dataArgs: dataArgs + ) + } + func toList() -> [Any?] { + return [ + idArgs, + dataArgs, ] } } /// Generated class from Pigeon that represents data sent in messages. struct MyGattServiceArgs { - var key: Int64 - var uuid: String + var hashCodeArgs: Int64 + var uuidArgs: String + var characteristicsArgs: [MyGattCharacteristicArgs?] static func fromList(_ list: [Any?]) -> MyGattServiceArgs? { - let key = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) - let uuid = list[1] as! String + let hashCodeArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let uuidArgs = list[1] as! String + let characteristicsArgs = list[2] as! [MyGattCharacteristicArgs?] return MyGattServiceArgs( - key: key, - uuid: uuid + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + characteristicsArgs: characteristicsArgs ) } func toList() -> [Any?] { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, + characteristicsArgs, ] } } /// Generated class from Pigeon that represents data sent in messages. struct MyGattCharacteristicArgs { - var key: Int64 - var uuid: String - var myPropertyNumbers: [Int64?] + var hashCodeArgs: Int64 + var uuidArgs: String + var propertyNumbersArgs: [Int64?] + var descriptorsArgs: [MyGattDescriptorArgs?] static func fromList(_ list: [Any?]) -> MyGattCharacteristicArgs? { - let key = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) - let uuid = list[1] as! String - let myPropertyNumbers = list[2] as! [Int64?] + let hashCodeArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let uuidArgs = list[1] as! String + let propertyNumbersArgs = list[2] as! [Int64?] + let descriptorsArgs = list[3] as! [MyGattDescriptorArgs?] return MyGattCharacteristicArgs( - key: key, - uuid: uuid, - myPropertyNumbers: myPropertyNumbers + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + propertyNumbersArgs: propertyNumbersArgs, + descriptorsArgs: descriptorsArgs ) } func toList() -> [Any?] { return [ - key, - uuid, - myPropertyNumbers, + hashCodeArgs, + uuidArgs, + propertyNumbersArgs, + descriptorsArgs, ] } } /// Generated class from Pigeon that represents data sent in messages. struct MyGattDescriptorArgs { - var key: Int64 - var uuid: String + var hashCodeArgs: Int64 + var uuidArgs: String + var valueArgs: FlutterStandardTypedData? = nil static func fromList(_ list: [Any?]) -> MyGattDescriptorArgs? { - let key = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) - let uuid = list[1] as! String + let hashCodeArgs = list[0] is Int64 ? list[0] as! Int64 : Int64(list[0] as! Int32) + let uuidArgs = list[1] as! String + let valueArgs: FlutterStandardTypedData? = nilOrValue(list[2]) return MyGattDescriptorArgs( - key: key, - uuid: uuid + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + valueArgs: valueArgs ) } func toList() -> [Any?] { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, + valueArgs, ] } } -private class MyCentralControllerHostApiCodecReader: FlutterStandardReader { +private class MyCentralManagerHostApiCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { case 128: - return MyCentralControllerArgs.fromList(self.readValue() as! [Any?]) + return MyCentralManagerArgs.fromList(self.readValue() as! [Any?]) case 129: return MyGattCharacteristicArgs.fromList(self.readValue() as! [Any?]) case 130: @@ -212,9 +293,9 @@ private class MyCentralControllerHostApiCodecReader: FlutterStandardReader { } } -private class MyCentralControllerHostApiCodecWriter: FlutterStandardWriter { +private class MyCentralManagerHostApiCodecWriter: FlutterStandardWriter { override func writeValue(_ value: Any) { - if let value = value as? MyCentralControllerArgs { + if let value = value as? MyCentralManagerArgs { super.writeByte(128) super.writeValue(value.toList()) } else if let value = value as? MyGattCharacteristicArgs { @@ -232,47 +313,44 @@ private class MyCentralControllerHostApiCodecWriter: FlutterStandardWriter { } } -private class MyCentralControllerHostApiCodecReaderWriter: FlutterStandardReaderWriter { +private class MyCentralManagerHostApiCodecReaderWriter: FlutterStandardReaderWriter { override func reader(with data: Data) -> FlutterStandardReader { - return MyCentralControllerHostApiCodecReader(data: data) + return MyCentralManagerHostApiCodecReader(data: data) } override func writer(with data: NSMutableData) -> FlutterStandardWriter { - return MyCentralControllerHostApiCodecWriter(data: data) + return MyCentralManagerHostApiCodecWriter(data: data) } } -class MyCentralControllerHostApiCodec: FlutterStandardMessageCodec { - static let shared = MyCentralControllerHostApiCodec(readerWriter: MyCentralControllerHostApiCodecReaderWriter()) +class MyCentralManagerHostApiCodec: FlutterStandardMessageCodec { + static let shared = MyCentralManagerHostApiCodec(readerWriter: MyCentralManagerHostApiCodecReaderWriter()) } /// Generated protocol from Pigeon that represents a handler of messages from Flutter. -protocol MyCentralControllerHostApi { - func setUp(completion: @escaping (Result) -> Void) - func tearDown() throws +protocol MyCentralManagerHostApi { + func setUp(completion: @escaping (Result) -> Void) func startDiscovery() throws func stopDiscovery() throws - func connect(myPeripheralKey: Int64, completion: @escaping (Result) -> Void) - func disconnect(myPeripheralKey: Int64, completion: @escaping (Result) -> Void) - func getMaximumWriteLength(myPeripheralKey: Int64, myTypeNumber: Int64) throws -> Int64 - func discoverGATT(myPeripheralKey: Int64, completion: @escaping (Result) -> Void) - func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] - func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] - func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] - func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) - func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) - func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) - func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) - func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) + func connect(peripheralHashCodeArgs: Int64, completion: @escaping (Result) -> Void) + func disconnect(peripheralHashCodeArgs: Int64, completion: @escaping (Result) -> Void) + func getMaximumWriteLength(peripheralHashCodeArgs: Int64, typeNumberArgs: Int64) throws -> Int64 + func readRSSI(peripheralHashCodeArgs: Int64, completion: @escaping (Result) -> Void) + func discoverGATT(peripheralHashCodeArgs: Int64, completion: @escaping (Result<[MyGattServiceArgs], Error>) -> Void) + func readCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, completion: @escaping (Result) -> Void) + func writeCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, typeNumberArgs: Int64, completion: @escaping (Result) -> Void) + func notifyCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, stateArgs: Bool, completion: @escaping (Result) -> Void) + func readDescriptor(peripheralHashCodeArgs: Int64, descriptorHashCodeArgs: Int64, completion: @escaping (Result) -> Void) + func writeDescriptor(peripheralHashCodeArgs: Int64, descriptorHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. -class MyCentralControllerHostApiSetup { - /// The codec used by MyCentralControllerHostApi. - static var codec: FlutterStandardMessageCodec { MyCentralControllerHostApiCodec.shared } - /// Sets up an instance of `MyCentralControllerHostApi` to handle messages through the `binaryMessenger`. - static func setUp(binaryMessenger: FlutterBinaryMessenger, api: MyCentralControllerHostApi?) { - let setUpChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.setUp", binaryMessenger: binaryMessenger, codec: codec) +class MyCentralManagerHostApiSetup { + /// The codec used by MyCentralManagerHostApi. + static var codec: FlutterStandardMessageCodec { MyCentralManagerHostApiCodec.shared } + /// Sets up an instance of `MyCentralManagerHostApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: MyCentralManagerHostApi?) { + let setUpChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.setUp", binaryMessenger: binaryMessenger, codec: codec) if let api = api { setUpChannel.setMessageHandler { _, reply in api.setUp() { result in @@ -287,20 +365,7 @@ class MyCentralControllerHostApiSetup { } else { setUpChannel.setMessageHandler(nil) } - let tearDownChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.tearDown", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - tearDownChannel.setMessageHandler { _, reply in - do { - try api.tearDown() - reply(wrapResult(nil)) - } catch { - reply(wrapError(error)) - } - } - } else { - tearDownChannel.setMessageHandler(nil) - } - let startDiscoveryChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.startDiscovery", binaryMessenger: binaryMessenger, codec: codec) + let startDiscoveryChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.startDiscovery", binaryMessenger: binaryMessenger, codec: codec) if let api = api { startDiscoveryChannel.setMessageHandler { _, reply in do { @@ -313,7 +378,7 @@ class MyCentralControllerHostApiSetup { } else { startDiscoveryChannel.setMessageHandler(nil) } - let stopDiscoveryChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.stopDiscovery", binaryMessenger: binaryMessenger, codec: codec) + let stopDiscoveryChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.stopDiscovery", binaryMessenger: binaryMessenger, codec: codec) if let api = api { stopDiscoveryChannel.setMessageHandler { _, reply in do { @@ -326,12 +391,12 @@ class MyCentralControllerHostApiSetup { } else { stopDiscoveryChannel.setMessageHandler(nil) } - let connectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.connect", binaryMessenger: binaryMessenger, codec: codec) + let connectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.connect", binaryMessenger: binaryMessenger, codec: codec) if let api = api { connectChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - api.connect(myPeripheralKey: myPeripheralKeyArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + api.connect(peripheralHashCodeArgs: peripheralHashCodeArgsArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -343,12 +408,12 @@ class MyCentralControllerHostApiSetup { } else { connectChannel.setMessageHandler(nil) } - let disconnectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.disconnect", binaryMessenger: binaryMessenger, codec: codec) + let disconnectChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.disconnect", binaryMessenger: binaryMessenger, codec: codec) if let api = api { disconnectChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - api.disconnect(myPeripheralKey: myPeripheralKeyArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + api.disconnect(peripheralHashCodeArgs: peripheralHashCodeArgsArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -360,14 +425,14 @@ class MyCentralControllerHostApiSetup { } else { disconnectChannel.setMessageHandler(nil) } - let getMaximumWriteLengthChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getMaximumWriteLength", binaryMessenger: binaryMessenger, codec: codec) + let getMaximumWriteLengthChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.getMaximumWriteLength", binaryMessenger: binaryMessenger, codec: codec) if let api = api { getMaximumWriteLengthChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myTypeNumberArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let typeNumberArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) do { - let result = try api.getMaximumWriteLength(myPeripheralKey: myPeripheralKeyArg, myTypeNumber: myTypeNumberArg) + let result = try api.getMaximumWriteLength(peripheralHashCodeArgs: peripheralHashCodeArgsArg, typeNumberArgs: typeNumberArgsArg) reply(wrapResult(result)) } catch { reply(wrapError(error)) @@ -376,15 +441,32 @@ class MyCentralControllerHostApiSetup { } else { getMaximumWriteLengthChannel.setMessageHandler(nil) } - let discoverGATTChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.discoverGATT", binaryMessenger: binaryMessenger, codec: codec) + let readRSSIChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.readRSSI", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + readRSSIChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + api.readRSSI(peripheralHashCodeArgs: peripheralHashCodeArgsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + readRSSIChannel.setMessageHandler(nil) + } + let discoverGATTChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.discoverGATT", binaryMessenger: binaryMessenger, codec: codec) if let api = api { discoverGATTChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - api.discoverGATT(myPeripheralKey: myPeripheralKeyArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + api.discoverGATT(peripheralHashCodeArgs: peripheralHashCodeArgsArg) { result in switch result { - case .success: - reply(wrapResult(nil)) + case .success(let res): + reply(wrapResult(res)) case .failure(let error): reply(wrapError(error)) } @@ -393,59 +475,13 @@ class MyCentralControllerHostApiSetup { } else { discoverGATTChannel.setMessageHandler(nil) } - let getServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getServices", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - getServicesChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - do { - let result = try api.getServices(myPeripheralKey: myPeripheralKeyArg) - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - getServicesChannel.setMessageHandler(nil) - } - let getCharacteristicsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getCharacteristics", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - getCharacteristicsChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let myServiceKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - do { - let result = try api.getCharacteristics(myServiceKey: myServiceKeyArg) - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - getCharacteristicsChannel.setMessageHandler(nil) - } - let getDescriptorsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getDescriptors", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - getDescriptorsChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let myCharacteristicKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - do { - let result = try api.getDescriptors(myCharacteristicKey: myCharacteristicKeyArg) - reply(wrapResult(result)) - } catch { - reply(wrapError(error)) - } - } - } else { - getDescriptorsChannel.setMessageHandler(nil) - } - let readCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.readCharacteristic", binaryMessenger: binaryMessenger, codec: codec) + let readCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.readCharacteristic", binaryMessenger: binaryMessenger, codec: codec) if let api = api { readCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) - api.readCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let characteristicHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + api.readCharacteristic(peripheralHashCodeArgs: peripheralHashCodeArgsArg, characteristicHashCodeArgs: characteristicHashCodeArgsArg) { result in switch result { case .success(let res): reply(wrapResult(res)) @@ -457,16 +493,15 @@ class MyCentralControllerHostApiSetup { } else { readCharacteristicChannel.setMessageHandler(nil) } - let writeCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.writeCharacteristic", binaryMessenger: binaryMessenger, codec: codec) + let writeCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.writeCharacteristic", binaryMessenger: binaryMessenger, codec: codec) if let api = api { writeCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) - let valueArg = args[3] as! FlutterStandardTypedData - let myTypeNumberArg = args[4] is Int64 ? args[4] as! Int64 : Int64(args[4] as! Int32) - api.writeCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, value: valueArg, myTypeNumber: myTypeNumberArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let characteristicHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let valueArgsArg = args[2] as! FlutterStandardTypedData + let typeNumberArgsArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) + api.writeCharacteristic(peripheralHashCodeArgs: peripheralHashCodeArgsArg, characteristicHashCodeArgs: characteristicHashCodeArgsArg, valueArgs: valueArgsArg, typeNumberArgs: typeNumberArgsArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -478,15 +513,14 @@ class MyCentralControllerHostApiSetup { } else { writeCharacteristicChannel.setMessageHandler(nil) } - let notifyCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.notifyCharacteristic", binaryMessenger: binaryMessenger, codec: codec) + let notifyCharacteristicChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.notifyCharacteristic", binaryMessenger: binaryMessenger, codec: codec) if let api = api { notifyCharacteristicChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myServiceKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let myCharacteristicKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) - let stateArg = args[3] as! Bool - api.notifyCharacteristic(myPeripheralKey: myPeripheralKeyArg, myServiceKey: myServiceKeyArg, myCharacteristicKey: myCharacteristicKeyArg, state: stateArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let characteristicHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let stateArgsArg = args[2] as! Bool + api.notifyCharacteristic(peripheralHashCodeArgs: peripheralHashCodeArgsArg, characteristicHashCodeArgs: characteristicHashCodeArgsArg, stateArgs: stateArgsArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -498,14 +532,13 @@ class MyCentralControllerHostApiSetup { } else { notifyCharacteristicChannel.setMessageHandler(nil) } - let readDescriptorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.readDescriptor", binaryMessenger: binaryMessenger, codec: codec) + let readDescriptorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.readDescriptor", binaryMessenger: binaryMessenger, codec: codec) if let api = api { readDescriptorChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) - api.readDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let descriptorHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + api.readDescriptor(peripheralHashCodeArgs: peripheralHashCodeArgsArg, descriptorHashCodeArgs: descriptorHashCodeArgsArg) { result in switch result { case .success(let res): reply(wrapResult(res)) @@ -517,15 +550,14 @@ class MyCentralControllerHostApiSetup { } else { readDescriptorChannel.setMessageHandler(nil) } - let writeDescriptorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.writeDescriptor", binaryMessenger: binaryMessenger, codec: codec) + let writeDescriptorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.writeDescriptor", binaryMessenger: binaryMessenger, codec: codec) if let api = api { writeDescriptorChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let myPeripheralKeyArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) - let myCharacteristicKeyArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) - let myDescriptorKeyArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) - let valueArg = args[3] as! FlutterStandardTypedData - api.writeDescriptor(myPeripheralKey: myPeripheralKeyArg, myCharacteristicKey: myCharacteristicKeyArg, myDescriptorKey: myDescriptorKeyArg, value: valueArg) { result in + let peripheralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let descriptorHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let valueArgsArg = args[2] as! FlutterStandardTypedData + api.writeDescriptor(peripheralHashCodeArgs: peripheralHashCodeArgsArg, descriptorHashCodeArgs: descriptorHashCodeArgsArg, valueArgs: valueArgsArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -539,12 +571,18 @@ class MyCentralControllerHostApiSetup { } } } -private class MyCentralControllerFlutterApiCodecReader: FlutterStandardReader { +private class MyCentralManagerFlutterApiCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { case 128: - return MyAdvertisementArgs.fromList(self.readValue() as! [Any?]) + return MyAdvertiseDataArgs.fromList(self.readValue() as! [Any?]) case 129: + return MyGattCharacteristicArgs.fromList(self.readValue() as! [Any?]) + case 130: + return MyGattDescriptorArgs.fromList(self.readValue() as! [Any?]) + case 131: + return MyManufacturerSpecificDataArgs.fromList(self.readValue() as! [Any?]) + case 132: return MyPeripheralArgs.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -552,64 +590,399 @@ private class MyCentralControllerFlutterApiCodecReader: FlutterStandardReader { } } -private class MyCentralControllerFlutterApiCodecWriter: FlutterStandardWriter { +private class MyCentralManagerFlutterApiCodecWriter: FlutterStandardWriter { override func writeValue(_ value: Any) { - if let value = value as? MyAdvertisementArgs { + if let value = value as? MyAdvertiseDataArgs { super.writeByte(128) super.writeValue(value.toList()) - } else if let value = value as? MyPeripheralArgs { + } else if let value = value as? MyGattCharacteristicArgs { super.writeByte(129) super.writeValue(value.toList()) + } else if let value = value as? MyGattDescriptorArgs { + super.writeByte(130) + super.writeValue(value.toList()) + } else if let value = value as? MyManufacturerSpecificDataArgs { + super.writeByte(131) + super.writeValue(value.toList()) + } else if let value = value as? MyPeripheralArgs { + super.writeByte(132) + super.writeValue(value.toList()) } else { super.writeValue(value) } } } -private class MyCentralControllerFlutterApiCodecReaderWriter: FlutterStandardReaderWriter { +private class MyCentralManagerFlutterApiCodecReaderWriter: FlutterStandardReaderWriter { override func reader(with data: Data) -> FlutterStandardReader { - return MyCentralControllerFlutterApiCodecReader(data: data) + return MyCentralManagerFlutterApiCodecReader(data: data) } override func writer(with data: NSMutableData) -> FlutterStandardWriter { - return MyCentralControllerFlutterApiCodecWriter(data: data) + return MyCentralManagerFlutterApiCodecWriter(data: data) } } -class MyCentralControllerFlutterApiCodec: FlutterStandardMessageCodec { - static let shared = MyCentralControllerFlutterApiCodec(readerWriter: MyCentralControllerFlutterApiCodecReaderWriter()) +class MyCentralManagerFlutterApiCodec: FlutterStandardMessageCodec { + static let shared = MyCentralManagerFlutterApiCodec(readerWriter: MyCentralManagerFlutterApiCodecReaderWriter()) } /// Generated class from Pigeon that represents Flutter messages that can be called from Swift. -class MyCentralControllerFlutterApi { +class MyCentralManagerFlutterApi { private let binaryMessenger: FlutterBinaryMessenger init(binaryMessenger: FlutterBinaryMessenger){ self.binaryMessenger = binaryMessenger } var codec: FlutterStandardMessageCodec { - return MyCentralControllerFlutterApiCodec.shared + return MyCentralManagerFlutterApiCodec.shared } - func onStateChanged(myStateNumber myStateNumberArg: Int64, completion: @escaping () -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onStateChanged", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([myStateNumberArg] as [Any?]) { _ in + func onStateChanged(stateNumberArgs stateNumberArgsArg: Int64, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onStateChanged", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([stateNumberArgsArg] as [Any?]) { _ in completion() } } - func onDiscovered(myPeripheralArgs myPeripheralArgsArg: MyPeripheralArgs, rssi rssiArg: Int64, myAdvertisementArgs myAdvertisementArgsArg: MyAdvertisementArgs, completion: @escaping () -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onDiscovered", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([myPeripheralArgsArg, rssiArg, myAdvertisementArgsArg] as [Any?]) { _ in + func onDiscovered(peripheralArgs peripheralArgsArg: MyPeripheralArgs, rssiArgs rssiArgsArg: Int64, advertiseDataArgs advertiseDataArgsArg: MyAdvertiseDataArgs, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onDiscovered", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([peripheralArgsArg, rssiArgsArg, advertiseDataArgsArg] as [Any?]) { _ in completion() } } - func onPeripheralStateChanged(myPeripheralKey myPeripheralKeyArg: Int64, state stateArg: Bool, completion: @escaping () -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onPeripheralStateChanged", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([myPeripheralKeyArg, stateArg] as [Any?]) { _ in + func onPeripheralStateChanged(peripheralArgs peripheralArgsArg: MyPeripheralArgs, stateArgs stateArgsArg: Bool, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onPeripheralStateChanged", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([peripheralArgsArg, stateArgsArg] as [Any?]) { _ in completion() } } - func onCharacteristicValueChanged(myCharacteristicKey myCharacteristicKeyArg: Int64, value valueArg: FlutterStandardTypedData, completion: @escaping () -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onCharacteristicValueChanged", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([myCharacteristicKeyArg, valueArg] as [Any?]) { _ in + func onCharacteristicValueChanged(characteristicArgs characteristicArgsArg: MyGattCharacteristicArgs, valueArgs valueArgsArg: FlutterStandardTypedData, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onCharacteristicValueChanged", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([characteristicArgsArg, valueArgsArg] as [Any?]) { _ in + completion() + } + } +} +private class MyPeripheralManagerHostApiCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 128: + return MyAdvertiseDataArgs.fromList(self.readValue() as! [Any?]) + case 129: + return MyGattCharacteristicArgs.fromList(self.readValue() as! [Any?]) + case 130: + return MyGattDescriptorArgs.fromList(self.readValue() as! [Any?]) + case 131: + return MyGattServiceArgs.fromList(self.readValue() as! [Any?]) + case 132: + return MyManufacturerSpecificDataArgs.fromList(self.readValue() as! [Any?]) + case 133: + return MyPeripheralManagerArgs.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class MyPeripheralManagerHostApiCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? MyAdvertiseDataArgs { + super.writeByte(128) + super.writeValue(value.toList()) + } else if let value = value as? MyGattCharacteristicArgs { + super.writeByte(129) + super.writeValue(value.toList()) + } else if let value = value as? MyGattDescriptorArgs { + super.writeByte(130) + super.writeValue(value.toList()) + } else if let value = value as? MyGattServiceArgs { + super.writeByte(131) + super.writeValue(value.toList()) + } else if let value = value as? MyManufacturerSpecificDataArgs { + super.writeByte(132) + super.writeValue(value.toList()) + } else if let value = value as? MyPeripheralManagerArgs { + super.writeByte(133) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class MyPeripheralManagerHostApiCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return MyPeripheralManagerHostApiCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return MyPeripheralManagerHostApiCodecWriter(data: data) + } +} + +class MyPeripheralManagerHostApiCodec: FlutterStandardMessageCodec { + static let shared = MyPeripheralManagerHostApiCodec(readerWriter: MyPeripheralManagerHostApiCodecReaderWriter()) +} + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol MyPeripheralManagerHostApi { + func setUp(completion: @escaping (Result) -> Void) + func addService(serviceArgs: MyGattServiceArgs, completion: @escaping (Result) -> Void) + func removeService(serviceHashCodeArgs: Int64) throws + func clearServices() throws + func startAdvertising(advertiseDataArgs: MyAdvertiseDataArgs, completion: @escaping (Result) -> Void) + func stopAdvertising() throws + func getMaximumWriteLength(centralHashCodeArgs: Int64) throws -> Int64 + func sendReadCharacteristicReply(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, idArgs: Int64, offsetArgs: Int64, statusArgs: Bool, valueArgs: FlutterStandardTypedData) throws + func sendWriteCharacteristicReply(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, idArgs: Int64, offsetArgs: Int64, statusArgs: Bool) throws + func notifyCharacteristicValueChanged(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class MyPeripheralManagerHostApiSetup { + /// The codec used by MyPeripheralManagerHostApi. + static var codec: FlutterStandardMessageCodec { MyPeripheralManagerHostApiCodec.shared } + /// Sets up an instance of `MyPeripheralManagerHostApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: MyPeripheralManagerHostApi?) { + let setUpChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.setUp", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setUpChannel.setMessageHandler { _, reply in + api.setUp() { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setUpChannel.setMessageHandler(nil) + } + let addServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.addService", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addServiceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let serviceArgsArg = args[0] as! MyGattServiceArgs + api.addService(serviceArgs: serviceArgsArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addServiceChannel.setMessageHandler(nil) + } + let removeServiceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.removeService", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeServiceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let serviceHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + do { + try api.removeService(serviceHashCodeArgs: serviceHashCodeArgsArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + removeServiceChannel.setMessageHandler(nil) + } + let clearServicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.clearServices", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + clearServicesChannel.setMessageHandler { _, reply in + do { + try api.clearServices() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + clearServicesChannel.setMessageHandler(nil) + } + let startAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.startAdvertising", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + startAdvertisingChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let advertiseDataArgsArg = args[0] as! MyAdvertiseDataArgs + api.startAdvertising(advertiseDataArgs: advertiseDataArgsArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + startAdvertisingChannel.setMessageHandler(nil) + } + let stopAdvertisingChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.stopAdvertising", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + stopAdvertisingChannel.setMessageHandler { _, reply in + do { + try api.stopAdvertising() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + stopAdvertisingChannel.setMessageHandler(nil) + } + let getMaximumWriteLengthChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.getMaximumWriteLength", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getMaximumWriteLengthChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let centralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + do { + let result = try api.getMaximumWriteLength(centralHashCodeArgs: centralHashCodeArgsArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getMaximumWriteLengthChannel.setMessageHandler(nil) + } + let sendReadCharacteristicReplyChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.sendReadCharacteristicReply", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + sendReadCharacteristicReplyChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let centralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let characteristicHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let idArgsArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let offsetArgsArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) + let statusArgsArg = args[4] as! Bool + let valueArgsArg = args[5] as! FlutterStandardTypedData + do { + try api.sendReadCharacteristicReply(centralHashCodeArgs: centralHashCodeArgsArg, characteristicHashCodeArgs: characteristicHashCodeArgsArg, idArgs: idArgsArg, offsetArgs: offsetArgsArg, statusArgs: statusArgsArg, valueArgs: valueArgsArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + sendReadCharacteristicReplyChannel.setMessageHandler(nil) + } + let sendWriteCharacteristicReplyChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.sendWriteCharacteristicReply", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + sendWriteCharacteristicReplyChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let centralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let characteristicHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let idArgsArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + let offsetArgsArg = args[3] is Int64 ? args[3] as! Int64 : Int64(args[3] as! Int32) + let statusArgsArg = args[4] as! Bool + do { + try api.sendWriteCharacteristicReply(centralHashCodeArgs: centralHashCodeArgsArg, characteristicHashCodeArgs: characteristicHashCodeArgsArg, idArgs: idArgsArg, offsetArgs: offsetArgsArg, statusArgs: statusArgsArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + sendWriteCharacteristicReplyChannel.setMessageHandler(nil) + } + let notifyCharacteristicValueChangedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.notifyCharacteristicValueChanged", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + notifyCharacteristicValueChangedChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let centralHashCodeArgsArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32) + let characteristicHashCodeArgsArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let valueArgsArg = args[2] as! FlutterStandardTypedData + api.notifyCharacteristicValueChanged(centralHashCodeArgs: centralHashCodeArgsArg, characteristicHashCodeArgs: characteristicHashCodeArgsArg, valueArgs: valueArgsArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + notifyCharacteristicValueChangedChannel.setMessageHandler(nil) + } + } +} +private class MyPeripheralManagerFlutterApiCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 128: + return MyCentralArgs.fromList(self.readValue() as! [Any?]) + case 129: + return MyGattCharacteristicArgs.fromList(self.readValue() as! [Any?]) + case 130: + return MyGattDescriptorArgs.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class MyPeripheralManagerFlutterApiCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? MyCentralArgs { + super.writeByte(128) + super.writeValue(value.toList()) + } else if let value = value as? MyGattCharacteristicArgs { + super.writeByte(129) + super.writeValue(value.toList()) + } else if let value = value as? MyGattDescriptorArgs { + super.writeByte(130) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class MyPeripheralManagerFlutterApiCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return MyPeripheralManagerFlutterApiCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return MyPeripheralManagerFlutterApiCodecWriter(data: data) + } +} + +class MyPeripheralManagerFlutterApiCodec: FlutterStandardMessageCodec { + static let shared = MyPeripheralManagerFlutterApiCodec(readerWriter: MyPeripheralManagerFlutterApiCodecReaderWriter()) +} + +/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. +class MyPeripheralManagerFlutterApi { + private let binaryMessenger: FlutterBinaryMessenger + init(binaryMessenger: FlutterBinaryMessenger){ + self.binaryMessenger = binaryMessenger + } + var codec: FlutterStandardMessageCodec { + return MyPeripheralManagerFlutterApiCodec.shared + } + func onStateChanged(stateNumberArgs stateNumberArgsArg: Int64, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onStateChanged", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([stateNumberArgsArg] as [Any?]) { _ in + completion() + } + } + func onReadCharacteristicCommandReceived(centralArgs centralArgsArg: MyCentralArgs, characteristicArgs characteristicArgsArg: MyGattCharacteristicArgs, idArgs idArgsArg: Int64, offsetArgs offsetArgsArg: Int64, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([centralArgsArg, characteristicArgsArg, idArgsArg, offsetArgsArg] as [Any?]) { _ in + completion() + } + } + func onWriteCharacteristicCommandReceived(centralArgs centralArgsArg: MyCentralArgs, characteristicArgs characteristicArgsArg: MyGattCharacteristicArgs, idArgs idArgsArg: Int64, offsetArgs offsetArgsArg: Int64, valueArgs valueArgsArg: FlutterStandardTypedData, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([centralArgsArg, characteristicArgsArg, idArgsArg, offsetArgsArg, valueArgsArg] as [Any?]) { _ in + completion() + } + } + func onNotifyCharacteristicCommandReceived(centralArgs centralArgsArg: MyCentralArgs, characteristicArgs characteristicArgsArg: MyGattCharacteristicArgs, stateArgs stateArgsArg: Bool, completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([centralArgsArg, characteristicArgsArg, stateArgsArg] as [Any?]) { _ in completion() } } diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyApi.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyApi.swift new file mode 100644 index 0000000..c1a6f01 --- /dev/null +++ b/bluetooth_low_energy_darwin/darwin/Classes/MyApi.swift @@ -0,0 +1,286 @@ +// +// MyApi.swift +// bluetooth_low_energy_darwin +// +// Created by 闫守旺 on 2023/9/28. +// + +import Foundation +import CoreBluetooth + +#if os(iOS) +import Flutter +#elseif os(macOS) +import FlutterMacOS +#else +#error("Unsupported platform.") +#endif + +extension CBManagerState { + func toArgs() -> MyBluetoothLowEnergyStateArgs { + switch self { + case .unauthorized: + return .unauthorized + case .poweredOff: + return .poweredOff + case .poweredOn: + return .poweredOn + default: + return .unsupported + } + } +} + +extension CBPeer { + var uuidArgs: String { identifier.uuidString } +} + +extension CBCentral { + func toArgs() -> MyCentralArgs { + let hashCodeArgs = Int64(hash) + return MyCentralArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs) + } +} + +extension CBPeripheral { + func toArgs() -> MyPeripheralArgs { + let hashCodeArgs = Int64(hash) + return MyPeripheralArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs) + } +} + +extension CBAttribute { + var uuidArgs: String { uuid.uuidString } +} + +extension CBService { + func toArgs(_ characteristicsArgs: [MyGattCharacteristicArgs]) -> MyGattServiceArgs { + let hashCodeArgs = Int64(hash) + return MyGattServiceArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs, characteristicsArgs: characteristicsArgs) + } +} + +extension CBCharacteristic { + func toArgs(_ descriptorsArgs: [MyGattDescriptorArgs]) -> MyGattCharacteristicArgs { + let hashCodeArgs = Int64(hash) + return MyGattCharacteristicArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs, propertyNumbersArgs: propertyNumbersArgs, descriptorsArgs: descriptorsArgs) + } + + var propertyNumbersArgs: [Int64] { + var propertiesArgs = [MyGattCharacteristicPropertyArgs]() + let properties = self.properties + if properties.contains(.read) { + propertiesArgs.append(.read) + } + if properties.contains(.write) { + propertiesArgs.append(.write) + } + if properties.contains(.writeWithoutResponse) { + propertiesArgs.append(.writeWithoutResponse) + } + if properties.contains(.notify) { + propertiesArgs.append(.notify) + } + if properties.contains(.indicate) { + propertiesArgs.append(.indicate) + } + return propertiesArgs.map { args in Int64(args.rawValue) } + } +} + +extension CBDescriptor { + func toArgs() -> MyGattDescriptorArgs { + let hashCodeArgs = Int64(hash) + return MyGattDescriptorArgs(hashCodeArgs: hashCodeArgs, uuidArgs: uuidArgs) + } +} + +extension MyGattCharacteristicWriteTypeArgs { + func toWriteType() -> CBCharacteristicWriteType { + switch self { + case .withResponse: + return .withResponse + case .withoutResponse: + return .withoutResponse + } + } +} + +extension String { + var data: Data { data(using: String.Encoding.utf8)! } +} + +extension NSNumber { + var data: Data { + var source = self + return Data(bytes: &source, count: MemoryLayout.size) + } +} + +extension UInt16 { + var data: Data { + var source = self + return Data(bytes: &source, count: MemoryLayout.size) + } +} + +extension [String: Any] { + func toAdvertiseDataArgs() -> MyAdvertiseDataArgs { + let nameArgs = self[CBAdvertisementDataLocalNameKey] as? String + let serviceUUIDs = self[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] ?? [] + let serviceUUIDsArgs = serviceUUIDs.map { uuid in uuid.uuidString } + let serviceData = self[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] ?? [:] + let serviceDataArgsKeyWithValues = serviceData.map { (uuid, data) in + let uuidArgs = uuid.uuidString + let dataArgs = FlutterStandardTypedData(bytes: data) + return (uuidArgs, dataArgs) + } + let serviceDataArgs = [String?: FlutterStandardTypedData?](uniqueKeysWithValues: serviceDataArgsKeyWithValues) + let manufacturerSpecificData = self[CBAdvertisementDataManufacturerDataKey] as? Data + let manufacturerSpecificDataArgs = manufacturerSpecificData?.toManufacturerSpecificDataArgs() + return MyAdvertiseDataArgs(nameArgs: nameArgs, serviceUUIDsArgs: serviceUUIDsArgs, serviceDataArgs: serviceDataArgs, manufacturerSpecificDataArgs: manufacturerSpecificDataArgs) + } +} + +extension Data { + func toManufacturerSpecificDataArgs() -> MyManufacturerSpecificDataArgs? { + if count > 2 { + let idArgs = Int64(self[0]) | (Int64(self[1]) << 8) + let data = self[2...count - 1] + let dataArgs = FlutterStandardTypedData(bytes: data) + return MyManufacturerSpecificDataArgs(idArgs: idArgs, dataArgs: dataArgs) + } else { + return nil + } + } +} + +extension MyAdvertiseDataArgs { + func toAdvertiseData() throws -> [String : Any] { + // CoreBluetooth only support `CBAdvertisementDataLocalNameKey` and `CBAdvertisementDataServiceUUIDsKey`, see https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393252-startadvertising + var advertiseData = [String: Any]() + if nameArgs != nil { + let name = nameArgs! + advertiseData[CBAdvertisementDataLocalNameKey] = name + } + if serviceUUIDsArgs.count > 0 { + var serviceUUIDs = [CBUUID]() + for args in serviceUUIDsArgs { + guard let uuidArgs = args else { + throw MyError.illegalArgument + } + let uuid = CBUUID(string: uuidArgs) + serviceUUIDs.append(uuid) + } + advertiseData[CBAdvertisementDataServiceUUIDsKey] = serviceUUIDs + } +// if serviceDataArgs.count > 0 { +// var serviceData = [CBUUID: Data]() +// for args in serviceDataArgs { +// guard let uuidArgs = args.key else { +// throw MyError.illegalArgument +// } +// guard let dataArgs = args.value else { +// throw MyError.illegalArgument +// } +// let uuid = CBUUID(string: uuidArgs) +// let data = dataArgs.data +// serviceData[uuid] = data +// } +// advertiseData[CBAdvertisementDataServiceDataKey] = serviceData +// } +// if manufacturerSpecificDataArgs != nil { +// let manufacturerSpecificData = manufacturerSpecificDataArgs!.toManufacturerSpecificData() +// advertiseData[CBAdvertisementDataManufacturerDataKey] = manufacturerSpecificData +// } + return advertiseData + } +} + +//extension MyManufacturerSpecificDataArgs { +// func toManufacturerSpecificData() -> Data { +// let id = UInt16(idArgs).data +// let data = dataArgs.data +// return id + data +// } +//} + +extension MyGattServiceArgs { + func toService() -> CBMutableService { + let type = CBUUID(string: uuidArgs) + let primary = true + return CBMutableService(type: type, primary: primary) + } +} + +extension MyGattCharacteristicArgs { + func toCharacteristic() -> CBMutableCharacteristic { + let type = CBUUID(string: uuidArgs) + return CBMutableCharacteristic(type: type, properties: properties, value: nil, permissions: permissions) + } + + var properties: CBCharacteristicProperties { + var properties: CBCharacteristicProperties = [] + for args in propertyNumbersArgs { + guard let rawArgs = args else { + continue + } + let rawValue = Int(rawArgs) + let property = MyGattCharacteristicPropertyArgs(rawValue: rawValue) + switch property { + case .read: + properties.insert(.read) + case .write: + properties.insert(.write) + case .writeWithoutResponse: + properties.insert(.writeWithoutResponse) + case .notify: + properties.insert(.notify) + case .indicate: + properties.insert(.indicate) + default: + continue + } + } + return properties + } + + var permissions: CBAttributePermissions { + var permissions: CBAttributePermissions = [] + for args in propertyNumbersArgs { + guard let rawArgs = args else { + continue + } + let rawValue = Int(rawArgs) + let property = MyGattCharacteristicPropertyArgs(rawValue: rawValue) + switch property { + case .read: + permissions.insert(.readable) + case .write, .writeWithoutResponse: + permissions.insert(.writeable) + default: + continue + } + } + return permissions + } +} + +extension MyGattDescriptorArgs { + func toDescriptor() -> CBMutableDescriptor { + let type = CBUUID(string: uuidArgs) + let value = valueArgs?.data + return CBMutableDescriptor(type: type, value: value) + } +} + +extension Dictionary { + mutating func getOrPut(_ key: Key, _ defaultValue: () -> Value) -> Value { + guard let value = self[key] else { + let value1 = defaultValue() + self[key] = value1 + return value1 + } + return value + } +} diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyCentralController.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyCentralController.swift deleted file mode 100644 index b1fe0e5..0000000 --- a/bluetooth_low_energy_darwin/darwin/Classes/MyCentralController.swift +++ /dev/null @@ -1,737 +0,0 @@ -// -// MyCentralController.swift -// bluetooth_low_energy_ios -// -// Created by 闫守旺 on 2023/8/13. -// - -import Foundation -import CoreBluetooth -#if os(iOS) -import Flutter -#elseif os(macOS) -import FlutterMacOS -#else -#error("Unsupported platform.") -#endif - -class MyCentralController: MyCentralControllerHostApi { - init(_ binaryMessenger: FlutterBinaryMessenger) { - myApi = MyCentralControllerFlutterApi(binaryMessenger: binaryMessenger) - } - - private let myApi: MyCentralControllerFlutterApi - private lazy var myCentralManagerDelegate = MyCentralManagerDelegate(self) - private lazy var myPeripheralDelegate = MyPeripheralDelegate(self) - private let centralManager = CBCentralManager() - - private var cachedPeripherals = [Int: CBPeripheral]() - private var cachedServices = [Int: [Int: CBService]]() - private var cachedCharacteristics = [Int: [Int: CBCharacteristic]]() - private var cachedDescriptors = [Int: [Int: CBDescriptor]]() - - var setUpCompletion: ((Result) -> Void)? - var connectCompletions = [Int: (Result) -> Void]() - var disconnectCompletions = [Int: (Result) -> Void]() - var discoverGattCompletions = [Int: (Result) -> Void]() - var unfinishedServices = [Int: [CBService]]() - var unfinishedCharacteristics = [Int: [CBCharacteristic]]() - var readCharacteristicCompletions = [Int: (Result) -> Void]() - var writeCharacteristicCompletions = [Int: (Result) -> Void]() - var notifyCharacteristicCompletions = [Int: (Result) -> Void]() - var readDescriptorCompletions = [Int: (Result) -> Void]() - var writeDescriptorCompletions = [Int: (Result) -> Void]() - - func setUp(completion: @escaping (Result) -> Void) { - do { - let unfinishedCompletion = setUpCompletion - if unfinishedCompletion != nil { - throw MyError.illegalState - } - centralManager.delegate = myCentralManagerDelegate - if centralManager.state == .unknown { - setUpCompletion = completion - } else { - let myStateArgs = centralManager.state.toMyArgs() - let myStateNumber = Int64(myStateArgs.rawValue) - let myArgs = MyCentralControllerArgs(myStateNumber: myStateNumber) - completion(.success(myArgs)) - } - } catch { - completion(.failure(error)) - } - } - - func tearDown() throws { - centralManager.delegate = nil - if(centralManager.isScanning) { - centralManager.stopScan() - } - for peripheral in cachedPeripherals.values { - peripheral.delegate = nil - if peripheral.state != .disconnected { - centralManager.cancelPeripheralConnection(peripheral) - } - } - cachedPeripherals.removeAll() - cachedServices.removeAll() - cachedCharacteristics.removeAll() - cachedDescriptors.removeAll() - } - - func startDiscovery() throws { - let options = [CBCentralManagerScanOptionAllowDuplicatesKey: true] - centralManager.scanForPeripherals(withServices: nil, options: options) - } - - func stopDiscovery() throws { - centralManager.stopScan() - } - - func connect(myPeripheralKey: Int64, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - let unfinishedCompletion = connectCompletions[peripheralKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - centralManager.connect(peripheral) - connectCompletions[peripheralKey] = completion - } catch { - completion(.failure(error)) - } - } - - func disconnect(myPeripheralKey: Int64, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - let unfinishedCompletion = disconnectCompletions[peripheralKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - centralManager.cancelPeripheralConnection(peripheral) - disconnectCompletions[peripheralKey] = completion - } catch { - completion(.failure(error)) - } - } - - func getMaximumWriteLength(myPeripheralKey: Int64, myTypeNumber: Int64) throws -> Int64 { - let peripheralKey = Int(myPeripheralKey) - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - let myTypeRawValue = Int(myTypeNumber) - guard let myTypeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: myTypeRawValue) else { - throw MyError.illegalArgument - } - let type = myTypeArgs.toType() - let maximumWriteLength32 = peripheral.maximumWriteValueLength(for: type) - let maximumWriteLength = Int64(maximumWriteLength32) - return maximumWriteLength - } - - func discoverGATT(myPeripheralKey: Int64, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - let unfinishedCompletion = discoverGattCompletions[peripheralKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - peripheral.discoverServices(nil) - discoverGattCompletions[peripheralKey] = completion - } catch { - completion(.failure(error)) - } - } - - func getServices(myPeripheralKey: Int64) throws -> [MyGattServiceArgs] { - let peripheralKey = Int(myPeripheralKey) - guard let services = cachedServices[peripheralKey] else { - throw MyError.illegalArgument - } - return services.map { (key, service) in - return service.toMyArgs() - } - } - - func getCharacteristics(myServiceKey: Int64) throws -> [MyGattCharacteristicArgs] { - let serviceKey = Int(myServiceKey) - guard let characteristics = cachedCharacteristics[serviceKey] else { - throw MyError.illegalArgument - } - return characteristics.map { (key, characteristic) in - return characteristic.toMyArgs() - } - } - - func getDescriptors(myCharacteristicKey: Int64) throws -> [MyGattDescriptorArgs] { - let characteristicKey = Int(myCharacteristicKey) - guard let descriptors = cachedDescriptors[characteristicKey] else { - throw MyError.illegalArgument - } - return descriptors.map { (key, descriptor) in - return descriptor.toMyArgs() - } - } - - func readCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - let serviceKey = Int(myServiceKey) - guard let characteristics = cachedCharacteristics[serviceKey] else { - throw MyError.illegalArgument - } - let characteristicKey = Int(myCharacteristicKey) - guard let characteristic = characteristics[characteristicKey] else { - throw MyError.illegalArgument - } - let unfinishedCompletion = readCharacteristicCompletions[characteristicKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - peripheral.readValue(for: characteristic) - readCharacteristicCompletions[characteristicKey] = completion - } catch { - completion(.failure(error)) - } - } - - func writeCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, value: FlutterStandardTypedData, myTypeNumber: Int64, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - let serviceKey = Int(myServiceKey) - guard let characteristics = cachedCharacteristics[serviceKey] else { - throw MyError.illegalArgument - } - let characteristicKey = Int(myCharacteristicKey) - guard let characteristic = characteristics[characteristicKey] else { - throw MyError.illegalArgument - } - let data = value.data - let myTypeRawValue = Int(myTypeNumber) - guard let myTypeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: myTypeRawValue) else { - throw MyError.illegalArgument - } - let type = myTypeArgs.toType() - let unfinishedCompletion = writeCharacteristicCompletions[characteristicKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - peripheral.writeValue(data, for: characteristic, type: type) - writeCharacteristicCompletions[characteristicKey] = completion - } catch { - completion(.failure(error)) - } - } - - func notifyCharacteristic(myPeripheralKey: Int64, myServiceKey: Int64, myCharacteristicKey: Int64, state: Bool, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - let serviceKey = Int(myServiceKey) - guard let characteristics = cachedCharacteristics[serviceKey] else { - throw MyError.illegalArgument - } - let characteristicKey = Int(myCharacteristicKey) - guard let characteristic = characteristics[characteristicKey] else { - throw MyError.illegalArgument - } - let unfinishedCompletion = notifyCharacteristicCompletions[characteristicKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - peripheral.setNotifyValue(state, for: characteristic) - notifyCharacteristicCompletions[characteristicKey] = completion - } catch { - completion(.failure(error)) - } - } - - func readDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - let characteristicKey = Int(myCharacteristicKey) - guard let descriptors = cachedDescriptors[characteristicKey] else { - throw MyError.illegalArgument - } - let descriptorKey = Int(myDescriptorKey) - guard let descriptor = descriptors[descriptorKey] else { - throw MyError.illegalArgument - } - let unfinishedCompletion = readDescriptorCompletions[descriptorKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - peripheral.readValue(for: descriptor) - readDescriptorCompletions[descriptorKey] = completion - } catch { - completion(.failure(error)) - } - } - - func writeDescriptor(myPeripheralKey: Int64, myCharacteristicKey: Int64, myDescriptorKey: Int64, value: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { - do { - let peripheralKey = Int(myPeripheralKey) - guard let peripheral = cachedPeripherals[peripheralKey] else { - throw MyError.illegalArgument - } - let characteristicKey = Int(myCharacteristicKey) - guard let descriptors = cachedDescriptors[characteristicKey] else { - throw MyError.illegalArgument - } - let descriptorKey = Int(myDescriptorKey) - guard let descriptor = descriptors[descriptorKey] else { - throw MyError.illegalArgument - } - let data = value.data - let unfinishedCompletion = writeDescriptorCompletions[descriptorKey] - if unfinishedCompletion != nil { - throw MyError.illegalState - } - peripheral.writeValue(data, for: descriptor) - writeDescriptorCompletions[descriptorKey] = completion - } catch { - completion(.failure(error)) - } - } - - func didUpdateState(_ state: CBManagerState) { - let completion = setUpCompletion - if state != .unknown && completion != nil { - let myStateArgs = state.toMyArgs() - let myStateNumber = Int64(myStateArgs.rawValue) - let myArgs = MyCentralControllerArgs(myStateNumber: myStateNumber) - completion!(.success(myArgs)) - setUpCompletion = nil - } - let myStateArgs = state.toMyArgs() - let myStateNumber = Int64(myStateArgs.rawValue) - myApi.onStateChanged(myStateNumber: myStateNumber) {} - } - - - func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssiNumber: NSNumber) { - let peripheralKey = peripheral.hash - if cachedPeripherals[peripheralKey] == nil { - peripheral.delegate = myPeripheralDelegate - cachedPeripherals[peripheralKey] = peripheral - } - let myPeripheralArgs = peripheral.toMyArgs() - let rssi = rssiNumber.int64Value - let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String - let rawManufacturerSpecificData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data - var manufacturerSpecificData = [Int64: FlutterStandardTypedData]() - if rawManufacturerSpecificData != nil { - do { - guard let data = rawManufacturerSpecificData else { - throw MyError.illegalArgument - } - guard data.count >= 2 else { - throw MyError.illegalArgument - } - let key = Int64(data[0]) | (Int64(data[1]) << 8) - let bytes = data.count > 2 ? data[2...data.count-1] : Data() - let value = FlutterStandardTypedData(bytes: bytes) - manufacturerSpecificData[key] = value - } catch { - manufacturerSpecificData = [:] - } - } - let rawServiceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] ?? [] - let serviceUUIDs = rawServiceUUIDs.map { uuid in uuid.uuidString } - let rawServiceData = advertisementData[CBAdvertisementDataServiceDataKey] as? [CBUUID: Data] ?? [:] - let elements = rawServiceData.map { (uuid, data) in - let key = uuid.uuidString - let value = FlutterStandardTypedData(bytes: data) - return (key, value) - } - let serviceData = [String?: FlutterStandardTypedData?](uniqueKeysWithValues: elements) - let myAdvertisementArgs = MyAdvertisementArgs(name: name, manufacturerSpecificData: manufacturerSpecificData, serviceUUIDs: serviceUUIDs, serviceData: serviceData) - myApi.onDiscovered(myPeripheralArgs: myPeripheralArgs, rssi: rssi, myAdvertisementArgs: myAdvertisementArgs) {} - } - - func didConnect(_ peripheral: CBPeripheral) { - let peripheralKey = peripheral.hash - let myPeripheralKey = Int64(peripheralKey) - myApi.onPeripheralStateChanged(myPeripheralKey: myPeripheralKey, state: true) {} - guard let completion = connectCompletions.removeValue(forKey: peripheralKey) else { - return - } - completion(.success(())) - } - - func didFailToConnect(_ peripheral: CBPeripheral, _ error: Error?) { - let peripheralKey = peripheral.hash - guard let completion = connectCompletions.removeValue(forKey: peripheralKey) else { - return - } - completion(.failure(error ?? MyError.unknown)) - } - - func didDisconnectPeripheral(_ peripheral: CBPeripheral, _ error: Error?) { - let peripheralKey = peripheral.hash - let myPeripheralKey = Int64(peripheralKey) - let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralKey) - if discoverGattCompletion != nil { - didDiscoverGATT(peripheral, error ?? MyError.unknown) - } - let services = cachedServices[peripheralKey] ?? [:] - for service in services { - let characteristics = cachedCharacteristics[service.key] ?? [:] - for characteristic in characteristics { - let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristic.key) - let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristic.key) - if readCharacteristicCompletion != nil { - readCharacteristicCompletion!(.failure(MyError.illegalState)) - } - if writeCharacteristicCompletion != nil { - writeCharacteristicCompletion!(.failure(MyError.illegalState)) - } - let descriptors = cachedDescriptors[characteristic.key] ?? [:] - for descriptor in descriptors { - let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptor.key) - let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptor.key) - if readDescriptorCompletion != nil { - readDescriptorCompletion!(.failure(MyError.illegalState)) - } - if writeDescriptorCompletion != nil { - writeDescriptorCompletion!(.failure(MyError.illegalState)) - } - } - } - } - myApi.onPeripheralStateChanged(myPeripheralKey: myPeripheralKey, state: false) {} - guard let completion = disconnectCompletions.removeValue(forKey: peripheralKey) else { - return - } - if error == nil { - completion(.success(())) - } else { - completion(.failure(error!)) - } - } - - - func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) { - let peripheralKey = peripheral.hash - if error == nil { - var services = peripheral.services ?? [] - if services.isEmpty { - didDiscoverGATT(peripheral, error) - } else { - let service = services.removeFirst() - unfinishedServices[peripheralKey] = services - peripheral.discoverCharacteristics(nil, for: service) - } - } else { - didDiscoverGATT(peripheral, error) - } - } - - func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) { - let peripheralKey = peripheral.hash - if error == nil { - var characteristics = service.characteristics ?? [] - if characteristics.isEmpty { - var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] - if services.isEmpty { - didDiscoverGATT(peripheral, error) - } else { - let service = services.removeFirst() - unfinishedServices[peripheralKey] = services - peripheral.discoverCharacteristics(nil, for: service) - } - } else { - let characteristic = characteristics.removeFirst() - unfinishedCharacteristics[peripheralKey] = characteristics - peripheral.discoverDescriptors(for: characteristic) - } - } else { - didDiscoverGATT(peripheral, error) - } - } - - func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) { - let peripheralKey = peripheral.hash - if error == nil { - var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralKey) ?? [] - if (characteristics.isEmpty) { - var services = unfinishedServices.removeValue(forKey: peripheralKey) ?? [] - if services.isEmpty { - didDiscoverGATT(peripheral, error) - } else { - let service = services.removeFirst() - unfinishedServices[peripheralKey] = services - peripheral.discoverCharacteristics(nil, for: service) - } - } else { - let characteristic = characteristics.removeFirst() - unfinishedCharacteristics[peripheralKey] = characteristics - peripheral.discoverDescriptors(for: characteristic) - } - } else { - didDiscoverGATT(peripheral, error) - } - } - - private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) { - let peripheralKey = peripheral.hash - unfinishedServices.removeValue(forKey: peripheralKey) - unfinishedCharacteristics.removeValue(forKey: peripheralKey) - guard let completion = discoverGattCompletions.removeValue(forKey: peripheralKey) else { - return - } - if error == nil { - let services = peripheral.services ?? [] - var cachedServices = [Int: CBService]() - for service in services { - let serviceKey = service.hash - cachedServices[serviceKey] = service - let characteristics = service.characteristics ?? [] - var cachedCharacteristics = [Int: CBCharacteristic]() - for characteristic in characteristics { - let characteristicKey = characteristic.hash - cachedCharacteristics[characteristicKey] = characteristic - let descriptors = characteristic.descriptors ?? [] - var cachedDescriptors = [Int: CBDescriptor]() - for descriptor in descriptors { - let descriptorKey = descriptor.hash - cachedDescriptors[descriptorKey] = descriptor - } - self.cachedDescriptors[characteristicKey] = cachedDescriptors - } - self.cachedCharacteristics[serviceKey] = cachedCharacteristics - } - self.cachedServices[peripheralKey] = cachedServices - completion(.success(())) - } else { - completion(.failure(error!)) - } - } - - func didUpdateCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) { - let characteristicKey = characteristic.hash - guard let completion = readCharacteristicCompletions.removeValue(forKey: characteristicKey) else { - let myCharacteristicKey = Int64(characteristicKey) - let rawValue = characteristic.value ?? Data() - let value = FlutterStandardTypedData(bytes: rawValue) - myApi.onCharacteristicValueChanged(myCharacteristicKey: myCharacteristicKey, value: value) {} - return - } - if error == nil { - let rawValue = characteristic.value ?? Data() - let value = FlutterStandardTypedData(bytes: rawValue) - completion(.success(value)) - } else { - completion(.failure(error!)) - } - } - - func didWriteCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) { - let characteristicKey = characteristic.hash - guard let completion = writeCharacteristicCompletions.removeValue(forKey: characteristicKey) else { - return - } - if error == nil { - completion(.success(())) - } else { - completion(.failure(error!)) - } - } - - func didUpdateNotificationState(_ characteristic: CBCharacteristic, _ error: Error?) { - let characteristicKey = characteristic.hash - guard let completion = notifyCharacteristicCompletions.removeValue(forKey: characteristicKey) else { - return - } - if error == nil { - completion(.success(())) - } else { - completion(.failure(error!)) - } - } - - func didUpdateDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) { - let descriptorKey = descriptor.hash - guard let completion = readDescriptorCompletions.removeValue(forKey: descriptorKey) else { - return - } - if error == nil { - // TODO: Need to confirm wheather the corresponding descriptor type and value is correct. - let value: FlutterStandardTypedData - let rawValue = descriptor.value - do { - switch descriptor.uuid.uuidString { - case CBUUIDCharacteristicExtendedPropertiesString: - fallthrough - case CBUUIDClientCharacteristicConfigurationString: - fallthrough - case CBUUIDServerCharacteristicConfigurationString: - guard let rawNumber = rawValue as? NSNumber else { - throw MyError.illegalArgument - } - value = FlutterStandardTypedData(bytes: rawNumber.data) - case CBUUIDCharacteristicUserDescriptionString: - fallthrough - case CBUUIDCharacteristicAggregateFormatString: - guard let rawString = rawValue as? String else { - throw MyError.illegalArgument - } - value = FlutterStandardTypedData(bytes: rawString.data) - case CBUUIDCharacteristicFormatString: - guard let rawData = rawValue as? Data else { - throw MyError.illegalArgument - } - value = FlutterStandardTypedData(bytes: rawData) - case CBUUIDL2CAPPSMCharacteristicString: - guard let rawU16 = rawValue as? UInt16 else { - throw MyError.illegalArgument - } - value = FlutterStandardTypedData(bytes: rawU16.data) - default: - throw MyError.illegalArgument - } - } catch { - value = FlutterStandardTypedData() - } - completion(.success((value))) - } else { - completion(.failure(error!)) - } - } - - func didWriteDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) { - let descriptorKey = descriptor.hash - guard let completion = writeDescriptorCompletions.removeValue(forKey: descriptorKey) else { - return - } - if error == nil { - completion(.success(())) - } else { - completion(.failure(error!)) - } - } -} - -extension CBManagerState { - func toMyArgs() -> MyCentralStateArgs { - switch self { - case .unauthorized: - return .unauthorized - case .poweredOff: - return .poweredOff - case .poweredOn: - return .poweredOn - default: - return .unsupported - } - } -} - -extension CBPeripheral { - func toMyArgs() -> MyPeripheralArgs { - let key = Int64(hash) - let uuid = identifier.uuidString - return MyPeripheralArgs(key: key, uuid: uuid) - } -} - -extension CBService { - func toMyArgs() -> MyGattServiceArgs { - let key = Int64(hash) - let uuid = uuid.uuidString - return MyGattServiceArgs(key: key, uuid: uuid) - } -} - -extension CBCharacteristic { - func toMyArgs() -> MyGattCharacteristicArgs { - let key = Int64(hash) - let uuid = uuid.uuidString - let myPropertyArgses = properties.toMyArgses() - let myPropertyNumbers = myPropertyArgses.map { myPropertyArgs in Int64(myPropertyArgs.rawValue) } - return MyGattCharacteristicArgs(key: key, uuid: uuid, myPropertyNumbers: myPropertyNumbers) - } -} - -extension CBDescriptor { - func toMyArgs() -> MyGattDescriptorArgs { - let key = Int64(hash) - let uuid = uuid.uuidString - return MyGattDescriptorArgs(key: key, uuid: uuid) - } -} - -extension CBCharacteristicProperties { - func toMyArgses() -> [MyGattCharacteristicPropertyArgs] { - var myPropertyArgs = [MyGattCharacteristicPropertyArgs]() - if contains(.read) { - myPropertyArgs.append(.read) - } - if contains(.write) { - myPropertyArgs.append(.write) - } - if contains(.writeWithoutResponse) { - myPropertyArgs.append(.writeWithoutResponse) - } - if contains(.notify) { - myPropertyArgs.append(.notify) - } - if contains(.indicate) { - myPropertyArgs.append(.indicate) - } - return myPropertyArgs - } -} - -extension MyGattCharacteristicWriteTypeArgs { - func toType() -> CBCharacteristicWriteType { - switch self { - case .withResponse: - return .withResponse - case .withoutResponse: - return .withoutResponse - } - } -} - -extension NSNumber { - var data: Data { - var source = self - return Data(bytes: &source, count: MemoryLayout.size) - } -} - -extension String { - var data: Data { - return data(using: String.Encoding.utf8)! - } -} - -extension UInt16 { - var data: Data { - var source = self - return Data(bytes: &source, count: MemoryLayout.size) - } -} diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyCentralManager.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyCentralManager.swift new file mode 100644 index 0000000..fe7fb3e --- /dev/null +++ b/bluetooth_low_energy_darwin/darwin/Classes/MyCentralManager.swift @@ -0,0 +1,650 @@ +// +// MyCentralController.swift +// bluetooth_low_energy_ios +// +// Created by 闫守旺 on 2023/8/13. +// + +import Foundation +import CoreBluetooth + +#if os(iOS) +import Flutter +#elseif os(macOS) +import FlutterMacOS +#else +#error("Unsupported platform.") +#endif + +class MyCentralManager: MyCentralManagerHostApi { + init(_ binaryMessenger: FlutterBinaryMessenger) { + self.binaryMessenger = binaryMessenger + } + + private let binaryMessenger: FlutterBinaryMessenger + private let centralManager = CBCentralManager() + + private lazy var api = MyCentralManagerFlutterApi(binaryMessenger: binaryMessenger) + private lazy var centralManagerDelegate = MyCentralManagerDelegate(self) + private lazy var peripheralDelegate = MyPeripheralDelegate(self) + + private var peripherals = [Int64: CBPeripheral]() + private var services = [Int64: CBService]() + private var characteristics = [Int64: CBCharacteristic]() + private var descriptors = [Int64: CBDescriptor]() + + private var peripheralsArgs = [Int: MyPeripheralArgs]() + private var servicesArgsOfPeripheralsArgs = [Int64: [MyGattServiceArgs]]() + private var servicesArgs = [Int: MyGattServiceArgs]() + private var characteristicsArgs = [Int: MyGattCharacteristicArgs]() + private var descriptorsArgs = [Int: MyGattDescriptorArgs]() + + private var setUpCompletion: ((Result) -> Void)? + private var connectCompletions = [Int64: (Result) -> Void]() + private var disconnectCompletions = [Int64: (Result) -> Void]() + private var readRssiCompletions = [Int64: (Result) -> Void]() + private var discoverGattCompletions = [Int64: (Result<[MyGattServiceArgs], Error>) -> Void]() + private var unfinishedServices = [Int64: [CBService]]() + private var unfinishedCharacteristics = [Int64: [CBCharacteristic]]() + private var readCharacteristicCompletions = [Int64: (Result) -> Void]() + private var writeCharacteristicCompletions = [Int64: (Result) -> Void]() + private var notifyCharacteristicCompletions = [Int64: (Result) -> Void]() + private var readDescriptorCompletions = [Int64: (Result) -> Void]() + private var writeDescriptorCompletions = [Int64: (Result) -> Void]() + + func setUp(completion: @escaping (Result) -> Void) { + do { + if setUpCompletion != nil { + throw MyError.illegalState + } + try tearDown() + centralManager.delegate = centralManagerDelegate + if centralManager.state == .unknown { + setUpCompletion = completion + } else { + let stateArgs = centralManager.state.toArgs() + let stateNumberArgs = Int64(stateArgs.rawValue) + let args = MyCentralManagerArgs(stateNumberArgs: stateNumberArgs) + completion(.success(args)) + } + } catch { + completion(.failure(error)) + } + } + + func tearDown() throws { + if(centralManager.isScanning) { + centralManager.stopScan() + } + for peripheral in peripherals.values { + if peripheral.state != .disconnected { + centralManager.cancelPeripheralConnection(peripheral) + } + } + peripherals.removeAll() + services.removeAll() + characteristics.removeAll() + descriptors.removeAll() + peripheralsArgs.removeAll() + servicesArgsOfPeripheralsArgs.removeAll() + servicesArgs.removeAll() + characteristicsArgs.removeAll() + descriptorsArgs.removeAll() + setUpCompletion = nil + connectCompletions.removeAll() + disconnectCompletions.removeAll() + readRssiCompletions.removeAll() + discoverGattCompletions.removeAll() + unfinishedServices.removeAll() + unfinishedCharacteristics.removeAll() + readCharacteristicCompletions.removeAll() + writeCharacteristicCompletions.removeAll() + notifyCharacteristicCompletions.removeAll() + readDescriptorCompletions.removeAll() + writeDescriptorCompletions.removeAll() + } + + func startDiscovery() throws { + let options = [CBCentralManagerScanOptionAllowDuplicatesKey: true] + centralManager.scanForPeripherals(withServices: nil, options: options) + } + + func stopDiscovery() throws { + centralManager.stopScan() + } + + func connect(peripheralHashCodeArgs: Int64, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = connectCompletions[peripheralHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + centralManager.connect(peripheral) + connectCompletions[peripheralHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func disconnect(peripheralHashCodeArgs: Int64, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = disconnectCompletions[peripheralHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + centralManager.cancelPeripheralConnection(peripheral) + disconnectCompletions[peripheralHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func getMaximumWriteLength(peripheralHashCodeArgs: Int64, typeNumberArgs: Int64) throws -> Int64 { + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + let typeRawValue = Int(typeNumberArgs) + guard let typeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: typeRawValue) else { + throw MyError.illegalArgument + } + let type = typeArgs.toWriteType() + let maximumWriteLength = peripheral.maximumWriteValueLength(for: type) + let maximumWriteLengthArgs = Int64(maximumWriteLength) + return maximumWriteLengthArgs + } + + func readRSSI(peripheralHashCodeArgs: Int64, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = readRssiCompletions[peripheralHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + peripheral.readRSSI() + readRssiCompletions[peripheralHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func discoverGATT(peripheralHashCodeArgs: Int64, completion: @escaping (Result<[MyGattServiceArgs], Error>) -> Void) { + do { + let unfinishedCompletion = discoverGattCompletions[peripheralHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + peripheral.discoverServices(nil) + discoverGattCompletions[peripheralHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func readCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = readCharacteristicCompletions[characteristicHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + guard let characteristic = characteristics[characteristicHashCodeArgs] else { + throw MyError.illegalArgument + } + peripheral.readValue(for: characteristic) + readCharacteristicCompletions[characteristicHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func writeCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, typeNumberArgs: Int64, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = writeCharacteristicCompletions[characteristicHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + guard let characteristic = characteristics[characteristicHashCodeArgs] else { + throw MyError.illegalArgument + } + let data = valueArgs.data + let typeRawValue = Int(typeNumberArgs) + guard let typeArgs = MyGattCharacteristicWriteTypeArgs(rawValue: typeRawValue) else { + throw MyError.illegalArgument + } + let type = typeArgs.toWriteType() + peripheral.writeValue(data, for: characteristic, type: type) + writeCharacteristicCompletions[characteristicHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func notifyCharacteristic(peripheralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, stateArgs: Bool, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = notifyCharacteristicCompletions[characteristicHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + guard let characteristic = characteristics[characteristicHashCodeArgs] else { + throw MyError.illegalArgument + } + let enabled = stateArgs + peripheral.setNotifyValue(enabled, for: characteristic) + notifyCharacteristicCompletions[characteristicHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func readDescriptor(peripheralHashCodeArgs: Int64, descriptorHashCodeArgs: Int64, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = readDescriptorCompletions[descriptorHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + guard let descriptor = descriptors[descriptorHashCodeArgs] else { + throw MyError.illegalArgument + } + peripheral.readValue(for: descriptor) + readDescriptorCompletions[descriptorHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func writeDescriptor(peripheralHashCodeArgs: Int64, descriptorHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { + do { + let unfinishedCompletion = writeDescriptorCompletions[descriptorHashCodeArgs] + if unfinishedCompletion != nil { + throw MyError.illegalState + } + guard let peripheral = peripherals[peripheralHashCodeArgs] else { + throw MyError.illegalArgument + } + guard let descriptor = descriptors[descriptorHashCodeArgs] else { + throw MyError.illegalArgument + } + let data = valueArgs.data + peripheral.writeValue(data, for: descriptor) + writeDescriptorCompletions[descriptorHashCodeArgs] = completion + } catch { + completion(.failure(error)) + } + } + + func didUpdateState() { + let state = centralManager.state + let stateArgs = state.toArgs() + let stateNumberArgs = Int64(stateArgs.rawValue) + if state != .unknown && setUpCompletion != nil { + let args = MyCentralManagerArgs(stateNumberArgs: stateNumberArgs) + setUpCompletion!(.success(args)) + setUpCompletion = nil + } + api.onStateChanged(stateNumberArgs: stateNumberArgs) {} + } + + + func didDiscover(_ peripheral: CBPeripheral, _ advertisementData: [String : Any], _ rssi: NSNumber) { + let peripheralArgs = peripheral.toArgs() + let peripheralHashCode = peripheral.hash + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + peripheral.delegate = peripheralDelegate + peripherals[peripheralHashCodeArgs] = peripheral + peripheralsArgs[peripheralHashCode] = peripheralArgs + let rssiArgs = rssi.int64Value + let advertiseDataArgs = advertisementData.toAdvertiseDataArgs() + api.onDiscovered(peripheralArgs: peripheralArgs, rssiArgs: rssiArgs, advertiseDataArgs: advertiseDataArgs) {} + } + + func didConnect(_ peripheral: CBPeripheral) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + let completion = connectCompletions.removeValue(forKey: peripheralHashCodeArgs) + completion?(.success(())) + let stateArgs = true + api.onPeripheralStateChanged(peripheralArgs: peripheralArgs, stateArgs: stateArgs) {} + } + + func didFailToConnect(_ peripheral: CBPeripheral, _ error: Error?) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + let completion = connectCompletions.removeValue(forKey: peripheralHashCodeArgs) + completion?(.failure(error ?? MyError.unknown)) + } + + func didDisconnectPeripheral(_ peripheral: CBPeripheral, _ error: Error?) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + let readRssiCompletion = readRssiCompletions.removeValue(forKey: peripheralHashCodeArgs) + readRssiCompletion?(.failure(error ?? MyError.unknown)) + let discoverGattCompletion = discoverGattCompletions.removeValue(forKey: peripheralHashCodeArgs) + discoverGattCompletion?(.failure(error ?? MyError.unknown)) + unfinishedServices.removeValue(forKey: peripheralHashCodeArgs) + unfinishedCharacteristics.removeValue(forKey: peripheralHashCodeArgs) + let servicesArgs = servicesArgsOfPeripheralsArgs[peripheralHashCodeArgs] ?? [] + for serviceArgs in servicesArgs { + let characteristicsArgs = serviceArgs.characteristicsArgs.map { args in args! } + for characteristicArgs in characteristicsArgs { + let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + let readCharacteristicCompletion = readCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) + let writeCharacteristicCompletion = writeCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) + let notifyCharacteristicCompletion = notifyCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) + readCharacteristicCompletion?(.failure(error ?? MyError.unknown)) + writeCharacteristicCompletion?(.failure(error ?? MyError.unknown)) + notifyCharacteristicCompletion?(.failure(error ?? MyError.unknown)) + let descriptorsArgs = characteristicArgs.descriptorsArgs.map { args in args! } + for descriptorArgs in descriptorsArgs { + let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + let readDescriptorCompletion = readDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs) + let writeDescriptorCompletion = writeDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs) + readDescriptorCompletion?(.failure(error ?? MyError.unknown)) + writeDescriptorCompletion?(.failure(error ?? MyError.unknown)) + } + } + } + let stateArgs = false + api.onPeripheralStateChanged(peripheralArgs: peripheralArgs, stateArgs: stateArgs) {} + guard let completion = disconnectCompletions.removeValue(forKey: peripheralHashCodeArgs) else { + return + } + if error == nil { + completion(.success(())) + } else { + completion(.failure(error!)) + } + } + + func didReadRSSI(_ peripheral: CBPeripheral, _ rssi: NSNumber, _ error: Error?) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + guard let completion = readRssiCompletions.removeValue(forKey: peripheralHashCodeArgs) else { + return + } + if error == nil { + let rssiArgs = rssi.int64Value + completion(.success((rssiArgs))) + } else { + completion(.failure(error!)) + } + } + + func didDiscoverServices(_ peripheral: CBPeripheral, _ error: Error?) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + if error == nil { + var services = peripheral.services ?? [] + if services.isEmpty { + didDiscoverGATT(peripheral, error) + } else { + let service = services.removeFirst() + unfinishedServices[peripheralHashCodeArgs] = services + peripheral.discoverCharacteristics(nil, for: service) + } + } else { + didDiscoverGATT(peripheral, error) + } + } + + func didDiscoverCharacteristics(_ peripheral: CBPeripheral, _ service: CBService, _ error: Error?) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + if error == nil { + var characteristics = service.characteristics ?? [] + if characteristics.isEmpty { + var services = unfinishedServices.removeValue(forKey: peripheralHashCodeArgs) ?? [] + if services.isEmpty { + didDiscoverGATT(peripheral, error) + } else { + let service = services.removeFirst() + unfinishedServices[peripheralHashCodeArgs] = services + peripheral.discoverCharacteristics(nil, for: service) + } + } else { + let characteristic = characteristics.removeFirst() + unfinishedCharacteristics[peripheralHashCodeArgs] = characteristics + peripheral.discoverDescriptors(for: characteristic) + } + } else { + didDiscoverGATT(peripheral, error) + } + } + + func didDiscoverDescriptors(_ peripheral: CBPeripheral, _ characteristic: CBCharacteristic, _ error: Error?) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralHashCodeArgs = peripheralArgs.hashCodeArgs + if error == nil { + var characteristics = unfinishedCharacteristics.removeValue(forKey: peripheralHashCodeArgs) ?? [] + if (characteristics.isEmpty) { + var services = unfinishedServices.removeValue(forKey: peripheralHashCodeArgs) ?? [] + if services.isEmpty { + didDiscoverGATT(peripheral, error) + } else { + let service = services.removeFirst() + unfinishedServices[peripheralHashCodeArgs] = services + peripheral.discoverCharacteristics(nil, for: service) + } + } else { + let characteristic = characteristics.removeFirst() + unfinishedCharacteristics[peripheralHashCodeArgs] = characteristics + peripheral.discoverDescriptors(for: characteristic) + } + } else { + didDiscoverGATT(peripheral, error) + } + } + + private func didDiscoverGATT(_ peripheral: CBPeripheral, _ error: Error?) { + let peripheralHashCode = peripheral.hash + guard let peripheralArgs = peripheralsArgs[peripheralHashCode] else { + return + } + let peripheralhashCodeArgs = peripheralArgs.hashCodeArgs + guard let completion = discoverGattCompletions.removeValue(forKey: peripheralhashCodeArgs) else { + return + } + if error == nil { + let services = peripheral.services ?? [] + var servicesArgs = [MyGattServiceArgs]() + for service in services { + let characteristics = service.characteristics ?? [] + var characteristicsArgs = [MyGattCharacteristicArgs]() + for characteristic in characteristics { + let descriptors = characteristic.descriptors ?? [] + var descriptorsArgs = [MyGattDescriptorArgs]() + for descriptor in descriptors { + let descriptorArgs = descriptor.toArgs() + let descriptorHashCode = descriptor.hash + let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + self.descriptors[descriptorHashCodeArgs] = descriptor + self.descriptorsArgs[descriptorHashCode] = descriptorArgs + descriptorsArgs.append(descriptorArgs) + } + let characteristicArgs = characteristic.toArgs(descriptorsArgs) + let characteristicHashCode = characteristic.hash + let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + self.characteristics[characteristicHashCodeArgs] = characteristic + self.characteristicsArgs[characteristicHashCode] = characteristicArgs + characteristicsArgs.append(characteristicArgs) + } + let serviceArgs = service.toArgs(characteristicsArgs) + let serviceHashCode = service.hash + let servcieHashCodeArgs = serviceArgs.hashCodeArgs + self.services[servcieHashCodeArgs] = service + self.servicesArgs[serviceHashCode] = serviceArgs + servicesArgs.append(serviceArgs) + } + servicesArgsOfPeripheralsArgs[peripheralhashCodeArgs] = servicesArgs + completion(.success((servicesArgs))) + } else { + completion(.failure(error!)) + unfinishedServices.removeValue(forKey: peripheralhashCodeArgs) + unfinishedCharacteristics.removeValue(forKey: peripheralhashCodeArgs) + } + } + + func didUpdateCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) { + let characteristicHashCode = characteristic.hash + guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else { + return + } + let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + guard let completion = readCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) else { + let value = characteristic.value ?? Data() + let valueArgs = FlutterStandardTypedData(bytes: value) + api.onCharacteristicValueChanged(characteristicArgs: characteristicArgs, valueArgs: valueArgs) {} + return + } + if error == nil { + let value = characteristic.value ?? Data() + let valueArgs = FlutterStandardTypedData(bytes: value) + completion(.success(valueArgs)) + } else { + completion(.failure(error!)) + } + } + + func didWriteCharacteristicValue(_ characteristic: CBCharacteristic, _ error: Error?) { + let characteristicHashCode = characteristic.hash + guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else { + return + } + let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + guard let completion = writeCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) else { + return + } + if error == nil { + completion(.success(())) + } else { + completion(.failure(error!)) + } + } + + func didUpdateNotificationState(_ characteristic: CBCharacteristic, _ error: Error?) { + let characteristicHashCode = characteristic.hash + guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else { + return + } + let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + guard let completion = notifyCharacteristicCompletions.removeValue(forKey: characteristicHashCodeArgs) else { + return + } + if error == nil { + completion(.success(())) + } else { + completion(.failure(error!)) + } + } + + func didUpdateDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) { + let descriptorHashCode = descriptor.hash + guard let descriptorArgs = descriptorsArgs[descriptorHashCode] else { + return + } + let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + guard let completion = readDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs) else { + return + } + if error == nil { + // TODO: Need to confirm wheather the corresponding descriptor type and value is correct. + let valueArgs: FlutterStandardTypedData + let value = descriptor.value + do { + switch descriptor.uuid.uuidString { + case CBUUIDCharacteristicExtendedPropertiesString: + fallthrough + case CBUUIDClientCharacteristicConfigurationString: + fallthrough + case CBUUIDServerCharacteristicConfigurationString: + guard let numberValue = value as? NSNumber else { + throw MyError.illegalArgument + } + valueArgs = FlutterStandardTypedData(bytes: numberValue.data) + case CBUUIDCharacteristicUserDescriptionString: + fallthrough + case CBUUIDCharacteristicAggregateFormatString: + guard let stringValue = value as? String else { + throw MyError.illegalArgument + } + valueArgs = FlutterStandardTypedData(bytes: stringValue.data) + case CBUUIDCharacteristicFormatString: + guard let bytes = value as? Data else { + throw MyError.illegalArgument + } + valueArgs = FlutterStandardTypedData(bytes: bytes) + case CBUUIDL2CAPPSMCharacteristicString: + guard let uint16Value = value as? UInt16 else { + throw MyError.illegalArgument + } + valueArgs = FlutterStandardTypedData(bytes: uint16Value.data) + default: + throw MyError.illegalArgument + } + } catch { + valueArgs = FlutterStandardTypedData() + } + completion(.success((valueArgs))) + } else { + completion(.failure(error!)) + } + } + + func didWriteDescriptorValue(_ descriptor: CBDescriptor, _ error: Error?) { + let descriptorHashCode = descriptor.hash + guard let descriptorArgs = descriptorsArgs[descriptorHashCode] else { + return + } + let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + guard let completion = writeDescriptorCompletions.removeValue(forKey: descriptorHashCodeArgs) else { + return + } + if error == nil { + completion(.success(())) + } else { + completion(.failure(error!)) + } + } +} diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyCentralManagerDelegate.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyCentralManagerDelegate.swift index 377137d..9fdc05d 100644 --- a/bluetooth_low_energy_darwin/darwin/Classes/MyCentralManagerDelegate.swift +++ b/bluetooth_low_energy_darwin/darwin/Classes/MyCentralManagerDelegate.swift @@ -9,30 +9,29 @@ import Foundation import CoreBluetooth class MyCentralManagerDelegate: NSObject, CBCentralManagerDelegate { - private let myCentralController: MyCentralController - - init(_ myCentralController: MyCentralController) { - self.myCentralController = myCentralController + init(_ centralManager: MyCentralManager) { + self.centralManager = centralManager } + private let centralManager: MyCentralManager + func centralManagerDidUpdateState(_ central: CBCentralManager) { - let state = central.state - myCentralController.didUpdateState(state) + centralManager.didUpdateState() } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { - myCentralController.didDiscover(peripheral, advertisementData, RSSI) + centralManager.didDiscover(peripheral, advertisementData, RSSI) } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { - myCentralController.didConnect(peripheral) + centralManager.didConnect(peripheral) } func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { - myCentralController.didFailToConnect(peripheral, error) + centralManager.didFailToConnect(peripheral, error) } func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - myCentralController.didDisconnectPeripheral(peripheral, error) + centralManager.didDisconnectPeripheral(peripheral, error) } } diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralDelegate.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralDelegate.swift index 5915d9b..d0617fb 100644 --- a/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralDelegate.swift +++ b/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralDelegate.swift @@ -9,41 +9,45 @@ import Foundation import CoreBluetooth class MyPeripheralDelegate: NSObject, CBPeripheralDelegate { - private let myCentralController: MyCentralController + private let centralManager: MyCentralManager - init(_ myCentralController: MyCentralController) { - self.myCentralController = myCentralController + init(_ centralManager: MyCentralManager) { + self.centralManager = centralManager + } + + func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { + centralManager.didReadRSSI(peripheral, RSSI, error) } func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - myCentralController.didDiscoverServices(peripheral, error) + centralManager.didDiscoverServices(peripheral, error) } func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - myCentralController.didDiscoverCharacteristics(peripheral, service, error) + centralManager.didDiscoverCharacteristics(peripheral, service, error) } func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) { - myCentralController.didDiscoverDescriptors(peripheral, characteristic, error) + centralManager.didDiscoverDescriptors(peripheral, characteristic, error) } func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - myCentralController.didUpdateCharacteristicValue(characteristic, error) + centralManager.didUpdateCharacteristicValue(characteristic, error) } func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { - myCentralController.didWriteCharacteristicValue(characteristic, error) + centralManager.didWriteCharacteristicValue(characteristic, error) } func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - myCentralController.didUpdateNotificationState(characteristic, error) + centralManager.didUpdateNotificationState(characteristic, error) } func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?) { - myCentralController.didUpdateDescriptorValue(descriptor, error) + centralManager.didUpdateDescriptorValue(descriptor, error) } func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) { - myCentralController.didWriteDescriptorValue(descriptor, error) + centralManager.didWriteDescriptorValue(descriptor, error) } } diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManager.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManager.swift new file mode 100644 index 0000000..e382922 --- /dev/null +++ b/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManager.swift @@ -0,0 +1,375 @@ +// +// MyPeripheralManager.swift +// bluetooth_low_energy_darwin +// +// Created by 闫守旺 on 2023/10/7. +// + +import Foundation +import CoreBluetooth + +#if os(iOS) +import Flutter +#elseif os(macOS) +import FlutterMacOS +#else +#error("Unsupported platform.") +#endif + +class MyPeripheralManager: MyPeripheralManagerHostApi { + init(_ binaryMessenger: FlutterBinaryMessenger) { + self.binaryMessenger = binaryMessenger + } + + private let binaryMessenger: FlutterBinaryMessenger + private let peripheralManager = CBPeripheralManager() + + private lazy var api = MyPeripheralManagerFlutterApi(binaryMessenger: binaryMessenger) + private lazy var peripheralManagerDelegate = MyPeripheralManagerDelegate(self) + + private var centrals = [Int64: CBCentral]() + private var services = [Int64: CBMutableService]() + private var characteristics = [Int64: CBMutableCharacteristic]() + private var descriptors = [Int64: CBMutableDescriptor]() + private var requests = [Int64: CBATTRequest]() + + private var centralsArgs = [Int: MyCentralArgs]() + private var servicesArgs = [Int: MyGattServiceArgs]() + private var characteristicsArgs = [Int: MyGattCharacteristicArgs]() + private var descriptorsArgs = [Int: MyGattDescriptorArgs]() + + private var setUpCompletion: ((Result) -> Void)? + private var addServiceCompletion: ((Result) -> Void)? + private var startAdvertisingCompletion: ((Result) -> Void)? + private var notifyCharacteristicValueChangedCallbacks = [() -> Void]() + + func setUp(completion: @escaping (Result) -> Void) { + do { + if setUpCompletion != nil { + throw MyError.illegalState + } + try tearDown() + peripheralManager.delegate = peripheralManagerDelegate + if peripheralManager.state == .unknown { + setUpCompletion = completion + } else { + let stateArgs = peripheralManager.state.toArgs() + let stateNumberArgs = Int64(stateArgs.rawValue) + let args = MyPeripheralManagerArgs(stateNumberArgs: stateNumberArgs) + completion(.success(args)) + } + } catch { + completion(.failure(error)) + } + } + + func tearDown() throws { + if(peripheralManager.isAdvertising) { + peripheralManager.stopAdvertising() + } + centrals.removeAll() + services.removeAll() + characteristics.removeAll() + descriptors.removeAll() + requests.removeAll() + centralsArgs.removeAll() + servicesArgs.removeAll() + characteristicsArgs.removeAll() + descriptorsArgs.removeAll() + setUpCompletion = nil + addServiceCompletion = nil + startAdvertisingCompletion = nil + notifyCharacteristicValueChangedCallbacks.removeAll() + } + + func addService(serviceArgs: MyGattServiceArgs, completion: @escaping (Result) -> Void) { + do { + if addServiceCompletion != nil { + throw MyError.illegalState + } + let service = serviceArgs.toService() + var characteristics = [CBMutableCharacteristic]() + let characteristicsArgs = serviceArgs.characteristicsArgs + for args in characteristicsArgs { + guard let characteristicArgs = args else { + continue + } + let characteristic = characteristicArgs.toCharacteristic() + var descriptors = [CBMutableDescriptor]() + let descriptorsArgs = characteristicArgs.descriptorsArgs + for args in descriptorsArgs { + guard let descriptorArgs = args else { + continue + } + let descriptor = descriptorArgs.toDescriptor() + descriptors.append(descriptor) + let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + let descriptorHashCode = descriptor.hash + self.descriptorsArgs[descriptorHashCode] = descriptorArgs + self.descriptors[descriptorHashCodeArgs] = descriptor + } + characteristic.descriptors = descriptors + characteristics.append(characteristic) + let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + let characteristicHashCode = characteristic.hash + self.characteristicsArgs[characteristicHashCode] = characteristicArgs + self.characteristics[characteristicHashCodeArgs] = characteristic + } + service.characteristics = characteristics + let serviceHashCodeArgs = serviceArgs.hashCodeArgs + let serviceHashCode = service.hash + self.servicesArgs[serviceHashCode] = serviceArgs + self.services[serviceHashCodeArgs] = service + peripheralManager.add(service) + addServiceCompletion = completion + } catch { + freeService(serviceArgs) + completion(.failure(error)) + } + } + + func removeService(serviceHashCodeArgs: Int64) throws { + guard let service = services[serviceHashCodeArgs] else { + throw MyError.illegalArgument + } + let serviceHashCode = service.hash + guard let serviceArgs = servicesArgs[serviceHashCode] else { + throw MyError.illegalArgument + } + peripheralManager.remove(service) + freeService(serviceArgs) + } + + func clearServices() throws { + peripheralManager.removeAllServices() + let servicesArgs = self.servicesArgs.values + for serviceArgs in servicesArgs { + freeService(serviceArgs) + } + } + + private func freeService(_ serviceArgs: MyGattServiceArgs) { + let characteristicsArgs = serviceArgs.characteristicsArgs + for args in characteristicsArgs { + guard let characteristicArgs = args else { + continue + } + let descriptorsArgs = characteristicArgs.descriptorsArgs + for args in descriptorsArgs { + guard let descriptorArgs = args else { + continue + } + let descriptorHashCodeArgs = descriptorArgs.hashCodeArgs + guard let descriptor = self.descriptors.removeValue(forKey: descriptorHashCodeArgs) else { + continue + } + let descriptorHashCode = descriptor.hash + self.descriptorsArgs.removeValue(forKey: descriptorHashCode) + } + let characteristicHashCodeArgs = characteristicArgs.hashCodeArgs + guard let characteristic = self.characteristics.removeValue(forKey: characteristicHashCodeArgs) else { + continue + } + let characteristicHashCode = characteristic.hash + self.characteristicsArgs.removeValue(forKey: characteristicHashCode) + } + let serviceHashCodeArgs = serviceArgs.hashCodeArgs + guard let service = self.services.removeValue(forKey: serviceHashCodeArgs) else { + return + } + let serviceHashCode = service.hash + self.servicesArgs.removeValue(forKey: serviceHashCode) + } + + func startAdvertising(advertiseDataArgs: MyAdvertiseDataArgs, completion: @escaping (Result) -> Void) { + do { + if startAdvertisingCompletion != nil { + throw MyError.illegalState + } + let advertisementData = try advertiseDataArgs.toAdvertiseData() + peripheralManager.startAdvertising(advertisementData) + startAdvertisingCompletion = completion + } catch { + completion(.failure(error)) + } + } + + func stopAdvertising() throws { + peripheralManager.stopAdvertising() + } + + func getMaximumWriteLength(centralHashCodeArgs: Int64) throws -> Int64 { + guard let central = centrals[centralHashCodeArgs] else { + throw MyError.illegalArgument + } + let maximumWriteLength = central.maximumUpdateValueLength + let maximumWriteLengthArgs = Int64(maximumWriteLength) + return maximumWriteLengthArgs + } + + func sendReadCharacteristicReply(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, idArgs: Int64, offsetArgs: Int64, statusArgs: Bool, valueArgs: FlutterStandardTypedData) throws { + guard let request = requests[idArgs] else { + throw MyError.illegalArgument + } + request.value = valueArgs.data + let result = statusArgs ? CBATTError.Code.success : CBATTError.Code.requestNotSupported + peripheralManager.respond(to: request, withResult: result) + } + + func sendWriteCharacteristicReply(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, idArgs: Int64, offsetArgs: Int64, statusArgs: Bool) throws { + guard let request = requests[idArgs] else { + throw MyError.illegalArgument + } + let result = statusArgs ? CBATTError.Code.success : CBATTError.Code.requestNotSupported + peripheralManager.respond(to: request, withResult: result) + } + + func notifyCharacteristicValueChanged(centralHashCodeArgs: Int64, characteristicHashCodeArgs: Int64, valueArgs: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { + do { + if notifyCharacteristicValueChangedCallbacks.count > 0 { + throw MyError.illegalState + } + let value = valueArgs.data + guard let characteristic = characteristics[characteristicHashCodeArgs] else { + throw MyError.illegalArgument + } + guard let central = centrals[centralHashCodeArgs] else { + throw MyError.illegalArgument + } + let centrals = [central] + let updated = peripheralManager.updateValue(value, for: characteristic, onSubscribedCentrals: centrals) + if updated { + completion(.success(())) + } else { + notifyCharacteristicValueChangedCallbacks.append { + let updated = self.peripheralManager.updateValue(value, for: characteristic, onSubscribedCentrals: centrals) + if updated { + completion(.success(())) + } else { + completion(.failure(MyError.unknown)) + } + } + } + } catch { + completion(.failure(error)) + } + } + + func didUpdateState() { + let state = peripheralManager.state + let stateArgs = state.toArgs() + let stateNumberArgs = Int64(stateArgs.rawValue) + if state != .unknown && setUpCompletion != nil { + let args = MyPeripheralManagerArgs(stateNumberArgs: stateNumberArgs) + setUpCompletion!(.success(args)) + setUpCompletion = nil + } + api.onStateChanged(stateNumberArgs: stateNumberArgs) {} + } + + func didAdd(_ service: CBService, _ error: Error?) { + guard let completion = addServiceCompletion else { + return + } + addServiceCompletion = nil + if error == nil { + completion(.success(())) + } else { + completion(.failure(error!)) + let serviceHashCode = service.hash + guard let serviceArgs = servicesArgs[serviceHashCode] else { + return + } + freeService(serviceArgs) + } + } + + func didStartAdvertising(_ error: Error?) { + guard let completion = startAdvertisingCompletion else { + return + } + startAdvertisingCompletion = nil + if error == nil { + completion(.success(())) + } else { + completion(.failure(error!)) + } + } + + func didReceiveRead(_ request: CBATTRequest) { + let central = request.central + let centralHashCode = central.hash + let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() } + let centralHashCodeArgs = centralArgs.hashCodeArgs + centrals[centralHashCodeArgs] = central + let characteristic = request.characteristic + let characteristicHashCode = characteristic.hash + guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else { + peripheralManager.respond(to: request, withResult: .attributeNotFound) + return + } + let idArgs = Int64(request.hash) + requests[idArgs] = request + let offsetArgs = Int64(request.offset) + api.onReadCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, idArgs: idArgs, offsetArgs: offsetArgs) {} + } + + func didReceiveWrite(_ requests: [CBATTRequest]) { + for request in requests { + let central = request.central + let centralHashCode = central.hash + let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() } + let centralHashCodeArgs = centralArgs.hashCodeArgs + centrals[centralHashCodeArgs] = central + let characteristic = request.characteristic + let characteristicHashCode = characteristic.hash + guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else { + peripheralManager.respond(to: request, withResult: .attributeNotFound) + return + } + let idArgs = Int64(request.hash) + self.requests[idArgs] = request + let offsetArgs = Int64(request.offset) + guard let value = request.value else { + peripheralManager.respond(to: request, withResult: .requestNotSupported) + return + } + let valueArgs = FlutterStandardTypedData(bytes: value) + api.onWriteCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, idArgs: idArgs, offsetArgs: offsetArgs, valueArgs: valueArgs) {} + } + } + + func didSubscribeTo(_ central: CBCentral, _ characteristic: CBCharacteristic) { + let centralHashCode = central.hash + let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() } + let centralHashCodeArgs = centralArgs.hashCodeArgs + centrals[centralHashCodeArgs] = central + let characteristicHashCode = characteristic.hash + guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else { + return + } + let stateArgs = true + api.onNotifyCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, stateArgs: stateArgs) {} + } + + func didUnsubscribeFrom(_ central: CBCentral, _ characteristic: CBCharacteristic) { + let centralHashCode = central.hash + let centralArgs = centralsArgs.getOrPut(centralHashCode) { central.toArgs() } + let centralHashCodeArgs = centralArgs.hashCodeArgs + centrals[centralHashCodeArgs] = central + let characteristicHashCode = characteristic.hash + guard let characteristicArgs = characteristicsArgs[characteristicHashCode] else { + return + } + let stateArgs = false + api.onNotifyCharacteristicCommandReceived(centralArgs: centralArgs, characteristicArgs: characteristicArgs, stateArgs: stateArgs) {} + } + + func isReadyToUpdateSubscribers() { + let callbacks = notifyCharacteristicValueChangedCallbacks + notifyCharacteristicValueChangedCallbacks.removeAll() + for callback in callbacks { + callback() + } + } +} diff --git a/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManagerDelegate.swift b/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManagerDelegate.swift new file mode 100644 index 0000000..e8c784d --- /dev/null +++ b/bluetooth_low_energy_darwin/darwin/Classes/MyPeripheralManagerDelegate.swift @@ -0,0 +1,49 @@ +// +// MyPeripheralManagerDelegate.swift +// bluetooth_low_energy_darwin +// +// Created by 闫守旺 on 2023/10/7. +// + +import Foundation +import CoreBluetooth + +class MyPeripheralManagerDelegate: NSObject, CBPeripheralManagerDelegate { + init(_ peripheralManager: MyPeripheralManager) { + self.peripheralManager = peripheralManager + } + + private let peripheralManager: MyPeripheralManager + + func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { + peripheralManager.didUpdateState() + } + + func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) { + peripheralManager.didAdd(service, error) + } + + func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) { + peripheralManager.didStartAdvertising(error) + } + + func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) { + peripheralManager.didReceiveRead(request) + } + + func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) { + peripheralManager.didReceiveWrite(requests) + } + + func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) { + peripheralManager.didSubscribeTo(central, characteristic) + } + + func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) { + peripheralManager.didUnsubscribeFrom(central, characteristic) + } + + func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) { + peripheralManager.isReadyToUpdateSubscribers() + } +} diff --git a/bluetooth_low_energy_darwin/lib/bluetooth_low_energy_darwin.dart b/bluetooth_low_energy_darwin/lib/bluetooth_low_energy_darwin.dart index 9dd5f3d..ba802f9 100644 --- a/bluetooth_low_energy_darwin/lib/bluetooth_low_energy_darwin.dart +++ b/bluetooth_low_energy_darwin/lib/bluetooth_low_energy_darwin.dart @@ -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 BluetoothLowEnergyDarwin { static void registerWith() { - CentralController.instance = MyCentralController(); + BluetoothLowEnergy.instance = MyBluetoothLowEnergy(); } } diff --git a/bluetooth_low_energy_darwin/lib/src/my_api.dart b/bluetooth_low_energy_darwin/lib/src/my_api.dart new file mode 100644 index 0000000..08e60d5 --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_api.dart @@ -0,0 +1,224 @@ +import 'dart:typed_data'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_api.g.dart'; +import 'my_gatt_characteristic2.dart'; +import 'my_gatt_descriptor2.dart'; +import 'my_gatt_service2.dart'; + +export 'my_api.g.dart'; + +extension MyBluetoothLowEnergyStateArgsX on MyBluetoothLowEnergyStateArgs { + BluetoothLowEnergyState toState() { + return BluetoothLowEnergyState.values[index]; + } +} + +extension MyAdvertiseDataArgsX on MyAdvertiseDataArgs { + AdvertiseData toAdvertiseData() { + final name = nameArgs; + final serviceUUIDs = serviceUUIDsArgs + .cast() + .map((args) => UUID.fromString(args)) + .toList(); + final serviceData = serviceDataArgs.cast().map( + (uuidArgs, dataArgs) { + final uuid = UUID.fromString(uuidArgs); + final data = dataArgs; + return MapEntry(uuid, data); + }, + ); + final manufacturerSpecificData = + manufacturerSpecificDataArgs?.toManufacturerSpecificData(); + return AdvertiseData( + name: name, + serviceUUIDs: serviceUUIDs, + serviceData: serviceData, + manufacturerSpecificData: manufacturerSpecificData, + ); + } +} + +extension MyManufacturerSpecificDataArgsX on MyManufacturerSpecificDataArgs { + ManufacturerSpecificData toManufacturerSpecificData() { + final id = idArgs; + final data = dataArgs; + return ManufacturerSpecificData( + id: id, + data: data, + ); + } +} + +extension MyGattCharacteristicPropertyArgsX + on MyGattCharacteristicPropertyArgs { + GattCharacteristicProperty toProperty() { + return GattCharacteristicProperty.values[index]; + } +} + +extension GattCharacteristicWriteTypeX on GattCharacteristicWriteType { + MyGattCharacteristicWriteTypeArgs toArgs() { + return MyGattCharacteristicWriteTypeArgs.values[index]; + } +} + +extension MyPeripheralArgsX on MyPeripheralArgs { + Peripheral toPeripheral() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + return MyPeripheral( + hashCode: hashCode, + uuid: uuid, + ); + } +} + +extension MyGattServiceArgsX on MyGattServiceArgs { + MyGattService2 toService2() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + final characteristics = characteristicsArgs + .cast() + .map((args) => args.toCharacteristic2()) + .toList(); + return MyGattService2( + hashCode: hashCode, + uuid: uuid, + characteristics: characteristics, + ); + } +} + +extension MyGattCharacteristicArgsX on MyGattCharacteristicArgs { + MyGattCharacteristic2 toCharacteristic2() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + final properties = propertyNumbersArgs.cast().map( + (args) { + final propertyArgs = MyGattCharacteristicPropertyArgs.values[args]; + return propertyArgs.toProperty(); + }, + ).toList(); + final descriptors = descriptorsArgs + .cast() + .map((args) => args.toDescriptor2()) + .toList(); + return MyGattCharacteristic2( + hashCode: hashCode, + uuid: uuid, + properties: properties, + descriptors: descriptors, + ); + } +} + +extension MyGattDescriptorArgsX on MyGattDescriptorArgs { + MyGattDescriptor2 toDescriptor2() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + return MyGattDescriptor2( + hashCode: hashCode, + uuid: uuid, + ); + } +} + +extension MyCentralArgsX on MyCentralArgs { + MyCentral toCentral() { + final hashCode = hashCodeArgs; + final uuid = UUID.fromString(uuidArgs); + return MyCentral( + hashCode: hashCode, + uuid: uuid, + ); + } +} + +extension AdvertiseDataX on AdvertiseData { + MyAdvertiseDataArgs toArgs() { + final nameArgs = name; + final serviceUUIDsArgs = + serviceUUIDs.map((uuid) => uuid.toString()).toList(); + final serviceDataArgs = serviceData.map((uuid, data) { + final uuidArgs = uuid.toString(); + final dataArgs = data; + return MapEntry(uuidArgs, dataArgs); + }); + final manufacturerSpecificDataArgs = manufacturerSpecificData?.toArgs(); + return MyAdvertiseDataArgs( + nameArgs: nameArgs, + serviceUUIDsArgs: serviceUUIDsArgs, + serviceDataArgs: serviceDataArgs, + manufacturerSpecificDataArgs: manufacturerSpecificDataArgs, + ); + } +} + +extension ManufacturerSpecificDataX on ManufacturerSpecificData { + MyManufacturerSpecificDataArgs toArgs() { + final idArgs = id; + final dataArgs = data; + return MyManufacturerSpecificDataArgs( + idArgs: idArgs, + dataArgs: dataArgs, + ); + } +} + +extension MyGattServiceX on MyGattService { + MyGattServiceArgs toArgs() { + final hashCodeArgs = hashCode; + final uuidArgs = uuid.toString(); + final characteristicsArgs = characteristics + .cast() + .map((characteristic) => characteristic.toArgs()) + .toList(); + return MyGattServiceArgs( + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + characteristicsArgs: characteristicsArgs, + ); + } +} + +extension MyGattCharacteristicX on MyGattCharacteristic { + MyGattCharacteristicArgs toArgs() { + final hashCodeArgs = hashCode; + final uuidArgs = uuid.toString(); + final propertyNumbersArgs = properties.map((property) { + final propertyArgs = property.toArgs(); + return propertyArgs.index; + }).toList(); + final descriptorsArgs = descriptors + .cast() + .map((descriptor) => descriptor.toArgs()) + .toList(); + return MyGattCharacteristicArgs( + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + propertyNumbersArgs: propertyNumbersArgs, + descriptorsArgs: descriptorsArgs, + ); + } +} + +extension MyGattDescriptorX on MyGattDescriptor { + MyGattDescriptorArgs toArgs() { + final hashCodeArgs = hashCode; + final uuidArgs = uuid.toString(); + final valueArgs = value; + return MyGattDescriptorArgs( + hashCodeArgs: hashCodeArgs, + uuidArgs: uuidArgs, + valueArgs: valueArgs, + ); + } +} + +extension GattCharacteristicPropertyX on GattCharacteristicProperty { + MyGattCharacteristicPropertyArgs toArgs() { + return MyGattCharacteristicPropertyArgs.values[index]; + } +} diff --git a/bluetooth_low_energy_darwin/lib/src/my_api.g.dart b/bluetooth_low_energy_darwin/lib/src/my_api.g.dart index 380f6da..c5fd859 100644 --- a/bluetooth_low_energy_darwin/lib/src/my_api.g.dart +++ b/bluetooth_low_energy_darwin/lib/src/my_api.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v10.1.6), do not edit directly. +// Autogenerated from Pigeon (v11.0.1), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import @@ -8,7 +8,7 @@ import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; -enum MyCentralStateArgs { +enum MyBluetoothLowEnergyStateArgs { unknown, unsupported, unauthorized, @@ -29,177 +29,267 @@ enum MyGattCharacteristicWriteTypeArgs { withoutResponse, } -class MyCentralControllerArgs { - MyCentralControllerArgs({ - required this.myStateNumber, +class MyCentralManagerArgs { + MyCentralManagerArgs({ + required this.stateNumberArgs, }); - int myStateNumber; + int stateNumberArgs; Object encode() { return [ - myStateNumber, + stateNumberArgs, ]; } - static MyCentralControllerArgs decode(Object result) { + static MyCentralManagerArgs decode(Object result) { result as List; - return MyCentralControllerArgs( - myStateNumber: result[0]! as int, + return MyCentralManagerArgs( + stateNumberArgs: result[0]! as int, + ); + } +} + +class MyPeripheralManagerArgs { + MyPeripheralManagerArgs({ + required this.stateNumberArgs, + }); + + int stateNumberArgs; + + Object encode() { + return [ + stateNumberArgs, + ]; + } + + static MyPeripheralManagerArgs decode(Object result) { + result as List; + return MyPeripheralManagerArgs( + stateNumberArgs: result[0]! as int, + ); + } +} + +class MyCentralArgs { + MyCentralArgs({ + required this.hashCodeArgs, + required this.uuidArgs, + }); + + int hashCodeArgs; + + String uuidArgs; + + Object encode() { + return [ + hashCodeArgs, + uuidArgs, + ]; + } + + static MyCentralArgs decode(Object result) { + result as List; + return MyCentralArgs( + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, ); } } class MyPeripheralArgs { MyPeripheralArgs({ - required this.key, - required this.uuid, + required this.hashCodeArgs, + required this.uuidArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; Object encode() { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, ]; } static MyPeripheralArgs decode(Object result) { result as List; return MyPeripheralArgs( - key: result[0]! as int, - uuid: result[1]! as String, + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, ); } } -class MyAdvertisementArgs { - MyAdvertisementArgs({ - this.name, - required this.manufacturerSpecificData, - required this.serviceUUIDs, - required this.serviceData, +class MyAdvertiseDataArgs { + MyAdvertiseDataArgs({ + this.nameArgs, + required this.serviceUUIDsArgs, + required this.serviceDataArgs, + this.manufacturerSpecificDataArgs, }); - String? name; + String? nameArgs; - Map manufacturerSpecificData; + List serviceUUIDsArgs; - List serviceUUIDs; + Map serviceDataArgs; - Map serviceData; + MyManufacturerSpecificDataArgs? manufacturerSpecificDataArgs; Object encode() { return [ - name, - manufacturerSpecificData, - serviceUUIDs, - serviceData, + nameArgs, + serviceUUIDsArgs, + serviceDataArgs, + manufacturerSpecificDataArgs?.encode(), ]; } - static MyAdvertisementArgs decode(Object result) { + static MyAdvertiseDataArgs decode(Object result) { result as List; - return MyAdvertisementArgs( - name: result[0] as String?, - manufacturerSpecificData: (result[1] as Map?)!.cast(), - serviceUUIDs: (result[2] as List?)!.cast(), - serviceData: (result[3] as Map?)!.cast(), + return MyAdvertiseDataArgs( + nameArgs: result[0] as String?, + serviceUUIDsArgs: (result[1] as List?)!.cast(), + serviceDataArgs: (result[2] as Map?)!.cast(), + manufacturerSpecificDataArgs: result[3] != null + ? MyManufacturerSpecificDataArgs.decode(result[3]! as List) + : null, + ); + } +} + +class MyManufacturerSpecificDataArgs { + MyManufacturerSpecificDataArgs({ + required this.idArgs, + required this.dataArgs, + }); + + int idArgs; + + Uint8List dataArgs; + + Object encode() { + return [ + idArgs, + dataArgs, + ]; + } + + static MyManufacturerSpecificDataArgs decode(Object result) { + result as List; + return MyManufacturerSpecificDataArgs( + idArgs: result[0]! as int, + dataArgs: result[1]! as Uint8List, ); } } class MyGattServiceArgs { MyGattServiceArgs({ - required this.key, - required this.uuid, + required this.hashCodeArgs, + required this.uuidArgs, + required this.characteristicsArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; + + List characteristicsArgs; Object encode() { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, + characteristicsArgs, ]; } static MyGattServiceArgs decode(Object result) { result as List; return MyGattServiceArgs( - key: result[0]! as int, - uuid: result[1]! as String, + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, + characteristicsArgs: (result[2] as List?)!.cast(), ); } } class MyGattCharacteristicArgs { MyGattCharacteristicArgs({ - required this.key, - required this.uuid, - required this.myPropertyNumbers, + required this.hashCodeArgs, + required this.uuidArgs, + required this.propertyNumbersArgs, + required this.descriptorsArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; - List myPropertyNumbers; + List propertyNumbersArgs; + + List descriptorsArgs; Object encode() { return [ - key, - uuid, - myPropertyNumbers, + hashCodeArgs, + uuidArgs, + propertyNumbersArgs, + descriptorsArgs, ]; } static MyGattCharacteristicArgs decode(Object result) { result as List; return MyGattCharacteristicArgs( - key: result[0]! as int, - uuid: result[1]! as String, - myPropertyNumbers: (result[2] as List?)!.cast(), + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, + propertyNumbersArgs: (result[2] as List?)!.cast(), + descriptorsArgs: (result[3] as List?)!.cast(), ); } } class MyGattDescriptorArgs { MyGattDescriptorArgs({ - required this.key, - required this.uuid, + required this.hashCodeArgs, + required this.uuidArgs, + this.valueArgs, }); - int key; + int hashCodeArgs; - String uuid; + String uuidArgs; + + Uint8List? valueArgs; Object encode() { return [ - key, - uuid, + hashCodeArgs, + uuidArgs, + valueArgs, ]; } static MyGattDescriptorArgs decode(Object result) { result as List; return MyGattDescriptorArgs( - key: result[0]! as int, - uuid: result[1]! as String, + hashCodeArgs: result[0]! as int, + uuidArgs: result[1]! as String, + valueArgs: result[2] as Uint8List?, ); } } -class _MyCentralControllerHostApiCodec extends StandardMessageCodec { - const _MyCentralControllerHostApiCodec(); +class _MyCentralManagerHostApiCodec extends StandardMessageCodec { + const _MyCentralManagerHostApiCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is MyCentralControllerArgs) { + if (value is MyCentralManagerArgs) { buffer.putUint8(128); writeValue(buffer, value.encode()); } else if (value is MyGattCharacteristicArgs) { @@ -220,7 +310,7 @@ class _MyCentralControllerHostApiCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 128: - return MyCentralControllerArgs.decode(readValue(buffer)!); + return MyCentralManagerArgs.decode(readValue(buffer)!); case 129: return MyGattCharacteristicArgs.decode(readValue(buffer)!); case 130: @@ -233,19 +323,19 @@ class _MyCentralControllerHostApiCodec extends StandardMessageCodec { } } -class MyCentralControllerHostApi { - /// Constructor for [MyCentralControllerHostApi]. The [binaryMessenger] named argument is +class MyCentralManagerHostApi { + /// Constructor for [MyCentralManagerHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - MyCentralControllerHostApi({BinaryMessenger? binaryMessenger}) + MyCentralManagerHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; - static const MessageCodec codec = _MyCentralControllerHostApiCodec(); + static const MessageCodec codec = _MyCentralManagerHostApiCodec(); - Future setUp() async { + Future setUp() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.setUp', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.setUp', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -266,35 +356,13 @@ class MyCentralControllerHostApi { message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as MyCentralControllerArgs?)!; - } - } - - Future tearDown() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.tearDown', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return; + return (replyList[0] as MyCentralManagerArgs?)!; } } Future startDiscovery() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.startDiscovery', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.startDiscovery', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -316,7 +384,7 @@ class MyCentralControllerHostApi { Future stopDiscovery() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.stopDiscovery', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.stopDiscovery', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send(null) as List?; @@ -336,12 +404,12 @@ class MyCentralControllerHostApi { } } - Future connect(int arg_myPeripheralKey) async { + Future connect(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.connect', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.connect', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -358,12 +426,12 @@ class MyCentralControllerHostApi { } } - Future disconnect(int arg_myPeripheralKey) async { + Future disconnect(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.disconnect', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.disconnect', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -380,12 +448,12 @@ class MyCentralControllerHostApi { } } - Future getMaximumWriteLength(int arg_myPeripheralKey, int arg_myTypeNumber) async { + Future getMaximumWriteLength(int arg_peripheralHashCodeArgs, int arg_typeNumberArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getMaximumWriteLength', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.getMaximumWriteLength', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myTypeNumber]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_typeNumberArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -407,12 +475,12 @@ class MyCentralControllerHostApi { } } - Future discoverGATT(int arg_myPeripheralKey) async { + Future readRSSI(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.discoverGATT', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.readRSSI', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -424,17 +492,22 @@ class MyCentralControllerHostApi { message: replyList[1] as String?, details: replyList[2], ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); } else { - return; + return (replyList[0] as int?)!; } } - Future> getServices(int arg_myPeripheralKey) async { + Future> discoverGATT(int arg_peripheralHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getServices', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.discoverGATT', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -456,66 +529,12 @@ class MyCentralControllerHostApi { } } - Future> getCharacteristics(int arg_myServiceKey) async { + Future readCharacteristic(int arg_peripheralHashCodeArgs, int arg_characteristicHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getCharacteristics', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.readCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myServiceKey]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as List?)!.cast(); - } - } - - Future> getDescriptors(int arg_myCharacteristicKey) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.getDescriptors', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_myCharacteristicKey]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (replyList[0] as List?)!.cast(); - } - } - - Future readCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.readCharacteristic', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_characteristicHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -537,12 +556,12 @@ class MyCentralControllerHostApi { } } - Future writeCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async { + Future writeCharacteristic(int arg_peripheralHashCodeArgs, int arg_characteristicHashCodeArgs, Uint8List arg_valueArgs, int arg_typeNumberArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.writeCharacteristic', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.writeCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_characteristicHashCodeArgs, arg_valueArgs, arg_typeNumberArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -559,12 +578,12 @@ class MyCentralControllerHostApi { } } - Future notifyCharacteristic(int arg_myPeripheralKey, int arg_myServiceKey, int arg_myCharacteristicKey, bool arg_state) async { + Future notifyCharacteristic(int arg_peripheralHashCodeArgs, int arg_characteristicHashCodeArgs, bool arg_stateArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.notifyCharacteristic', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.notifyCharacteristic', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myServiceKey, arg_myCharacteristicKey, arg_state]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_characteristicHashCodeArgs, arg_stateArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -581,12 +600,12 @@ class MyCentralControllerHostApi { } } - Future readDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey) async { + Future readDescriptor(int arg_peripheralHashCodeArgs, int arg_descriptorHashCodeArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.readDescriptor', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.readDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_descriptorHashCodeArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -608,12 +627,12 @@ class MyCentralControllerHostApi { } } - Future writeDescriptor(int arg_myPeripheralKey, int arg_myCharacteristicKey, int arg_myDescriptorKey, Uint8List arg_value) async { + Future writeDescriptor(int arg_peripheralHashCodeArgs, int arg_descriptorHashCodeArgs, Uint8List arg_valueArgs) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerHostApi.writeDescriptor', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerHostApi.writeDescriptor', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_myPeripheralKey, arg_myCharacteristicKey, arg_myDescriptorKey, arg_value]) as List?; + await channel.send([arg_peripheralHashCodeArgs, arg_descriptorHashCodeArgs, arg_valueArgs]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -631,16 +650,25 @@ class MyCentralControllerHostApi { } } -class _MyCentralControllerFlutterApiCodec extends StandardMessageCodec { - const _MyCentralControllerFlutterApiCodec(); +class _MyCentralManagerFlutterApiCodec extends StandardMessageCodec { + const _MyCentralManagerFlutterApiCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is MyAdvertisementArgs) { + if (value is MyAdvertiseDataArgs) { buffer.putUint8(128); writeValue(buffer, value.encode()); - } else if (value is MyPeripheralArgs) { + } else if (value is MyGattCharacteristicArgs) { buffer.putUint8(129); writeValue(buffer, value.encode()); + } else if (value is MyGattDescriptorArgs) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is MyManufacturerSpecificDataArgs) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is MyPeripheralArgs) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -650,8 +678,14 @@ class _MyCentralControllerFlutterApiCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 128: - return MyAdvertisementArgs.decode(readValue(buffer)!); + return MyAdvertiseDataArgs.decode(readValue(buffer)!); case 129: + return MyGattCharacteristicArgs.decode(readValue(buffer)!); + case 130: + return MyGattDescriptorArgs.decode(readValue(buffer)!); + case 131: + return MyManufacturerSpecificDataArgs.decode(readValue(buffer)!); + case 132: return MyPeripheralArgs.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -659,102 +693,542 @@ class _MyCentralControllerFlutterApiCodec extends StandardMessageCodec { } } -abstract class MyCentralControllerFlutterApi { - static const MessageCodec codec = _MyCentralControllerFlutterApiCodec(); +abstract class MyCentralManagerFlutterApi { + static const MessageCodec codec = _MyCentralManagerFlutterApiCodec(); - void onStateChanged(int myStateNumber); + void onStateChanged(int stateNumberArgs); - void onDiscovered(MyPeripheralArgs myPeripheralArgs, int rssi, MyAdvertisementArgs myAdvertisementArgs); + void onDiscovered(MyPeripheralArgs peripheralArgs, int rssiArgs, MyAdvertiseDataArgs advertiseDataArgs); - void onPeripheralStateChanged(int myPeripheralKey, bool state); + void onPeripheralStateChanged(MyPeripheralArgs peripheralArgs, bool stateArgs); - void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value); + void onCharacteristicValueChanged(MyGattCharacteristicArgs characteristicArgs, Uint8List valueArgs); - static void setup(MyCentralControllerFlutterApi? api, {BinaryMessenger? binaryMessenger}) { + static void setup(MyCentralManagerFlutterApi? api, {BinaryMessenger? binaryMessenger}) { { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onStateChanged', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onStateChanged', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onStateChanged was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onStateChanged was null.'); final List args = (message as List?)!; - final int? arg_myStateNumber = (args[0] as int?); - assert(arg_myStateNumber != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onStateChanged was null, expected non-null int.'); - api.onStateChanged(arg_myStateNumber!); + final int? arg_stateNumberArgs = (args[0] as int?); + assert(arg_stateNumberArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onStateChanged was null, expected non-null int.'); + api.onStateChanged(arg_stateNumberArgs!); return; }); } } { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onDiscovered', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onDiscovered', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onDiscovered was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onDiscovered was null.'); final List args = (message as List?)!; - final MyPeripheralArgs? arg_myPeripheralArgs = (args[0] as MyPeripheralArgs?); - assert(arg_myPeripheralArgs != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null MyPeripheralArgs.'); - final int? arg_rssi = (args[1] as int?); - assert(arg_rssi != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null int.'); - final MyAdvertisementArgs? arg_myAdvertisementArgs = (args[2] as MyAdvertisementArgs?); - assert(arg_myAdvertisementArgs != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null MyAdvertisementArgs.'); - api.onDiscovered(arg_myPeripheralArgs!, arg_rssi!, arg_myAdvertisementArgs!); + final MyPeripheralArgs? arg_peripheralArgs = (args[0] as MyPeripheralArgs?); + assert(arg_peripheralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onDiscovered was null, expected non-null MyPeripheralArgs.'); + final int? arg_rssiArgs = (args[1] as int?); + assert(arg_rssiArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onDiscovered was null, expected non-null int.'); + final MyAdvertiseDataArgs? arg_advertiseDataArgs = (args[2] as MyAdvertiseDataArgs?); + assert(arg_advertiseDataArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onDiscovered was null, expected non-null MyAdvertiseDataArgs.'); + api.onDiscovered(arg_peripheralArgs!, arg_rssiArgs!, arg_advertiseDataArgs!); return; }); } } { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onPeripheralStateChanged', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onPeripheralStateChanged', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onPeripheralStateChanged was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onPeripheralStateChanged was null.'); final List args = (message as List?)!; - final int? arg_myPeripheralKey = (args[0] as int?); - assert(arg_myPeripheralKey != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onPeripheralStateChanged was null, expected non-null int.'); - final bool? arg_state = (args[1] as bool?); - assert(arg_state != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onPeripheralStateChanged was null, expected non-null bool.'); - api.onPeripheralStateChanged(arg_myPeripheralKey!, arg_state!); + final MyPeripheralArgs? arg_peripheralArgs = (args[0] as MyPeripheralArgs?); + assert(arg_peripheralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onPeripheralStateChanged was null, expected non-null MyPeripheralArgs.'); + final bool? arg_stateArgs = (args[1] as bool?); + assert(arg_stateArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onPeripheralStateChanged was null, expected non-null bool.'); + api.onPeripheralStateChanged(arg_peripheralArgs!, arg_stateArgs!); return; }); } } { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onCharacteristicValueChanged', codec, + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onCharacteristicValueChanged', codec, binaryMessenger: binaryMessenger); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null.'); + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onCharacteristicValueChanged was null.'); final List args = (message as List?)!; - final int? arg_myCharacteristicKey = (args[0] as int?); - assert(arg_myCharacteristicKey != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null, expected non-null int.'); - final Uint8List? arg_value = (args[1] as Uint8List?); - assert(arg_value != null, - 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null, expected non-null Uint8List.'); - api.onCharacteristicValueChanged(arg_myCharacteristicKey!, arg_value!); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[0] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onCharacteristicValueChanged was null, expected non-null MyGattCharacteristicArgs.'); + final Uint8List? arg_valueArgs = (args[1] as Uint8List?); + assert(arg_valueArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyCentralManagerFlutterApi.onCharacteristicValueChanged was null, expected non-null Uint8List.'); + api.onCharacteristicValueChanged(arg_characteristicArgs!, arg_valueArgs!); + return; + }); + } + } + } +} + +class _MyPeripheralManagerHostApiCodec extends StandardMessageCodec { + const _MyPeripheralManagerHostApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is MyAdvertiseDataArgs) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is MyGattCharacteristicArgs) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is MyGattDescriptorArgs) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is MyGattServiceArgs) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is MyManufacturerSpecificDataArgs) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else if (value is MyPeripheralManagerArgs) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return MyAdvertiseDataArgs.decode(readValue(buffer)!); + case 129: + return MyGattCharacteristicArgs.decode(readValue(buffer)!); + case 130: + return MyGattDescriptorArgs.decode(readValue(buffer)!); + case 131: + return MyGattServiceArgs.decode(readValue(buffer)!); + case 132: + return MyManufacturerSpecificDataArgs.decode(readValue(buffer)!); + case 133: + return MyPeripheralManagerArgs.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class MyPeripheralManagerHostApi { + /// Constructor for [MyPeripheralManagerHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MyPeripheralManagerHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _MyPeripheralManagerHostApiCodec(); + + Future setUp() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.setUp', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as MyPeripheralManagerArgs?)!; + } + } + + Future addService(MyGattServiceArgs arg_serviceArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.addService', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_serviceArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future removeService(int arg_serviceHashCodeArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.removeService', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_serviceHashCodeArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future clearServices() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.clearServices', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future startAdvertising(MyAdvertiseDataArgs arg_advertiseDataArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.startAdvertising', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_advertiseDataArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future stopAdvertising() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.stopAdvertising', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future getMaximumWriteLength(int arg_centralHashCodeArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.getMaximumWriteLength', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as int?)!; + } + } + + Future sendReadCharacteristicReply(int arg_centralHashCodeArgs, int arg_characteristicHashCodeArgs, int arg_idArgs, int arg_offsetArgs, bool arg_statusArgs, Uint8List arg_valueArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.sendReadCharacteristicReply', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs, arg_characteristicHashCodeArgs, arg_idArgs, arg_offsetArgs, arg_statusArgs, arg_valueArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future sendWriteCharacteristicReply(int arg_centralHashCodeArgs, int arg_characteristicHashCodeArgs, int arg_idArgs, int arg_offsetArgs, bool arg_statusArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.sendWriteCharacteristicReply', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs, arg_characteristicHashCodeArgs, arg_idArgs, arg_offsetArgs, arg_statusArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future notifyCharacteristicValueChanged(int arg_centralHashCodeArgs, int arg_characteristicHashCodeArgs, Uint8List arg_valueArgs) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerHostApi.notifyCharacteristicValueChanged', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_centralHashCodeArgs, arg_characteristicHashCodeArgs, arg_valueArgs]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } +} + +class _MyPeripheralManagerFlutterApiCodec extends StandardMessageCodec { + const _MyPeripheralManagerFlutterApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is MyCentralArgs) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is MyGattCharacteristicArgs) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is MyGattDescriptorArgs) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return MyCentralArgs.decode(readValue(buffer)!); + case 129: + return MyGattCharacteristicArgs.decode(readValue(buffer)!); + case 130: + return MyGattDescriptorArgs.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class MyPeripheralManagerFlutterApi { + static const MessageCodec codec = _MyPeripheralManagerFlutterApiCodec(); + + void onStateChanged(int stateNumberArgs); + + void onReadCharacteristicCommandReceived(MyCentralArgs centralArgs, MyGattCharacteristicArgs characteristicArgs, int idArgs, int offsetArgs); + + void onWriteCharacteristicCommandReceived(MyCentralArgs centralArgs, MyGattCharacteristicArgs characteristicArgs, int idArgs, int offsetArgs, Uint8List valueArgs); + + void onNotifyCharacteristicCommandReceived(MyCentralArgs centralArgs, MyGattCharacteristicArgs characteristicArgs, bool stateArgs); + + static void setup(MyPeripheralManagerFlutterApi? api, {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onStateChanged', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onStateChanged was null.'); + final List args = (message as List?)!; + final int? arg_stateNumberArgs = (args[0] as int?); + assert(arg_stateNumberArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onStateChanged was null, expected non-null int.'); + api.onStateChanged(arg_stateNumberArgs!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null.'); + final List args = (message as List?)!; + final MyCentralArgs? arg_centralArgs = (args[0] as MyCentralArgs?); + assert(arg_centralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null MyCentralArgs.'); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[1] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null MyGattCharacteristicArgs.'); + final int? arg_idArgs = (args[2] as int?); + assert(arg_idArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null int.'); + final int? arg_offsetArgs = (args[3] as int?); + assert(arg_offsetArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived was null, expected non-null int.'); + api.onReadCharacteristicCommandReceived(arg_centralArgs!, arg_characteristicArgs!, arg_idArgs!, arg_offsetArgs!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null.'); + final List args = (message as List?)!; + final MyCentralArgs? arg_centralArgs = (args[0] as MyCentralArgs?); + assert(arg_centralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null MyCentralArgs.'); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[1] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null MyGattCharacteristicArgs.'); + final int? arg_idArgs = (args[2] as int?); + assert(arg_idArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null int.'); + final int? arg_offsetArgs = (args[3] as int?); + assert(arg_offsetArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null int.'); + final Uint8List? arg_valueArgs = (args[4] as Uint8List?); + assert(arg_valueArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived was null, expected non-null Uint8List.'); + api.onWriteCharacteristicCommandReceived(arg_centralArgs!, arg_characteristicArgs!, arg_idArgs!, arg_offsetArgs!, arg_valueArgs!); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null.'); + final List args = (message as List?)!; + final MyCentralArgs? arg_centralArgs = (args[0] as MyCentralArgs?); + assert(arg_centralArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null, expected non-null MyCentralArgs.'); + final MyGattCharacteristicArgs? arg_characteristicArgs = (args[1] as MyGattCharacteristicArgs?); + assert(arg_characteristicArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null, expected non-null MyGattCharacteristicArgs.'); + final bool? arg_stateArgs = (args[2] as bool?); + assert(arg_stateArgs != null, + 'Argument for dev.flutter.pigeon.bluetooth_low_energy_darwin.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived was null, expected non-null bool.'); + api.onNotifyCharacteristicCommandReceived(arg_centralArgs!, arg_characteristicArgs!, arg_stateArgs!); return; }); } diff --git a/bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy.dart b/bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy.dart new file mode 100644 index 0000000..752d659 --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy.dart @@ -0,0 +1,15 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_central_manager.dart'; +import 'my_peripheral_manager.dart'; + +class MyBluetoothLowEnergy extends BluetoothLowEnergy { + @override + final MyCentralManager centralManager; + @override + final MyPeripheralManager peripheralManager; + + MyBluetoothLowEnergy() + : centralManager = MyCentralManager(), + peripheralManager = MyPeripheralManager(); +} diff --git a/bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy_manager.dart b/bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy_manager.dart new file mode 100644 index 0000000..8082f8b --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_bluetooth_low_energy_manager.dart @@ -0,0 +1,39 @@ +import 'dart:async'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; +import 'package:flutter/foundation.dart'; + +abstract class MyBluetoothLowEnergyManager extends BluetoothLowEnergyManager { + MyBluetoothLowEnergyManager() + : _state = BluetoothLowEnergyState.unknown, + _stateChangedController = StreamController.broadcast(); + + final StreamController + _stateChangedController; + + BluetoothLowEnergyState _state; + @override + BluetoothLowEnergyState get state => _state; + @protected + set state(BluetoothLowEnergyState value) { + if (_state == value) { + return; + } + _state = value; + final eventArgs = BluetoothLowEnergyStateChangedEventArgs(state); + _stateChangedController.add(eventArgs); + } + + @override + Stream get stateChanged => + _stateChangedController.stream; + + @protected + Future throwWithoutState(BluetoothLowEnergyState state) async { + if (this.state != state) { + throw BluetoothLowEnergyError( + '$state is expected, but current state is ${this.state}.', + ); + } + } +} diff --git a/bluetooth_low_energy_darwin/lib/src/my_central_controller.dart b/bluetooth_low_energy_darwin/lib/src/my_central_controller.dart deleted file mode 100644 index 48d8d6c..0000000 --- a/bluetooth_low_energy_darwin/lib/src/my_central_controller.dart +++ /dev/null @@ -1,370 +0,0 @@ -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_gatt_characteristic.dart'; -import 'my_gatt_descriptor.dart'; -import 'my_gatt_service.dart'; -import 'my_peripheral.dart'; - -class MyCentralController extends CentralController - implements MyCentralControllerFlutterApi { - MyCentralController() - : _myApi = MyCentralControllerHostApi(), - _stateChangedController = StreamController.broadcast(), - _discoveredController = StreamController.broadcast(), - _peripheralStateChangedController = StreamController.broadcast(), - _characteristicValueChangedController = StreamController.broadcast(), - _myPeripherals = {}, - _myServices = {}, - _myCharacteristics = {}, - _myDescriptors = {}, - _state = CentralState.unknown; - - final MyCentralControllerHostApi _myApi; - final StreamController _stateChangedController; - final StreamController _discoveredController; - final StreamController - _peripheralStateChangedController; - final StreamController - _characteristicValueChangedController; - final Map _myPeripherals; - final Map _myServices; - final Map _myCharacteristics; - final Map _myDescriptors; - - CentralState _state; - @override - CentralState get state => _state; - - @override - Stream get stateChanged => - _stateChangedController.stream; - @override - Stream get discovered => - _discoveredController.stream; - @override - Stream get peripheralStateChanged => - _peripheralStateChangedController.stream; - @override - Stream - get characteristicValueChanged => - _characteristicValueChangedController.stream; - - Future _throwWithState(CentralState state) async { - if (this.state == state) { - throw BluetoothLowEnergyError('$state is unexpected.'); - } - } - - Future _throwWithoutState(CentralState state) async { - if (this.state != state) { - throw BluetoothLowEnergyError( - '$state is expected, but current state is ${this.state}.', - ); - } - } - - @override - Future setUp() async { - await _throwWithoutState(CentralState.unknown); - final args = await _myApi.setUp(); - final myStateArgs = MyCentralStateArgs.values[args.myStateNumber]; - _state = myStateArgs.toState(); - MyCentralControllerFlutterApi.setup(this); - } - - @override - Future tearDown() async { - await _throwWithState(CentralState.unknown); - await _myApi.tearDown(); - MyCentralControllerFlutterApi.setup(null); - _myPeripherals.clear(); - _myServices.clear(); - _myCharacteristics.clear(); - _myDescriptors.clear(); - _state = CentralState.unknown; - } - - @override - Future startDiscovery() async { - await _throwWithoutState(CentralState.poweredOn); - await _myApi.startDiscovery(); - } - - @override - Future stopDiscovery() async { - await _throwWithoutState(CentralState.poweredOn); - await _myApi.stopDiscovery(); - } - - @override - Future connect(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - await _myApi.connect(myPeripheral.hashCode); - } - - @override - Future disconnect(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - await _myApi.disconnect(myPeripheral.hashCode); - } - - @override - Future getMaximumWriteLength( - Peripheral peripheral, { - required GattCharacteristicWriteType type, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - final myTypeArgs = type.toMyArgs(); - final myTypeNumber = myTypeArgs.index; - final maximumWriteLength = await _myApi.getMaximumWriteLength( - myPeripheral.hashCode, - myTypeNumber, - ); - return maximumWriteLength; - } - - @override - Future discoverGATT(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - await _myApi.discoverGATT(myPeripheral.hashCode); - } - - @override - Future> getServices(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode); - return myServiceArgses.cast().map( - (myServiceArgs) { - final myService = MyGattService.fromMyArgs( - myPeripheral, - myServiceArgs, - ); - _myServices[myService.hashCode] = myService; - return myService; - }, - ).toList(); - } - - @override - Future> getCharacteristics( - GattService service, - ) async { - await _throwWithoutState(CentralState.poweredOn); - final myService = service as MyGattService; - final myCharactersiticArgses = await _myApi.getCharacteristics( - myService.hashCode, - ); - return myCharactersiticArgses.cast().map( - (myCharacteristicArgs) { - final myCharacteristic = MyGattCharacteristic.fromMyArgs( - myService, - myCharacteristicArgs, - ); - _myCharacteristics[myCharacteristic.hashCode] = myCharacteristic; - return myCharacteristic; - }, - ).toList(); - } - - @override - Future> getDescriptors( - GattCharacteristic characteristic, - ) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myDescriptorArgses = await _myApi.getDescriptors( - myCharacteristic.hashCode, - ); - return myDescriptorArgses.cast().map( - (myDescriptorArgs) { - final myDescriptor = MyGattDescriptor.fromMyArgs( - myCharacteristic, - myDescriptorArgs, - ); - _myDescriptors[myDescriptor.hashCode] = myDescriptor; - return myDescriptor; - }, - ).toList(); - } - - @override - Future readCharacteristic( - GattCharacteristic characteristic, - ) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - final value = await _myApi.readCharacteristic( - myPeripheral.hashCode, - myService.hashCode, - myCharacteristic.hashCode, - ); - return value; - } - - @override - Future writeCharacteristic( - GattCharacteristic characteristic, { - required Uint8List value, - required GattCharacteristicWriteType type, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - final myTypeArgs = type.toMyArgs(); - final myTypeNumber = myTypeArgs.index; - await _myApi.writeCharacteristic( - myPeripheral.hashCode, - myService.hashCode, - myCharacteristic.hashCode, - value, - myTypeNumber, - ); - } - - @override - Future notifyCharacteristic( - GattCharacteristic characteristic, { - required bool state, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myCharacteristic = characteristic as MyGattCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - await _myApi.notifyCharacteristic( - myPeripheral.hashCode, - myService.hashCode, - myCharacteristic.hashCode, - state, - ); - } - - @override - Future readDescriptor(GattDescriptor descriptor) async { - await _throwWithoutState(CentralState.poweredOn); - final myDescriptor = descriptor as MyGattDescriptor; - final myCharacteristic = myDescriptor.myCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - final value = await _myApi.readDescriptor( - myPeripheral.hashCode, - myCharacteristic.hashCode, - myDescriptor.hashCode, - ); - return value; - } - - @override - Future writeDescriptor( - GattDescriptor descriptor, { - required Uint8List value, - }) async { - await _throwWithoutState(CentralState.poweredOn); - final myDescriptor = descriptor as MyGattDescriptor; - final myCharacteristic = myDescriptor.myCharacteristic; - final myService = myCharacteristic.myService; - final myPeripheral = myService.myPeripheral; - await _myApi.writeDescriptor( - myPeripheral.hashCode, - myCharacteristic.hashCode, - myDescriptor.hashCode, - value, - ); - } - - @override - void onStateChanged(int myStateNumber) { - final myStateArgs = MyCentralStateArgs.values[myStateNumber]; - final state = myStateArgs.toState(); - if (_state == state) { - return; - } - _state = state; - final eventArgs = CentralStateChangedEventArgs(state); - _stateChangedController.add(eventArgs); - } - - @override - void onDiscovered( - MyPeripheralArgs myPeripheralArgs, - int rssi, - MyAdvertisementArgs myAdvertisementArgs, - ) { - final myPeripheral = MyPeripheral.fromMyArgs(myPeripheralArgs); - _myPeripherals[myPeripheral.hashCode] = myPeripheral; - final advertisement = myAdvertisementArgs.toAdvertisement(); - final eventArgs = CentralDiscoveredEventArgs( - myPeripheral, - rssi, - advertisement, - ); - _discoveredController.add(eventArgs); - } - - @override - void onPeripheralStateChanged(int myPeripheralKey, bool state) { - final myPeripheral = _myPeripherals[myPeripheralKey]; - if (myPeripheral == null) { - return; - } - final eventArgs = PeripheralStateChangedEventArgs(myPeripheral, state); - _peripheralStateChangedController.add(eventArgs); - } - - @override - void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value) { - final myCharacteristic = - _myCharacteristics[myCharacteristicKey] as MyGattCharacteristic; - final eventArgs = GattCharacteristicValueChangedEventArgs( - myCharacteristic, - value, - ); - _characteristicValueChangedController.add(eventArgs); - } -} - -extension on MyAdvertisementArgs { - Advertisement toAdvertisement() { - final serviceUUIDs = this - .serviceUUIDs - .cast() - .map((uuid) => UUID.fromString(uuid)) - .toList(); - final serviceData = this.serviceData.cast().map( - (uuid, data) { - final key = UUID.fromString(uuid); - final value = data; - return MapEntry(key, value); - }, - ); - return Advertisement( - name: name, - manufacturerSpecificData: manufacturerSpecificData.cast(), - serviceUUIDs: serviceUUIDs, - serviceData: serviceData, - ); - } -} - -extension on MyCentralStateArgs { - CentralState toState() { - return CentralState.values[index]; - } -} - -extension on GattCharacteristicWriteType { - MyGattCharacteristicWriteTypeArgs toMyArgs() { - return MyGattCharacteristicWriteTypeArgs.values[index]; - } -} diff --git a/bluetooth_low_energy_darwin/lib/src/my_central_manager.dart b/bluetooth_low_energy_darwin/lib/src/my_central_manager.dart new file mode 100644 index 0000000..56ebd60 --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_central_manager.dart @@ -0,0 +1,272 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_api.dart'; +import 'my_bluetooth_low_energy_manager.dart'; +import 'my_gatt_characteristic2.dart'; +import 'my_gatt_descriptor2.dart'; + +class MyCentralManager extends MyBluetoothLowEnergyManager + implements CentralManager, MyCentralManagerFlutterApi { + MyCentralManager() + : _api = MyCentralManagerHostApi(), + _discoveredController = StreamController.broadcast(), + _peripheralStateChangedController = StreamController.broadcast(), + _characteristicValueChangedController = StreamController.broadcast(); + + final MyCentralManagerHostApi _api; + final StreamController _discoveredController; + final StreamController + _peripheralStateChangedController; + final StreamController + _characteristicValueChangedController; + + @override + Stream get discovered => _discoveredController.stream; + @override + Stream get peripheralStateChanged => + _peripheralStateChangedController.stream; + @override + Stream + get characteristicValueChanged => + _characteristicValueChangedController.stream; + + @override + Future setUp() async { + await throwWithoutState(BluetoothLowEnergyState.unknown); + final args = await _api.setUp(); + final stateArgs = + MyBluetoothLowEnergyStateArgs.values[args.stateNumberArgs]; + state = stateArgs.toState(); + MyCentralManagerFlutterApi.setup(this); + } + + @override + Future startDiscovery() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.startDiscovery(); + } + + @override + Future stopDiscovery() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.stopDiscovery(); + } + + @override + Future connect(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + await _api.connect(peripheralHashCodeArgs); + } + + @override + Future disconnect(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + await _api.disconnect(peripheralHashCodeArgs); + } + + @override + Future getMaximumWriteLength( + Peripheral peripheral, { + required GattCharacteristicWriteType type, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + final typeArgs = type.toArgs(); + final typeNumberArgs = typeArgs.index; + final maximumWriteLength = await _api.getMaximumWriteLength( + peripheralHashCodeArgs, + typeNumberArgs, + ); + return maximumWriteLength; + } + + @override + Future readRSSI(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final peripheralHashCodeArgs = peripheral.hashCode; + final rssi = await _api.readRSSI(peripheralHashCodeArgs); + return rssi; + } + + @override + Future> discoverGATT(Peripheral peripheral) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (peripheral is! MyPeripheral) { + throw TypeError(); + } + final peripheralHashCodeArgs = peripheral.hashCode; + final servicesArgs = await _api.discoverGATT(peripheralHashCodeArgs); + final services = servicesArgs + .cast() + .map((args) => args.toService2()) + .toList(); + for (var service in services) { + for (var charactersitic in service.characteristics) { + for (var descriptor in charactersitic.descriptors) { + descriptor.characteristic = charactersitic; + } + charactersitic.service = service; + } + service.peripheral = peripheral; + } + return services; + } + + @override + Future readCharacteristic( + GattCharacteristic characteristic, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (characteristic is! MyGattCharacteristic2) { + throw TypeError(); + } + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final value = await _api.readCharacteristic( + peripheralHashCodeArgs, + characteristicHashCodeArgs, + ); + return value; + } + + @override + Future writeCharacteristic( + GattCharacteristic characteristic, { + required Uint8List value, + required GattCharacteristicWriteType type, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (characteristic is! MyGattCharacteristic2) { + throw TypeError(); + } + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final valueArgs = value; + final typeArgs = type.toArgs(); + final typeNumberArgs = typeArgs.index; + await _api.writeCharacteristic( + peripheralHashCodeArgs, + characteristicHashCodeArgs, + valueArgs, + typeNumberArgs, + ); + } + + @override + Future notifyCharacteristic( + GattCharacteristic characteristic, { + required bool state, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (characteristic is! MyGattCharacteristic2) { + throw TypeError(); + } + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final stateArgs = state; + await _api.notifyCharacteristic( + peripheralHashCodeArgs, + characteristicHashCodeArgs, + stateArgs, + ); + } + + @override + Future readDescriptor(GattDescriptor descriptor) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (descriptor is! MyGattDescriptor2) { + throw TypeError(); + } + final characteristic = descriptor.characteristic; + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final descriptorHashCodeArgs = descriptor.hashCode; + final value = await _api.readDescriptor( + peripheralHashCodeArgs, + descriptorHashCodeArgs, + ); + return value; + } + + @override + Future writeDescriptor( + GattDescriptor descriptor, { + required Uint8List value, + }) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (descriptor is! MyGattDescriptor2) { + throw TypeError(); + } + final characteristic = descriptor.characteristic; + final service = characteristic.service; + final peripheral = service.peripheral; + final peripheralHashCodeArgs = peripheral.hashCode; + final descriptorHashCodeArgs = descriptor.hashCode; + final valueArgs = value; + await _api.writeDescriptor( + peripheralHashCodeArgs, + descriptorHashCodeArgs, + valueArgs, + ); + } + + @override + void onStateChanged(int stateNumberArgs) { + final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs]; + state = stateArgs.toState(); + } + + @override + void onDiscovered( + MyPeripheralArgs peripheralArgs, + int rssiArgs, + MyAdvertiseDataArgs advertiseDataArgs, + ) { + final peripheral = peripheralArgs.toPeripheral(); + final rssi = rssiArgs; + final advertiseData = advertiseDataArgs.toAdvertiseData(); + final eventArgs = DiscoveredEventArgs( + peripheral, + rssi, + advertiseData, + ); + _discoveredController.add(eventArgs); + } + + @override + void onPeripheralStateChanged( + MyPeripheralArgs peripheralArgs, + bool stateArgs, + ) { + final peripheral = peripheralArgs.toPeripheral(); + final state = stateArgs; + final eventArgs = PeripheralStateChangedEventArgs(peripheral, state); + _peripheralStateChangedController.add(eventArgs); + } + + @override + void onCharacteristicValueChanged( + MyGattCharacteristicArgs characteristicArgs, + Uint8List valueArgs, + ) { + final characteristic = characteristicArgs.toCharacteristic2(); + final value = valueArgs; + final eventArgs = GattCharacteristicValueChangedEventArgs( + characteristic, + value, + ); + _characteristicValueChangedController.add(eventArgs); + } +} diff --git a/bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic.dart b/bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic.dart deleted file mode 100644 index 811fb23..0000000 --- a/bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_gatt_service.dart'; -import 'my_object.dart'; - -class MyGattCharacteristic extends MyObject implements GattCharacteristic { - final MyGattService myService; - @override - final UUID uuid; - @override - final List properties; - - MyGattCharacteristic( - super.hashCode, - this.myService, - this.uuid, - this.properties, - ); - - factory MyGattCharacteristic.fromMyArgs( - MyGattService myService, - MyGattCharacteristicArgs myArgs, - ) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - final properties = myArgs.myPropertyNumbers.cast().map( - (myPropertyNumber) { - final myPropertyArgs = - MyGattCharacteristicPropertyArgs.values[myPropertyNumber]; - return myPropertyArgs.toProperty(); - }, - ).toList(); - return MyGattCharacteristic(hashCode, myService, uuid, properties); - } -} - -extension on MyGattCharacteristicPropertyArgs { - GattCharacteristicProperty toProperty() { - return GattCharacteristicProperty.values[index]; - } -} diff --git a/bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic2.dart b/bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic2.dart new file mode 100644 index 0000000..b8c8a15 --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_gatt_characteristic2.dart @@ -0,0 +1,19 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_gatt_descriptor2.dart'; +import 'my_gatt_service2.dart'; + +class MyGattCharacteristic2 extends MyGattCharacteristic { + late final MyGattService2 service; + + MyGattCharacteristic2({ + super.hashCode, + required super.uuid, + required super.properties, + required List descriptors, + }) : super(descriptors: descriptors); + + @override + List get descriptors => + super.descriptors.cast(); +} diff --git a/bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor.dart b/bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor.dart deleted file mode 100644 index 6798f4a..0000000 --- a/bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_gatt_characteristic.dart'; -import 'my_object.dart'; - -class MyGattDescriptor extends MyObject implements GattDescriptor { - final MyGattCharacteristic myCharacteristic; - @override - final UUID uuid; - - MyGattDescriptor(super.hashCode, this.myCharacteristic, this.uuid); - - factory MyGattDescriptor.fromMyArgs( - MyGattCharacteristic myCharacteristic, - MyGattDescriptorArgs myArgs, - ) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - return MyGattDescriptor(hashCode, myCharacteristic, uuid); - } -} diff --git a/bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor2.dart b/bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor2.dart new file mode 100644 index 0000000..5bc7dc4 --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_gatt_descriptor2.dart @@ -0,0 +1,12 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_gatt_characteristic2.dart'; + +class MyGattDescriptor2 extends MyGattDescriptor { + late final MyGattCharacteristic2 characteristic; + + MyGattDescriptor2({ + super.hashCode, + required super.uuid, + }); +} diff --git a/bluetooth_low_energy_darwin/lib/src/my_gatt_service.dart b/bluetooth_low_energy_darwin/lib/src/my_gatt_service.dart deleted file mode 100644 index 37babdb..0000000 --- a/bluetooth_low_energy_darwin/lib/src/my_gatt_service.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_object.dart'; -import 'my_peripheral.dart'; - -class MyGattService extends MyObject implements GattService { - final MyPeripheral myPeripheral; - @override - final UUID uuid; - - MyGattService(super.hashCode, this.myPeripheral, this.uuid); - - factory MyGattService.fromMyArgs( - MyPeripheral myPeripheral, - MyGattServiceArgs myArgs, - ) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - return MyGattService(hashCode, myPeripheral, uuid); - } -} diff --git a/bluetooth_low_energy_darwin/lib/src/my_gatt_service2.dart b/bluetooth_low_energy_darwin/lib/src/my_gatt_service2.dart new file mode 100644 index 0000000..ac74a6d --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_gatt_service2.dart @@ -0,0 +1,17 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_gatt_characteristic2.dart'; + +class MyGattService2 extends MyGattService { + late final MyPeripheral peripheral; + + MyGattService2({ + super.hashCode, + required super.uuid, + required List characteristics, + }) : super(characteristics: characteristics); + + @override + List get characteristics => + super.characteristics.cast(); +} diff --git a/bluetooth_low_energy_darwin/lib/src/my_object.dart b/bluetooth_low_energy_darwin/lib/src/my_object.dart deleted file mode 100644 index 2b33805..0000000 --- a/bluetooth_low_energy_darwin/lib/src/my_object.dart +++ /dev/null @@ -1,11 +0,0 @@ -abstract class MyObject { - @override - final int hashCode; - - MyObject(this.hashCode); - - @override - bool operator ==(Object other) { - return other is MyObject && other.hashCode == hashCode; - } -} diff --git a/bluetooth_low_energy_darwin/lib/src/my_peripheral.dart b/bluetooth_low_energy_darwin/lib/src/my_peripheral.dart deleted file mode 100644 index 7be1bd3..0000000 --- a/bluetooth_low_energy_darwin/lib/src/my_peripheral.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -import 'my_api.g.dart'; -import 'my_object.dart'; - -class MyPeripheral extends MyObject implements Peripheral { - @override - final UUID uuid; - - MyPeripheral(super.hashCode, this.uuid); - - factory MyPeripheral.fromMyArgs(MyPeripheralArgs myArgs) { - final hashCode = myArgs.key; - final uuid = UUID.fromString(myArgs.uuid); - return MyPeripheral(hashCode, uuid); - } -} diff --git a/bluetooth_low_energy_darwin/lib/src/my_peripheral_manager.dart b/bluetooth_low_energy_darwin/lib/src/my_peripheral_manager.dart new file mode 100644 index 0000000..628ec37 --- /dev/null +++ b/bluetooth_low_energy_darwin/lib/src/my_peripheral_manager.dart @@ -0,0 +1,228 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +import 'my_api.dart'; +import 'my_bluetooth_low_energy_manager.dart'; + +class MyPeripheralManager extends MyBluetoothLowEnergyManager + implements PeripheralManager, MyPeripheralManagerFlutterApi { + final MyPeripheralManagerHostApi _api; + final StreamController + _readCharacteristicCommandReceivedController; + final StreamController + _writeCharacteristicCommandReceivedController; + final StreamController + _notifyCharacteristicCommandReceivedController; + + MyPeripheralManager() + : _api = MyPeripheralManagerHostApi(), + _readCharacteristicCommandReceivedController = + StreamController.broadcast(), + _writeCharacteristicCommandReceivedController = + StreamController.broadcast(), + _notifyCharacteristicCommandReceivedController = + StreamController.broadcast(); + + @override + Stream + get readCharacteristicCommandReceived => + _readCharacteristicCommandReceivedController.stream; + + @override + Stream + get writeCharacteristicCommandReceived => + _writeCharacteristicCommandReceivedController.stream; + + @override + Stream + get notifyCharacteristicCommandReceived => + _notifyCharacteristicCommandReceivedController.stream; + + @override + Future setUp() async { + final args = await _api.setUp(); + final stateArgs = + MyBluetoothLowEnergyStateArgs.values[args.stateNumberArgs]; + state = stateArgs.toState(); + MyPeripheralManagerFlutterApi.setup(this); + } + + @override + Future addService(GattService service) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + if (service is! MyGattService) { + throw TypeError(); + } + final serviceArgs = service.toArgs(); + await _api.addService(serviceArgs); + } + + @override + Future removeService(GattService service) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final serviceHashCodeArgs = service.hashCode; + await _api.removeService(serviceHashCodeArgs); + } + + @override + Future clearServices() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.clearServices(); + } + + @override + Future startAdvertising(AdvertiseData advertiseData) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final advertiseDataArgs = advertiseData.toArgs(); + await _api.startAdvertising(advertiseDataArgs); + } + + @override + Future stopAdvertising() async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _api.stopAdvertising(); + } + + @override + Future getMaximumWriteLength(Central central) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final maximumWriteLength = + await _api.getMaximumWriteLength(centralHashCodeArgs); + return maximumWriteLength; + } + + @override + Future sendReadCharacteristicReply( + Central central, + GattCharacteristic characteristic, + int id, + int offset, + bool status, + Uint8List value, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final idArgs = id; + final offsetArgs = offset; + final statusArgs = status; + final valueArgs = value; + await _api.sendReadCharacteristicReply( + centralHashCodeArgs, + characteristicHashCodeArgs, + idArgs, + offsetArgs, + statusArgs, + valueArgs, + ); + } + + @override + Future sendWriteCharacteristicReply( + Central central, + GattCharacteristic characteristic, + int id, + int offset, + bool status, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final idArgs = id; + final offsetArgs = offset; + final statusArgs = status; + await _api.sendWriteCharacteristicReply( + centralHashCodeArgs, + characteristicHashCodeArgs, + idArgs, + offsetArgs, + statusArgs, + ); + } + + @override + Future notifyCharacteristicValueChanged( + Central central, + GattCharacteristic characteristic, + Uint8List value, + ) async { + await throwWithoutState(BluetoothLowEnergyState.poweredOn); + final centralHashCodeArgs = central.hashCode; + final characteristicHashCodeArgs = characteristic.hashCode; + final valueArgs = value; + await _api.notifyCharacteristicValueChanged( + centralHashCodeArgs, + characteristicHashCodeArgs, + valueArgs, + ); + } + + @override + void onStateChanged(int stateNumberArgs) { + final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs]; + state = stateArgs.toState(); + } + + @override + void onReadCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + ) { + final central = centralArgs.toCentral(); + final characteristic = characteristicArgs.toCharacteristic2(); + final id = idArgs; + final offset = offsetArgs; + final eventArgs = ReadGattCharacteristicCommandEventArgs( + central, + characteristic, + id, + offset, + ); + _readCharacteristicCommandReceivedController.add(eventArgs); + } + + @override + void onWriteCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + Uint8List valueArgs, + ) { + final central = centralArgs.toCentral(); + final characteristic = characteristicArgs.toCharacteristic2(); + final id = idArgs; + final offset = offsetArgs; + final value = valueArgs; + final eventArgs = WriteGattCharacteristicCommandEventArgs( + central, + characteristic, + id, + offset, + value, + ); + _writeCharacteristicCommandReceivedController.add(eventArgs); + } + + @override + void onNotifyCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + bool stateArgs, + ) { + final central = centralArgs.toCentral(); + final characteristic = characteristicArgs.toCharacteristic2(); + final state = stateArgs; + final eventArgs = NotifyGattCharacteristicCommandEventArgs( + central, + characteristic, + state, + ); + _notifyCharacteristicCommandReceivedController.add(eventArgs); + } +} diff --git a/bluetooth_low_energy_darwin/my_api.dart b/bluetooth_low_energy_darwin/my_api.dart index 9f01be4..ef93a97 100644 --- a/bluetooth_low_energy_darwin/my_api.dart +++ b/bluetooth_low_energy_darwin/my_api.dart @@ -9,124 +9,213 @@ import 'package:pigeon/pigeon.dart'; ), ) @HostApi() -abstract class MyCentralControllerHostApi { +abstract class MyCentralManagerHostApi { @async - MyCentralControllerArgs setUp(); - void tearDown(); + MyCentralManagerArgs setUp(); void startDiscovery(); void stopDiscovery(); @async - void connect(int myPeripheralKey); + void connect(int peripheralHashCodeArgs); @async - void disconnect(int myPeripheralKey); - int getMaximumWriteLength(int myPeripheralKey, int myTypeNumber); + void disconnect(int peripheralHashCodeArgs); + int getMaximumWriteLength(int peripheralHashCodeArgs, int typeNumberArgs); @async - void discoverGATT(int myPeripheralKey); - List getServices(int myPeripheralKey); - List getCharacteristics(int myServiceKey); - List getDescriptors(int myCharacteristicKey); + int readRSSI(int peripheralHashCodeArgs); + @async + List discoverGATT(int peripheralHashCodeArgs); @async Uint8List readCharacteristic( - int myPeripheralKey, - int myServiceKey, - int myCharacteristicKey, + int peripheralHashCodeArgs, + int characteristicHashCodeArgs, ); @async void writeCharacteristic( - int myPeripheralKey, - int myServiceKey, - int myCharacteristicKey, - Uint8List value, - int myTypeNumber, + int peripheralHashCodeArgs, + int characteristicHashCodeArgs, + Uint8List valueArgs, + int typeNumberArgs, ); @async void notifyCharacteristic( - int myPeripheralKey, - int myServiceKey, - int myCharacteristicKey, - bool state, + int peripheralHashCodeArgs, + int characteristicHashCodeArgs, + bool stateArgs, ); @async Uint8List readDescriptor( - int myPeripheralKey, - int myCharacteristicKey, - int myDescriptorKey, + int peripheralHashCodeArgs, + int descriptorHashCodeArgs, ); @async void writeDescriptor( - int myPeripheralKey, - int myCharacteristicKey, - int myDescriptorKey, - Uint8List value, + int peripheralHashCodeArgs, + int descriptorHashCodeArgs, + Uint8List valueArgs, ); } @FlutterApi() -abstract class MyCentralControllerFlutterApi { - void onStateChanged(int myStateNumber); +abstract class MyCentralManagerFlutterApi { + void onStateChanged(int stateNumberArgs); void onDiscovered( - MyPeripheralArgs myPeripheralArgs, - int rssi, - MyAdvertisementArgs myAdvertisementArgs, + MyPeripheralArgs peripheralArgs, + int rssiArgs, + MyAdvertiseDataArgs advertiseDataArgs, + ); + void onPeripheralStateChanged( + MyPeripheralArgs peripheralArgs, + bool stateArgs, + ); + void onCharacteristicValueChanged( + MyGattCharacteristicArgs characteristicArgs, + Uint8List valueArgs, ); - void onPeripheralStateChanged(int myPeripheralKey, bool state); - void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value); } -class MyCentralControllerArgs { - final int myStateNumber; +@HostApi() +abstract class MyPeripheralManagerHostApi { + @async + MyPeripheralManagerArgs setUp(); + @async + void addService(MyGattServiceArgs serviceArgs); + void removeService(int serviceHashCodeArgs); + void clearServices(); + @async + void startAdvertising(MyAdvertiseDataArgs advertiseDataArgs); + void stopAdvertising(); + int getMaximumWriteLength(int centralHashCodeArgs); + void sendReadCharacteristicReply( + int centralHashCodeArgs, + int characteristicHashCodeArgs, + int idArgs, + int offsetArgs, + bool statusArgs, + Uint8List valueArgs, + ); + void sendWriteCharacteristicReply( + int centralHashCodeArgs, + int characteristicHashCodeArgs, + int idArgs, + int offsetArgs, + bool statusArgs, + ); + @async + void notifyCharacteristicValueChanged( + int centralHashCodeArgs, + int characteristicHashCodeArgs, + Uint8List valueArgs, + ); +} - MyCentralControllerArgs(this.myStateNumber); +@FlutterApi() +abstract class MyPeripheralManagerFlutterApi { + void onStateChanged(int stateNumberArgs); + void onReadCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + ); + void onWriteCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + int idArgs, + int offsetArgs, + Uint8List valueArgs, + ); + void onNotifyCharacteristicCommandReceived( + MyCentralArgs centralArgs, + MyGattCharacteristicArgs characteristicArgs, + bool stateArgs, + ); +} + +class MyCentralManagerArgs { + final int stateNumberArgs; + + MyCentralManagerArgs(this.stateNumberArgs); +} + +class MyPeripheralManagerArgs { + final int stateNumberArgs; + + MyPeripheralManagerArgs(this.stateNumberArgs); +} + +class MyCentralArgs { + final int hashCodeArgs; + final String uuidArgs; + + MyCentralArgs(this.hashCodeArgs, this.uuidArgs); } class MyPeripheralArgs { - final int key; - final String uuid; + final int hashCodeArgs; + final String uuidArgs; - MyPeripheralArgs(this.key, this.uuid); + MyPeripheralArgs(this.hashCodeArgs, this.uuidArgs); } -class MyAdvertisementArgs { - final String? name; - final Map manufacturerSpecificData; - final List serviceUUIDs; - final Map serviceData; +class MyAdvertiseDataArgs { + final String? nameArgs; + final List serviceUUIDsArgs; + final Map serviceDataArgs; + final MyManufacturerSpecificDataArgs? manufacturerSpecificDataArgs; - MyAdvertisementArgs( - this.name, - this.manufacturerSpecificData, - this.serviceUUIDs, - this.serviceData, + MyAdvertiseDataArgs( + this.nameArgs, + this.serviceUUIDsArgs, + this.serviceDataArgs, + this.manufacturerSpecificDataArgs, ); } -class MyGattServiceArgs { - final int key; - final String uuid; +class MyManufacturerSpecificDataArgs { + final int idArgs; + final Uint8List dataArgs; - MyGattServiceArgs(this.key, this.uuid); + MyManufacturerSpecificDataArgs(this.idArgs, this.dataArgs); +} + +class MyGattServiceArgs { + final int hashCodeArgs; + final String uuidArgs; + final List characteristicsArgs; + + MyGattServiceArgs( + this.hashCodeArgs, + this.uuidArgs, + this.characteristicsArgs, + ); } class MyGattCharacteristicArgs { - final int key; - final String uuid; - final List myPropertyNumbers; + final int hashCodeArgs; + final String uuidArgs; + final List propertyNumbersArgs; + final List descriptorsArgs; MyGattCharacteristicArgs( - this.key, - this.uuid, - this.myPropertyNumbers, + this.hashCodeArgs, + this.uuidArgs, + this.propertyNumbersArgs, + this.descriptorsArgs, ); } class MyGattDescriptorArgs { - final int key; - final String uuid; + final int hashCodeArgs; + final String uuidArgs; + final Uint8List? valueArgs; - MyGattDescriptorArgs(this.key, this.uuid); + MyGattDescriptorArgs( + this.hashCodeArgs, + this.uuidArgs, + this.valueArgs, + ); } -enum MyCentralStateArgs { +enum MyBluetoothLowEnergyStateArgs { unknown, unsupported, unauthorized, diff --git a/bluetooth_low_energy_darwin/pubspec.yaml b/bluetooth_low_energy_darwin/pubspec.yaml index c17b007..23c4447 100644 --- a/bluetooth_low_energy_darwin/pubspec.yaml +++ b/bluetooth_low_energy_darwin/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_darwin description: iOS and macOS 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,13 +10,13 @@ environment: dependencies: flutter: sdk: flutter - bluetooth_low_energy_platform_interface: ^2.2.0 + bluetooth_low_energy_platform_interface: ^3.0.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - pigeon: ^10.1.6 + pigeon: ^11.0.1 flutter: plugin: diff --git a/bluetooth_low_energy_linux/CHANGELOG.md b/bluetooth_low_energy_linux/CHANGELOG.md index af53ab5..abb1b52 100644 --- a/bluetooth_low_energy_linux/CHANGELOG.md +++ b/bluetooth_low_energy_linux/CHANGELOG.md @@ -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` 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` 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. diff --git a/bluetooth_low_energy_linux/lib/bluetooth_low_energy_linux.dart b/bluetooth_low_energy_linux/lib/bluetooth_low_energy_linux.dart index 4d0ee64..fb8a4b9 100644 --- a/bluetooth_low_energy_linux/lib/bluetooth_low_energy_linux.dart +++ b/bluetooth_low_energy_linux/lib/bluetooth_low_energy_linux.dart @@ -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(); } } diff --git a/bluetooth_low_energy_linux/lib/src/my_bluetooth_low_energy.dart b/bluetooth_low_energy_linux/lib/src/my_bluetooth_low_energy.dart new file mode 100644 index 0000000..b25d715 --- /dev/null +++ b/bluetooth_low_energy_linux/lib/src/my_bluetooth_low_energy.dart @@ -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(); +} diff --git a/bluetooth_low_energy_linux/lib/src/my_bluez.dart b/bluetooth_low_energy_linux/lib/src/my_bluez.dart index a277292..2b40b07 100644 --- a/bluetooth_low_energy_linux/lib/src/my_bluez.dart +++ b/bluetooth_low_energy_linux/lib/src/my_bluez.dart @@ -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 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 get properties => flags - .map((e) => e.toProperty()) - .whereType() + List get myCharacteristics => characteristics + .map((characteristic) => MyGattCharacteristic2(characteristic)) .toList(); } -extension MyBlueZGattCharacteristicFlag on BlueZGattCharacteristicFlag { - GattCharacteristicProperty? toProperty() { +extension MyBlueZGattCharacteristic on BlueZGattCharacteristic { + UUID get myUUID => uuid.toMyUUID(); + + List get myProperties => flags + .map((e) => e.toMyProperty()) + .whereType() + .toList(); + + List 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; diff --git a/bluetooth_low_energy_linux/lib/src/my_central_controller.dart b/bluetooth_low_energy_linux/lib/src/my_central_controller.dart deleted file mode 100644 index ad53fec..0000000 --- a/bluetooth_low_energy_linux/lib/src/my_central_controller.dart +++ /dev/null @@ -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 _stateChangedController; - final StreamController _discoveredController; - final StreamController - _peripheralStateChangedController; - final StreamController - _characteristicValueChangedController; - final StreamController - _myPeripheralDiscoveredController; - final Map>> - _devicePropertiesChangedSubscriptions; - final Map>> - _characteristicPropertiesChangedSubscriptions; - final Map _myPeripherals; - final Map> _myServices; - final Map> _myCharacteristics; - final Map> _myDescriptors; - - BlueZAdapter get _adapter => _client.adapters.first; - CentralState _state; - @override - CentralState get state => _state; - - @override - Stream get stateChanged => - _stateChangedController.stream; - @override - Stream get discovered => - _discoveredController.stream; - @override - Stream get peripheralStateChanged => - _peripheralStateChangedController.stream; - @override - Stream - get characteristicValueChanged => - _characteristicValueChangedController.stream; - Stream get _myPeripheralDiscovered => - _myPeripheralDiscoveredController.stream; - - late StreamSubscription> _adapterPropertiesChangedSubscription; - late StreamSubscription _deviceAddedSubscription; - late StreamSubscription _deviceRemovedSubscription; - - Future _throwWithState(CentralState state) async { - if (this.state == state) { - throw BluetoothLowEnergyError('$state is unexpected.'); - } - } - - Future _throwWithoutState(CentralState state) async { - if (this.state != state) { - throw BluetoothLowEnergyError( - '$state is expected, but current state is ${this.state}.', - ); - } - } - - @override - Future 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 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 startDiscovery() async { - await _throwWithoutState(CentralState.poweredOn); - await _adapter.startDiscovery(); - } - - @override - Future stopDiscovery() async { - await _throwWithoutState(CentralState.poweredOn); - await _adapter.stopDiscovery(); - } - - @override - Future connect(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - final device = myPeripheral.device; - await device.connect(); - } - - @override - Future disconnect(Peripheral peripheral) async { - await _throwWithoutState(CentralState.poweredOn); - final myPeripheral = peripheral as MyPeripheral; - final device = myPeripheral.device; - await device.disconnect(); - } - - @override - Future getMaximumWriteLength( - Peripheral peripheral, { - required GattCharacteristicWriteType type, - }) async { - // TODO: 当前版本 `bluez` 插件不支持获取 MTU,返回最小值 20. - return 20; - } - - @override - Future 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> 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> 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> 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 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 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 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 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 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 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 = {}; - for (var service in device.gattServices) { - final myService = MyGattService(service); - myServices[myService.hashCode] = myService; - final myCharacteristics = {}; - for (var characteristic in service.characteristics) { - final myCharacteristic = MyGattCharacteristic(characteristic); - myCharacteristics[myCharacteristic.hashCode] = - myCharacteristic; - _beginCharacteristicPropertiesChangedListener( - service, - characteristic, - ); - final myDescriptors = {}; - 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(); - } -} diff --git a/bluetooth_low_energy_linux/lib/src/my_central_manager.dart b/bluetooth_low_energy_linux/lib/src/my_central_manager.dart new file mode 100644 index 0000000..63083e6 --- /dev/null +++ b/bluetooth_low_energy_linux/lib/src/my_central_manager.dart @@ -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 + _stateChangedController; + final StreamController _discoveredController; + final StreamController + _peripheralStateChangedController; + final StreamController + _characteristicValueChangedController; + final StreamController + _deviceServicesResolvedController; + + final Map> _myServicesOfMyPeripherals; + final Map + _characteristicPropertiesChangedSubscriptions; + + BlueZAdapter get _adapter => _client.adapters.first; + BluetoothLowEnergyState _state; + @override + BluetoothLowEnergyState get state => _state; + + @override + Stream get stateChanged => + _stateChangedController.stream; + @override + Stream get discovered => _discoveredController.stream; + @override + Stream get peripheralStateChanged => + _peripheralStateChangedController.stream; + @override + Stream + get characteristicValueChanged => + _characteristicValueChangedController.stream; + Stream get _servicesResolved => + _deviceServicesResolvedController.stream; + + Future _throwWithoutState(BluetoothLowEnergyState state) async { + if (this.state != state) { + throw BluetoothLowEnergyError( + '$state is expected, but current state is ${this.state}.', + ); + } + } + + @override + Future 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 startDiscovery() async { + await _throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _adapter.startDiscovery(); + } + + @override + Future stopDiscovery() async { + await _throwWithoutState(BluetoothLowEnergyState.poweredOn); + await _adapter.stopDiscovery(); + } + + @override + Future connect(Peripheral peripheral) async { + await _throwWithoutState(BluetoothLowEnergyState.poweredOn); + final myPeripheral = peripheral as MyPeripheral2; + final device = myPeripheral.device; + await device.connect(); + } + + @override + Future disconnect(Peripheral peripheral) async { + await _throwWithoutState(BluetoothLowEnergyState.poweredOn); + final myPeripheral = peripheral as MyPeripheral2; + final device = myPeripheral.device; + await device.disconnect(); + } + + @override + Future getMaximumWriteLength( + Peripheral peripheral, { + required GattCharacteristicWriteType type, + }) async { + // TODO: 当前版本 `bluez` 插件不支持获取 MTU,返回最小值 20. + return 20; + } + + @override + Future readRSSI(Peripheral peripheral) async { + await _throwWithoutState(BluetoothLowEnergyState.poweredOn); + final myPeripheral = peripheral as MyPeripheral2; + final device = myPeripheral.device; + return device.rssi; + } + + @override + Future> 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 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 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 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 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 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 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(); + 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(); + } + } + } +} diff --git a/bluetooth_low_energy_linux/lib/src/my_event_args.dart b/bluetooth_low_energy_linux/lib/src/my_event_args.dart index 31e8141..24a2a85 100644 --- a/bluetooth_low_energy_linux/lib/src/my_event_args.dart +++ b/bluetooth_low_energy_linux/lib/src/my_event_args.dart @@ -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); } diff --git a/bluetooth_low_energy_linux/lib/src/my_gatt_characteristic.dart b/bluetooth_low_energy_linux/lib/src/my_gatt_characteristic.dart deleted file mode 100644 index b441c52..0000000 --- a/bluetooth_low_energy_linux/lib/src/my_gatt_characteristic.dart +++ /dev/null @@ -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 get properties => characteristic.properties; -} diff --git a/bluetooth_low_energy_linux/lib/src/my_gatt_characteristic2.dart b/bluetooth_low_energy_linux/lib/src/my_gatt_characteristic2.dart new file mode 100644 index 0000000..9bf0311 --- /dev/null +++ b/bluetooth_low_energy_linux/lib/src/my_gatt_characteristic2.dart @@ -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, + ); +} diff --git a/bluetooth_low_energy_linux/lib/src/my_gatt_descriptor.dart b/bluetooth_low_energy_linux/lib/src/my_gatt_descriptor.dart deleted file mode 100644 index 7b55aae..0000000 --- a/bluetooth_low_energy_linux/lib/src/my_gatt_descriptor.dart +++ /dev/null @@ -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(); -} diff --git a/bluetooth_low_energy_linux/lib/src/my_gatt_descriptor2.dart b/bluetooth_low_energy_linux/lib/src/my_gatt_descriptor2.dart new file mode 100644 index 0000000..b8774ff --- /dev/null +++ b/bluetooth_low_energy_linux/lib/src/my_gatt_descriptor2.dart @@ -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, + ); +} diff --git a/bluetooth_low_energy_linux/lib/src/my_gatt_service.dart b/bluetooth_low_energy_linux/lib/src/my_gatt_service.dart deleted file mode 100644 index 023fda7..0000000 --- a/bluetooth_low_energy_linux/lib/src/my_gatt_service.dart +++ /dev/null @@ -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(); -} diff --git a/bluetooth_low_energy_linux/lib/src/my_gatt_service2.dart b/bluetooth_low_energy_linux/lib/src/my_gatt_service2.dart new file mode 100644 index 0000000..2c8cd41 --- /dev/null +++ b/bluetooth_low_energy_linux/lib/src/my_gatt_service2.dart @@ -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, + ); +} diff --git a/bluetooth_low_energy_linux/lib/src/my_object.dart b/bluetooth_low_energy_linux/lib/src/my_object.dart deleted file mode 100644 index d553fe6..0000000 --- a/bluetooth_low_energy_linux/lib/src/my_object.dart +++ /dev/null @@ -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; - } -} diff --git a/bluetooth_low_energy_linux/lib/src/my_peripheral.dart b/bluetooth_low_energy_linux/lib/src/my_peripheral2.dart similarity index 51% rename from bluetooth_low_energy_linux/lib/src/my_peripheral.dart rename to bluetooth_low_energy_linux/lib/src/my_peripheral2.dart index 0a6964a..86d1cbb 100644 --- a/bluetooth_low_energy_linux/lib/src/my_peripheral.dart +++ b/bluetooth_low_energy_linux/lib/src/my_peripheral2.dart @@ -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, + ); } diff --git a/bluetooth_low_energy_linux/pubspec.yaml b/bluetooth_low_energy_linux/pubspec.yaml index a5dfacb..3fa03ed 100644 --- a/bluetooth_low_energy_linux/pubspec.yaml +++ b/bluetooth_low_energy_linux/pubspec.yaml @@ -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: diff --git a/bluetooth_low_energy_platform_interface/CHANGELOG.md b/bluetooth_low_energy_platform_interface/CHANGELOG.md index b3749bf..3507f5a 100644 --- a/bluetooth_low_energy_platform_interface/CHANGELOG.md +++ b/bluetooth_low_energy_platform_interface/CHANGELOG.md @@ -1,3 +1,45 @@ +## 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` 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.5 + +* Move `Advertisement` class to `AdvertiseData` class. + +## 3.0.0-dev.4 + +* Fix issues. + +## 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` 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 + +* Add `PeripheralManager` api. +* Add `CentralManager#readRSSI` method. +* Move `CentralController` to `CentralManager`. +* Move `CentralState` to `BluetoothLowEnergyState`. +* Move `CentralDiscoveredEventArgs` to `DiscoveredEventArgs`. + ## 2.2.0 * Add `GattCharacteristicWriteType` argument to `CentralController#getMaximumWriteLength` method. diff --git a/bluetooth_low_energy_platform_interface/lib/bluetooth_low_energy_platform_interface.dart b/bluetooth_low_energy_platform_interface/lib/bluetooth_low_energy_platform_interface.dart index 38fd598..0b3623a 100644 --- a/bluetooth_low_energy_platform_interface/lib/bluetooth_low_energy_platform_interface.dart +++ b/bluetooth_low_energy_platform_interface/lib/bluetooth_low_energy_platform_interface.dart @@ -1,12 +1,24 @@ export 'src/errors.dart'; export 'src/event_args.dart'; -export 'src/central_controller.dart'; -export 'src/central_state.dart'; +export 'src/bluetooth_low_energy.dart'; +export 'src/bluetooth_low_energy_manager.dart'; +export 'src/bluetooth_low_energy_state.dart'; +export 'src/central_manager.dart'; +export 'src/peripheral_manager.dart'; +export 'src/bluetooth_low_energy_peer.dart'; +export 'src/central.dart'; export 'src/peripheral.dart'; export 'src/uuid.dart'; -export 'src/advertisement.dart'; +export 'src/advertise_data.dart'; +export 'src/manufacturer_specific_data.dart'; export 'src/gatt_service.dart'; export 'src/gatt_characteristic.dart'; export 'src/gatt_characteristic_property.dart'; export 'src/gatt_characteristic_write_type.dart'; export 'src/gatt_descriptor.dart'; +export 'src/my_object.dart'; +export 'src/my_peripheral.dart'; +export 'src/my_gatt_service.dart'; +export 'src/my_gatt_characteristic.dart'; +export 'src/my_gatt_descriptor.dart'; +export 'src/my_central.dart'; diff --git a/bluetooth_low_energy_platform_interface/lib/src/advertisement.dart b/bluetooth_low_energy_platform_interface/lib/src/advertise_data.dart similarity index 61% rename from bluetooth_low_energy_platform_interface/lib/src/advertisement.dart rename to bluetooth_low_energy_platform_interface/lib/src/advertise_data.dart index eabdf0b..6a554c1 100644 --- a/bluetooth_low_energy_platform_interface/lib/src/advertisement.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/advertise_data.dart @@ -1,26 +1,27 @@ import 'dart:typed_data'; +import 'manufacturer_specific_data.dart'; import 'uuid.dart'; -/// The advertisement discovered from a peripheral. -class Advertisement { +/// The advertise data discovered from a peripheral. +class AdvertiseData { /// The name of the peripheral. final String? name; - /// The manufacturer specific data of the peripheral. - final Map manufacturerSpecificData; - /// The GATT service uuids of the peripheral. final List serviceUUIDs; /// The GATT service data of the peripheral. final Map serviceData; - /// Constructs an [Advertisement]. - Advertisement({ + /// The manufacturer specific data of the peripheral. + final ManufacturerSpecificData? manufacturerSpecificData; + + /// Constructs an [AdvertiseData]. + AdvertiseData({ this.name, - this.manufacturerSpecificData = const {}, this.serviceUUIDs = const [], this.serviceData = const {}, + this.manufacturerSpecificData, }); } diff --git a/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy.dart b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy.dart new file mode 100644 index 0000000..fe0bb2c --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy.dart @@ -0,0 +1,41 @@ +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'central_manager.dart'; +import 'peripheral_manager.dart'; + +/// The bluetooth low energy interface. +/// +/// Call `setUp` before use any api. +abstract class BluetoothLowEnergy extends PlatformInterface { + /// Constructs a [BluetoothLowEnergy]. + BluetoothLowEnergy() : super(token: _token); + + static final Object _token = Object(); + + static BluetoothLowEnergy? _instance; + + /// The default instance of [BluetoothLowEnergy] to use. + static BluetoothLowEnergy get instance { + final instance = _instance; + if (instance == null) { + throw UnimplementedError( + '`BluetoothLowEnergy` is not implemented on this platform.', + ); + } + return instance; + } + + /// Platform-specific implementations should set this with their own + /// platform-specific class that extends [BluetoothLowEnergy] when + /// they register themselves. + static set instance(BluetoothLowEnergy instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + /// Gets the instance of central manager. + CentralManager get centralManager; + + /// Gets the instance of peripheral manager. + PeripheralManager get peripheralManager; +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_manager.dart b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_manager.dart new file mode 100644 index 0000000..b442f24 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_manager.dart @@ -0,0 +1,14 @@ +import 'bluetooth_low_energy_state.dart'; +import 'event_args.dart'; + +/// The abstract base class that manages central and peripheral objects. +abstract class BluetoothLowEnergyManager { + /// The current state of the manager. + BluetoothLowEnergyState get state; + + /// Tells the manager’s state updated. + Stream get stateChanged; + + /// Sets up this bluetooth low energy manager. + Future setUp(); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_peer.dart b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_peer.dart new file mode 100644 index 0000000..1e1e6fa --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_peer.dart @@ -0,0 +1,7 @@ +import 'uuid.dart'; + +/// An object that represents a remote device. +abstract class BluetoothLowEnergyPeer { + /// The UUID associated with the peer. + UUID get uuid; +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_state.dart b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_state.dart new file mode 100644 index 0000000..0836a4f --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/bluetooth_low_energy_state.dart @@ -0,0 +1,17 @@ +/// The state of the bluetooth low energy. +enum BluetoothLowEnergyState { + /// The bluetooth low energy is unknown. + unknown, + + /// The bluetooth low energy is unsupported. + unsupported, + + /// The bluetooth low energy is unauthorized. + unauthorized, + + /// The bluetooth low energy is powered off. + poweredOff, + + /// The bluetooth low energy is powered on. + poweredOn, +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/central.dart b/bluetooth_low_energy_platform_interface/lib/src/central.dart new file mode 100644 index 0000000..a7448f7 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/central.dart @@ -0,0 +1,4 @@ +import 'bluetooth_low_energy_peer.dart'; + +/// A remote device connected to a local app, which is acting as a peripheral. +abstract class Central extends BluetoothLowEnergyPeer {} diff --git a/bluetooth_low_energy_platform_interface/lib/src/central_controller.dart b/bluetooth_low_energy_platform_interface/lib/src/central_controller.dart deleted file mode 100644 index 455235b..0000000 --- a/bluetooth_low_energy_platform_interface/lib/src/central_controller.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'dart:typed_data'; - -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -import 'central_state.dart'; -import 'event_args.dart'; -import 'gatt_characteristic.dart'; -import 'gatt_characteristic_write_type.dart'; -import 'gatt_descriptor.dart'; -import 'gatt_service.dart'; -import 'peripheral.dart'; - -/// The central controller used to communicate with peripherals. -/// Call `setUp` before use any api, and call `tearDown` when it is no longer needed. -abstract class CentralController extends PlatformInterface { - /// Constructs a [CentralController]. - CentralController() : super(token: _token); - - static final Object _token = Object(); - - static CentralController? _instance; - - /// The default instance of [CentralController] to use. - static CentralController get instance { - final instance = _instance; - if (instance == null) { - const message = - '`BluetoothLowEnergy` is not implemented on this platform.'; - throw UnimplementedError(message); - } - return instance; - } - - /// Platform-specific implementations should set this with their own - /// platform-specific class that extends [CentralController] when - /// they register themselves. - static set instance(CentralController instance) { - PlatformInterface.verifyToken(instance, _token); - _instance = instance; - } - - /// Gets the state of the central. - CentralState get state; - - /// Used to listen the central state changed event. - Stream get stateChanged; - - /// Used to listen the central discovered event. - Stream get discovered; - - /// Used to listen peripherals state changed event. - Stream get peripheralStateChanged; - - /// Used to listen GATT characteristics value changed event. - Stream - get characteristicValueChanged; - - /// Sets up the central controller. - Future setUp(); - - /// Tears down the central controller. - Future tearDown(); - - /// Starts to discover peripherals. - Future startDiscovery(); - - /// Stops to discover peripherals. - Future stopDiscovery(); - - /// Connects to the peripheral. - Future connect(Peripheral peripheral); - - /// Disconnects form the peripheral. - Future disconnect(Peripheral peripheral); - - /// Gets the max length in bytes for a single write type of the peripheral. - Future getMaximumWriteLength( - Peripheral peripheral, { - required GattCharacteristicWriteType type, - }); - - /// Discovers GATT of the peripheral. - Future discoverGATT(Peripheral peripheral); - - /// Gets GATT services of the peripheral. - Future> getServices(Peripheral peripheral); - - /// Gets GATT characteristics of the GATT service. - Future> getCharacteristics(GattService service); - - /// Gets GATT descriptors of the GATT characteristic. - Future> getDescriptors( - GattCharacteristic characteristic, - ); - - /// Reads value of the GATT characteristic. - Future readCharacteristic(GattCharacteristic characteristic); - - /// Writes value of the GATT characteristic. - Future writeCharacteristic( - GattCharacteristic characteristic, { - required Uint8List value, - required GattCharacteristicWriteType type, - }); - - /// Notifies value of the GATT characteristic. - Future notifyCharacteristic( - GattCharacteristic characteristic, { - required bool state, - }); - - /// Reads value of the GATT descriptor. - Future readDescriptor(GattDescriptor descriptor); - - /// Writes value of the GATT descriptor. - Future writeDescriptor( - GattDescriptor descriptor, { - required Uint8List value, - }); -} diff --git a/bluetooth_low_energy_platform_interface/lib/src/central_manager.dart b/bluetooth_low_energy_platform_interface/lib/src/central_manager.dart new file mode 100644 index 0000000..732b304 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/central_manager.dart @@ -0,0 +1,76 @@ +import 'dart:typed_data'; + +import 'bluetooth_low_energy.dart'; +import 'bluetooth_low_energy_manager.dart'; +import 'event_args.dart'; +import 'gatt_characteristic.dart'; +import 'gatt_characteristic_write_type.dart'; +import 'gatt_descriptor.dart'; +import 'gatt_service.dart'; +import 'peripheral.dart'; + +/// An object that scans for, discovers, connects to, and manages peripherals. +abstract class CentralManager extends BluetoothLowEnergyManager { + /// Gets the instance of [CentralManager]. + static CentralManager get instance => + BluetoothLowEnergy.instance.centralManager; + + /// Tells the central manager discovered a peripheral while scanning for devices. + Stream get discovered; + + /// Tells that retrieving the specified peripheral's state changed. + Stream get peripheralStateChanged; + + /// Tells that retrieving the specified characteristic’s value changed. + Stream + get characteristicValueChanged; + + /// Scans for peripherals that are advertising services. + Future startDiscovery(); + + /// Asks the central manager to stop scanning for peripherals. + Future stopDiscovery(); + + /// Establishes a local connection to a peripheral. + Future connect(Peripheral peripheral); + + /// Cancels an active or pending local connection to a peripheral. + Future disconnect(Peripheral peripheral); + + /// Gets the maximum amount of data, in bytes, you can send to a characteristic in a single write type. + Future getMaximumWriteLength( + Peripheral peripheral, { + required GattCharacteristicWriteType type, + }); + + /// Retrieves the current RSSI value for the peripheral while connected to the central manager. + Future readRSSI(Peripheral peripheral); + + /// Discovers the GATT services, characteristics and descriptors of the peripheral. + Future> discoverGATT(Peripheral peripheral); + + /// Retrieves the value of a specified characteristic. + Future readCharacteristic(GattCharacteristic characteristic); + + /// Writes the value of a characteristic. + Future writeCharacteristic( + GattCharacteristic characteristic, { + required Uint8List value, + required GattCharacteristicWriteType type, + }); + + /// Sets notifications or indications for the value of a specified characteristic. + Future notifyCharacteristic( + GattCharacteristic characteristic, { + required bool state, + }); + + /// Retrieves the value of a specified characteristic descriptor. + Future readDescriptor(GattDescriptor descriptor); + + /// Writes the value of a characteristic descriptor. + Future writeDescriptor( + GattDescriptor descriptor, { + required Uint8List value, + }); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/central_state.dart b/bluetooth_low_energy_platform_interface/lib/src/central_state.dart deleted file mode 100644 index 206d55f..0000000 --- a/bluetooth_low_energy_platform_interface/lib/src/central_state.dart +++ /dev/null @@ -1,17 +0,0 @@ -/// The state of the central. -enum CentralState { - /// The central is unknown. - unknown, - - /// The central is unsupported. - unsupported, - - /// The central is unauthorized. - unauthorized, - - /// The central is powered off. - poweredOff, - - /// The central is powered on. - poweredOn, -} diff --git a/bluetooth_low_energy_platform_interface/lib/src/event_args.dart b/bluetooth_low_energy_platform_interface/lib/src/event_args.dart index d00002b..b5b5c95 100644 --- a/bluetooth_low_energy_platform_interface/lib/src/event_args.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/event_args.dart @@ -1,35 +1,36 @@ import 'dart:typed_data'; -import 'advertisement.dart'; -import 'central_state.dart'; +import 'advertise_data.dart'; +import 'bluetooth_low_energy_state.dart'; +import 'central.dart'; import 'gatt_characteristic.dart'; import 'peripheral.dart'; /// The base event arguments. abstract class EventArgs {} -/// The central state changed event arguments. -class CentralStateChangedEventArgs extends EventArgs { - /// The new state of the central. - final CentralState state; +/// The bluetooth low energy state changed event arguments. +class BluetoothLowEnergyStateChangedEventArgs extends EventArgs { + /// The new state of the bluetooth low energy. + final BluetoothLowEnergyState state; - /// Constructs a [CentralStateChangedEventArgs]. - CentralStateChangedEventArgs(this.state); + /// Constructs a [BluetoothLowEnergyStateChangedEventArgs]. + BluetoothLowEnergyStateChangedEventArgs(this.state); } -/// The central discovered event arguments. -class CentralDiscoveredEventArgs extends EventArgs { +/// The discovered event arguments. +class DiscoveredEventArgs extends EventArgs { /// The disvered peripheral. final Peripheral peripheral; /// The rssi of the peripheral. final int rssi; - /// The advertisement of the peripheral. - final Advertisement advertisement; + /// The advertise data of the peripheral. + final AdvertiseData advertiseData; - /// Constructs a [CentralDiscoveredEventArgs]. - CentralDiscoveredEventArgs(this.peripheral, this.rssi, this.advertisement); + /// Constructs a [DiscoveredEventArgs]. + DiscoveredEventArgs(this.peripheral, this.rssi, this.advertiseData); } /// The peripheral state changed event arguments. @@ -55,3 +56,45 @@ class GattCharacteristicValueChangedEventArgs extends EventArgs { /// Constructs a [GattCharacteristicValueChangedEventArgs]. GattCharacteristicValueChangedEventArgs(this.characteristic, this.value); } + +class ReadGattCharacteristicCommandEventArgs { + final Central central; + final GattCharacteristic characteristic; + final int id; + final int offset; + + ReadGattCharacteristicCommandEventArgs( + this.central, + this.characteristic, + this.id, + this.offset, + ); +} + +class WriteGattCharacteristicCommandEventArgs { + final Central central; + final GattCharacteristic characteristic; + final int id; + final int offset; + final Uint8List value; + + WriteGattCharacteristicCommandEventArgs( + this.central, + this.characteristic, + this.id, + this.offset, + this.value, + ); +} + +class NotifyGattCharacteristicCommandEventArgs { + final Central central; + final GattCharacteristic characteristic; + final bool state; + + NotifyGattCharacteristicCommandEventArgs( + this.central, + this.characteristic, + this.state, + ); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/gatt_attribute.dart b/bluetooth_low_energy_platform_interface/lib/src/gatt_attribute.dart new file mode 100644 index 0000000..f028aca --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/gatt_attribute.dart @@ -0,0 +1,7 @@ +import 'uuid.dart'; + +/// A representation of common aspects of services offered by a peripheral. +abstract class GattAttribute { + /// The Bluetooth-specific UUID of the attribute. + UUID get uuid; +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/gatt_characteristic.dart b/bluetooth_low_energy_platform_interface/lib/src/gatt_characteristic.dart index 0f3cee4..97a4f0a 100644 --- a/bluetooth_low_energy_platform_interface/lib/src/gatt_characteristic.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/gatt_characteristic.dart @@ -1,17 +1,27 @@ +import 'gatt_attribute.dart'; import 'gatt_characteristic_property.dart'; +import 'gatt_descriptor.dart'; +import 'my_gatt_characteristic.dart'; +import 'my_gatt_descriptor.dart'; import 'uuid.dart'; -/// The GATT characteristic. -class GattCharacteristic { - /// The [UUID] of this GATT characteristic. - final UUID uuid; +/// A characteristic of a remote peripheral’s service. +abstract class GattCharacteristic extends GattAttribute { + /// The properties of the characteristic. + List get properties; - /// The properties of this GATT characteristic. - final List properties; + /// A list of the descriptors discovered in this characteristic. + List get descriptors; /// Constructs a [GattCharacteristic]. - GattCharacteristic({ - required this.uuid, - required this.properties, - }); + factory GattCharacteristic({ + required UUID uuid, + required List properties, + required List descriptors, + }) => + MyGattCharacteristic( + uuid: uuid, + properties: properties, + descriptors: descriptors.cast(), + ); } diff --git a/bluetooth_low_energy_platform_interface/lib/src/gatt_descriptor.dart b/bluetooth_low_energy_platform_interface/lib/src/gatt_descriptor.dart index b60e2c7..75b8b72 100644 --- a/bluetooth_low_energy_platform_interface/lib/src/gatt_descriptor.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/gatt_descriptor.dart @@ -1,12 +1,18 @@ +import 'dart:typed_data'; + +import 'gatt_attribute.dart'; +import 'my_gatt_descriptor.dart'; import 'uuid.dart'; -/// The GATT characteristic. -class GattDescriptor { - /// The [UUID] of this GATT descriptor. - final UUID uuid; - +/// An object that provides further information about a remote peripheral’s characteristic. +abstract class GattDescriptor extends GattAttribute { /// Constructs a [GattDescriptor]. - GattDescriptor({ - required this.uuid, - }); + factory GattDescriptor({ + required UUID uuid, + required Uint8List value, + }) => + MyGattDescriptor( + uuid: uuid, + value: value, + ); } diff --git a/bluetooth_low_energy_platform_interface/lib/src/gatt_service.dart b/bluetooth_low_energy_platform_interface/lib/src/gatt_service.dart index ce5200a..a4f9020 100644 --- a/bluetooth_low_energy_platform_interface/lib/src/gatt_service.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/gatt_service.dart @@ -1,12 +1,21 @@ +import 'gatt_attribute.dart'; +import 'gatt_characteristic.dart'; +import 'my_gatt_characteristic.dart'; +import 'my_gatt_service.dart'; import 'uuid.dart'; -/// The GATT service. -class GattService { - /// The [UUID] of this GATT service. - final UUID uuid; +/// A collection of data and associated behaviors that accomplish a function or feature of a device. +abstract class GattService extends GattAttribute { + /// A list of characteristics discovered in this service. + List get characteristics; /// Constructs a [GattService]. - GattService({ - required this.uuid, - }); + factory GattService({ + required UUID uuid, + required List characteristics, + }) => + MyGattService( + uuid: uuid, + characteristics: characteristics.cast(), + ); } diff --git a/bluetooth_low_energy_platform_interface/lib/src/manufacturer_specific_data.dart b/bluetooth_low_energy_platform_interface/lib/src/manufacturer_specific_data.dart new file mode 100644 index 0000000..c506d6e --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/manufacturer_specific_data.dart @@ -0,0 +1,16 @@ +import 'dart:typed_data'; + +/// The manufacturer specific data of the peripheral +class ManufacturerSpecificData { + /// The manufacturer id. + final int id; + + /// The manufacturer data. + final Uint8List data; + + /// Constructs an [ManufacturerSpecificData]. + ManufacturerSpecificData({ + required this.id, + required this.data, + }); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/my_central.dart b/bluetooth_low_energy_platform_interface/lib/src/my_central.dart new file mode 100644 index 0000000..348cea2 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/my_central.dart @@ -0,0 +1,13 @@ +import 'central.dart'; +import 'my_object.dart'; +import 'uuid.dart'; + +class MyCentral extends MyObject implements Central { + @override + final UUID uuid; + + MyCentral({ + required super.hashCode, + required this.uuid, + }); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/my_gatt_characteristic.dart b/bluetooth_low_energy_platform_interface/lib/src/my_gatt_characteristic.dart new file mode 100644 index 0000000..a5cea0a --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/my_gatt_characteristic.dart @@ -0,0 +1,21 @@ +import 'gatt_characteristic.dart'; +import 'gatt_characteristic_property.dart'; +import 'my_gatt_descriptor.dart'; +import 'my_object.dart'; +import 'uuid.dart'; + +class MyGattCharacteristic extends MyObject implements GattCharacteristic { + @override + final UUID uuid; + @override + final List properties; + @override + final List descriptors; + + MyGattCharacteristic({ + super.hashCode, + required this.uuid, + required this.properties, + required this.descriptors, + }); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/my_gatt_descriptor.dart b/bluetooth_low_energy_platform_interface/lib/src/my_gatt_descriptor.dart new file mode 100644 index 0000000..f421203 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/my_gatt_descriptor.dart @@ -0,0 +1,17 @@ +import 'dart:typed_data'; + +import 'gatt_descriptor.dart'; +import 'my_object.dart'; +import 'uuid.dart'; + +class MyGattDescriptor extends MyObject implements GattDescriptor { + @override + final UUID uuid; + final Uint8List? value; + + MyGattDescriptor({ + super.hashCode, + required this.uuid, + this.value, + }); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/my_gatt_service.dart b/bluetooth_low_energy_platform_interface/lib/src/my_gatt_service.dart new file mode 100644 index 0000000..7ed4721 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/my_gatt_service.dart @@ -0,0 +1,17 @@ +import 'gatt_service.dart'; +import 'my_gatt_characteristic.dart'; +import 'my_object.dart'; +import 'uuid.dart'; + +class MyGattService extends MyObject implements GattService { + @override + final UUID uuid; + @override + final List characteristics; + + MyGattService({ + super.hashCode, + required this.uuid, + required this.characteristics, + }); +} diff --git a/bluetooth_low_energy_android/lib/src/my_object.dart b/bluetooth_low_energy_platform_interface/lib/src/my_object.dart similarity index 54% rename from bluetooth_low_energy_android/lib/src/my_object.dart rename to bluetooth_low_energy_platform_interface/lib/src/my_object.dart index 2b33805..084e1c1 100644 --- a/bluetooth_low_energy_android/lib/src/my_object.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/my_object.dart @@ -1,8 +1,10 @@ abstract class MyObject { - @override - final int hashCode; + final int? _hashCode; - MyObject(this.hashCode); + MyObject({int? hashCode}) : _hashCode = hashCode; + + @override + int get hashCode => _hashCode ?? super.hashCode; @override bool operator ==(Object other) { diff --git a/bluetooth_low_energy_platform_interface/lib/src/my_peripheral.dart b/bluetooth_low_energy_platform_interface/lib/src/my_peripheral.dart new file mode 100644 index 0000000..e4c4d36 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/my_peripheral.dart @@ -0,0 +1,13 @@ +import 'my_object.dart'; +import 'peripheral.dart'; +import 'uuid.dart'; + +class MyPeripheral extends MyObject implements Peripheral { + @override + final UUID uuid; + + MyPeripheral({ + required super.hashCode, + required this.uuid, + }); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/peripheral.dart b/bluetooth_low_energy_platform_interface/lib/src/peripheral.dart index e72ab89..58061ad 100644 --- a/bluetooth_low_energy_platform_interface/lib/src/peripheral.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/peripheral.dart @@ -1,7 +1,4 @@ -import 'uuid.dart'; +import 'bluetooth_low_energy_peer.dart'; -/// The peripheral. -abstract class Peripheral { - /// The [UUID] of this peripheral. - UUID get uuid; -} +/// A remote peripheral device. +abstract class Peripheral extends BluetoothLowEnergyPeer {} diff --git a/bluetooth_low_energy_platform_interface/lib/src/peripheral_manager.dart b/bluetooth_low_energy_platform_interface/lib/src/peripheral_manager.dart new file mode 100644 index 0000000..7bd8e31 --- /dev/null +++ b/bluetooth_low_energy_platform_interface/lib/src/peripheral_manager.dart @@ -0,0 +1,73 @@ +import 'dart:typed_data'; + +import 'advertise_data.dart'; +import 'bluetooth_low_energy.dart'; +import 'bluetooth_low_energy_manager.dart'; +import 'central.dart'; +import 'event_args.dart'; +import 'gatt_characteristic.dart'; +import 'gatt_service.dart'; + +/// An object that manages and advertises peripheral services exposed by this app. +abstract class PeripheralManager extends BluetoothLowEnergyManager { + /// Gets the instance of [PeripheralManager]. + static PeripheralManager get instance => + BluetoothLowEnergy.instance.peripheralManager; + + /// Tells that the local peripheral received an Attribute Protocol (ATT) read request for a characteristic with a dynamic value. + Stream + get readCharacteristicCommandReceived; + + /// Tells that the local peripheral device received an Attribute Protocol (ATT) write request for a characteristic with a dynamic value. + Stream + get writeCharacteristicCommandReceived; + + /// Tells that the peripheral manager received a characteristic’s notify changed. + Stream + get notifyCharacteristicCommandReceived; + + /// Publishes a service and any of its associated characteristics and characteristic descriptors to the local GATT database. + Future addService(GattService service); + + /// Removes a specified published service from the local GATT database. + Future removeService(GattService service); + + /// Removes all published services from the local GATT database. + Future clearServices(); + + /// Advertises peripheral manager data. + Future startAdvertising(AdvertiseData advertiseData); + + /// Stops advertising peripheral manager data. + Future stopAdvertising(); + + /// Gets the maximum amount of data, in bytes, that the central can receive in a + /// single notification or indication. + Future getMaximumWriteLength(Central central); + + /// Responds to a read request from a connected central. + Future sendReadCharacteristicReply( + Central central, + GattCharacteristic characteristic, + int id, + int offset, + bool status, + Uint8List value, + ); + + /// Responds to a write request from a connected central. + Future sendWriteCharacteristicReply( + Central central, + GattCharacteristic characteristic, + int id, + int offset, + bool status, + ); + + /// Send an updated characteristic value to one or more subscribed centrals, using a notification or indication. + Future notifyCharacteristicValueChanged( + Central central, + GattCharacteristic characteristic, + Uint8List value, + ); +} diff --git a/bluetooth_low_energy_platform_interface/lib/src/uuid.dart b/bluetooth_low_energy_platform_interface/lib/src/uuid.dart index 90a8a93..5e93092 100644 --- a/bluetooth_low_energy_platform_interface/lib/src/uuid.dart +++ b/bluetooth_low_energy_platform_interface/lib/src/uuid.dart @@ -48,13 +48,13 @@ class UUID { /// Creates a new UUID from the string format encoding (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where xx is a hexadecimal number). factory UUID.fromString(String value) { - if (value.length == 4) { - try { - final shortValue = int.parse(value, radix: 16); - return UUID.short(shortValue); - } catch (e) { + // 16 or 32 bits UUID. + if (value.length == 4 || value.length == 8) { + final shortValue = int.tryParse(value, radix: 16); + if (shortValue == null) { throw const FormatException('Invalid UUID string'); } + return UUID.short(shortValue); } var groups = value.split('-'); if (groups.length != 5 || @@ -91,7 +91,7 @@ class UUID { (group4 >> 24) & 0xff, (group4 >> 16) & 0xff, (group4 >> 8) & 0xff, - (group4 >> 0) & 0xff + (group4 >> 0) & 0xff, ]); } diff --git a/bluetooth_low_energy_platform_interface/pubspec.yaml b/bluetooth_low_energy_platform_interface/pubspec.yaml index 83ce398..c7f8b51 100644 --- a/bluetooth_low_energy_platform_interface/pubspec.yaml +++ b/bluetooth_low_energy_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_platform_interface description: A common platform interface for the bluetooth_low_energy plugin. -version: 2.2.0 +version: 3.0.0 homepage: https://github.com/yanshouwang/bluetooth_low_energy environment: diff --git a/bluetooth_low_energy_windows/lib/bluetooth_low_energy_windows.dart b/bluetooth_low_energy_windows/lib/bluetooth_low_energy_windows.dart index 52ed4d9..73567ef 100644 --- a/bluetooth_low_energy_windows/lib/bluetooth_low_energy_windows.dart +++ b/bluetooth_low_energy_windows/lib/bluetooth_low_energy_windows.dart @@ -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 BluetoothLowEnergyWindows { static void registerWith() { - CentralController.instance = MyCentralController(); + BluetoothLowEnergy.instance = MyBluetoothLowEnergy(); } } diff --git a/bluetooth_low_energy_windows/lib/src/my_bluetooth_low_energy.dart b/bluetooth_low_energy_windows/lib/src/my_bluetooth_low_energy.dart new file mode 100644 index 0000000..48b0455 --- /dev/null +++ b/bluetooth_low_energy_windows/lib/src/my_bluetooth_low_energy.dart @@ -0,0 +1,11 @@ +import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; + +class MyBluetoothLowEnergy extends BluetoothLowEnergy { + @override + // TODO: implement centralManager + CentralManager get centralManager => throw UnimplementedError(); + + @override + // TODO: implement peripheralManager + PeripheralManager get peripheralManager => throw UnimplementedError(); +} diff --git a/bluetooth_low_energy_windows/lib/src/my_central_controller.dart b/bluetooth_low_energy_windows/lib/src/my_central_controller.dart deleted file mode 100644 index 6c4fe5a..0000000 --- a/bluetooth_low_energy_windows/lib/src/my_central_controller.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'dart:typed_data'; - -import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart'; - -class MyCentralController extends CentralController { - @override - // TODO: implement state - CentralState get state => throw UnimplementedError(); - @override - // TODO: implement stateChanged - Stream get stateChanged => - throw UnimplementedError(); - @override - // TODO: implement discovered - Stream get discovered => - throw UnimplementedError(); - @override - // TODO: implement peripheralStateChanged - Stream get peripheralStateChanged => - throw UnimplementedError(); - @override - // TODO: implement characteristicValueChanged - Stream - get characteristicValueChanged => throw UnimplementedError(); - - @override - Future setUp() { - // TODO: implement setUp - throw UnimplementedError(); - } - - @override - Future tearDown() { - // TODO: implement tearDown - throw UnimplementedError(); - } - - @override - Future startDiscovery() { - // TODO: implement startDiscovery - throw UnimplementedError(); - } - - @override - Future stopDiscovery() { - // TODO: implement stopDiscovery - throw UnimplementedError(); - } - - @override - Future connect(Peripheral peripheral) { - // TODO: implement connect - throw UnimplementedError(); - } - - @override - Future disconnect(Peripheral peripheral) { - // TODO: implement disconnect - throw UnimplementedError(); - } - - @override - Future getMaximumWriteLength( - Peripheral peripheral, { - required GattCharacteristicWriteType type, - }) { - // TODO: implement getMaximumWriteLength - throw UnimplementedError(); - } - - @override - Future discoverGATT(Peripheral peripheral) { - // TODO: implement discoverGATT - throw UnimplementedError(); - } - - @override - Future> getServices(Peripheral peripheral) { - // TODO: implement getServices - throw UnimplementedError(); - } - - @override - Future> getCharacteristics(GattService service) { - // TODO: implement getCharacteristics - throw UnimplementedError(); - } - - @override - Future> getDescriptors( - GattCharacteristic characteristic) { - // TODO: implement getDescriptors - throw UnimplementedError(); - } - - @override - Future readCharacteristic(GattCharacteristic characteristic) { - // TODO: implement readCharacteristic - throw UnimplementedError(); - } - - @override - Future writeCharacteristic(GattCharacteristic characteristic, - {required Uint8List value, required GattCharacteristicWriteType type}) { - // TODO: implement writeCharacteristic - throw UnimplementedError(); - } - - @override - Future notifyCharacteristic(GattCharacteristic characteristic, - {required bool state}) { - // TODO: implement notifyCharacteristic - throw UnimplementedError(); - } - - @override - Future readDescriptor(GattDescriptor descriptor) { - // TODO: implement readDescriptor - throw UnimplementedError(); - } - - @override - Future writeDescriptor(GattDescriptor descriptor, - {required Uint8List value}) { - // TODO: implement writeDescriptor - throw UnimplementedError(); - } -} diff --git a/bluetooth_low_energy_windows/pubspec.yaml b/bluetooth_low_energy_windows/pubspec.yaml index 3a83613..3839ea2 100644 --- a/bluetooth_low_energy_windows/pubspec.yaml +++ b/bluetooth_low_energy_windows/pubspec.yaml @@ -1,6 +1,6 @@ name: bluetooth_low_energy_windows description: Windows 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 win32: ^5.0.6 dev_dependencies: