Closed ddomnik closed 5 months ago
Thanks for your report, I'll look into this issue a few days later.
Can't reproduce this issue with my device, is this issue always happen with your device? Need more information to resolve it.
Yes. If you can guide me where this issue rises in the source code and how to debug your lib I can try to resolve it.
Yes. If you can guide me where this issue rises in the source code and how to debug your lib I can try to resolve it.
Here is the guide of how to develope windows plugin in the step2f section. You need Visual Studio 2022 with C++ environment to debug this plugin.
After run the flutter app on windows, open the windows sln, then attach the app process to Visual Studio to debug the native codes.
Thanks.
Also this is the code I use for testing, where I can reproduce the error:
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:bluetooth_low_energy/bluetooth_low_energy.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class BledDev {
late bool connecting = false;
late final ValueNotifier<BluetoothLowEnergyState> state;
late final ValueNotifier<bool> discovering;
late final ValueNotifier<List<DiscoveredEventArgs>> discoveredEventArgs;
late final StreamSubscription stateChangedSubscription;
late final StreamSubscription discoveredSubscription;
late final ValueNotifier<Peripheral?> connectedDevice;
late final ValueNotifier<String> connectionDeviceName;
late final ValueNotifier<bool> connectionState;
late final DiscoveredEventArgs eventArgs;
late final ValueNotifier<List<GattService>> services;
late final ValueNotifier<List<GattCharacteristic>> characteristics;
late final ValueNotifier<GattService?> service;
late final ValueNotifier<GattCharacteristic?> characteristic;
late final ValueNotifier<GattCharacteristicWriteType> writeType;
late final TextEditingController writeController;
late final StreamSubscription connectionStateChangedSubscription;
late final StreamSubscription characteristicNotifiedSubscription;
BledDev._private() {
state = ValueNotifier(BluetoothLowEnergyState.unknown);
discovering = ValueNotifier(false);
discoveredEventArgs = ValueNotifier([]);
connectedDevice = ValueNotifier(null);
connectionDeviceName = ValueNotifier("");
connectionState = ValueNotifier(false);
services = ValueNotifier([]);
characteristics = ValueNotifier([]);
service = ValueNotifier(null);
characteristic = ValueNotifier(null);
writeType = ValueNotifier(GattCharacteristicWriteType.withResponse);
writeController = TextEditingController();
stateChangedSubscription = CentralManager.instance.stateChanged.listen(
(eventArgs) {
print("stateChangedSubscription");
state.value = eventArgs.state;
print('Change in stateChangedSubscription: $state.value');
},
onError: (error) {
// Handle errors
print('Error in stateChangedSubscription: $error');
},
onDone: () {
// Handle stream closure
print('stateChangedSubscription stream closed');
},
);
discoveredSubscription = CentralManager.instance.discovered.listen(
(eventArgs) {
print("discoveredSubscription");
final items = discoveredEventArgs.value;
bool isNewEntry = true;
int indexToUpdate = -1;
// Check if the device is already in the list
for (int i = 0; i < items.length; i++) {
if (items[i].peripheral == eventArgs.peripheral) {
isNewEntry = false;
indexToUpdate = i;
break;
}
}
if (isNewEntry) {
// Add a new entry if the device is not in the list
List<DiscoveredEventArgs> updatedItems = List.from(items);
updatedItems.add(eventArgs);
discoveredEventArgs.value = updatedItems;
updatedItems.forEach((element) {
print("name: '${element.advertisement.name}' uudi: '${element.peripheral.uuid}'");
if (element.advertisement.name == "BLED DEV") {
connect(element.peripheral);
}
});
print("UPDATE");
} else {
// Update the existing entry if the device is already in the list
List<DiscoveredEventArgs> updatedItems = List.from(items);
updatedItems[indexToUpdate] = eventArgs;
discoveredEventArgs.value = updatedItems;
}
},
);
connectionStateChangedSubscription = CentralManager.instance.connectionStateChanged.listen(
(eventArgs) async {
print("connectionStateChangedSubscription");
services.value = await CentralManager.instance.discoverGATT(eventArgs.peripheral);
final connectionState = eventArgs.connectionState;
this.connectionState.value = connectionState;
if (!connectionState) {
connectionDeviceName.value = "";
services.value = [];
characteristics.value = [];
service.value = null;
characteristic.value = null;
connectedDevice.value = null;
print("connectedDevice null");
} else {
discoveredEventArgs.value.forEach((device) {
if (device.peripheral.uuid == eventArgs.peripheral.uuid) {
connectionDeviceName.value = device.advertisement.name!;
}
});
}
},
);
characteristicNotifiedSubscription = CentralManager.instance.characteristicNotified.listen(
(eventArgs) {},
);
print("BLED DEV INSTANCE CREATED");
}
// Static private instance variable
static BledDev? _instance;
// Static method to access the instance
static BledDev get instance {
// Initialize instance if null
_instance ??= BledDev._private();
return _instance!;
}
init() async {
hierarchicalLoggingEnabled = true;
CentralManager.instance.logLevel = Level.ALL;
await CentralManager.instance.setUp();
state.value = await CentralManager.instance.getState();
if (kDebugMode) {
print('BLED DEV INSTANCE Initialized ${state.value}');
}
}
Future<void> startDiscovery() async {
print("START DISCOVERY");
discovering.value = true;
//discoveredEventArgs.value = [];
await CentralManager.instance.stopDiscovery();
await CentralManager.instance.startDiscovery();
Future.delayed(Duration(seconds: 5), stopDiscovery);
}
Future<void> stopDiscovery() async {
print("STOP DISCOVERY");
await CentralManager.instance.stopDiscovery();
discovering.value = false;
}
Future<bool> connect(Peripheral peripheral) async {
if (connecting) {
print("Already connecting ...");
return false;
}
connecting = true;
print("Connect to: ${peripheral.uuid}");
try {
await CentralManager.instance.connect(peripheral);
connectedDevice.value = peripheral;
connecting = false;
return true;
} on Exception catch (_err) {
print('Connect failed: $_err');
connecting = false;
return false;
}
}
Future<bool> disconnect(Peripheral? peripheral) async {
connectedDevice.value = null;
if (peripheral != null) {
print("Disconnect");
try {
await CentralManager.instance.disconnect(peripheral);
return true;
} on Exception catch (_err) {
print('Disconnect failed: $_err');
return false;
}
}
return false;
}
cleanup() {
stateChangedSubscription.cancel();
discoveredSubscription.cancel();
state.dispose();
discovering.dispose();
discoveredEventArgs.dispose();
connectionStateChangedSubscription.cancel();
characteristicNotifiedSubscription.cancel();
connectionState.dispose();
services.dispose();
characteristics.dispose();
service.dispose();
characteristic.dispose();
writeType.dispose();
writeController.dispose();
}
}
Modify NewProject Example this way:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
final BledDev _bledDev = BledDev.instance;
@override
void initState() {
super.initState();
print("home");
_bledDev.init();
}
void _incrementCounter() {
setState(() {
_counter++;
_bledDev.startDiscovery();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
services.value = await CentralManager.instance.discoverGATT(eventArgs.peripheral);
This method should only be called when connected
====== EDIT
I saw this crash when method called with wrong status. The null pointer exception can not be caught, will fix this crash in the next version. For now please don't call methods with wrong status to avoid this crash.
The 6.0.0-dev.0 has released, this issue should be resolved.
Fixed in 6.0.0
Hey, I am developing on windows, and notice a crash when a BLE device disconnects unexpectedly.
How to reproduce:
my code: